From 16f504a9dca3fe3b70568f67b7d41241ae485288 Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 18:49:04 +0200 Subject: Adding upstream version 7.0.6-dfsg. Signed-off-by: Daniel Baumann --- include/VBox/AssertGuest.h | 1781 ++++ include/VBox/ExtPack/ExtPack.h | 647 ++ include/VBox/Graphics/HGSMI.h | 251 + include/VBox/Graphics/HGSMIBase.h | 60 + include/VBox/Graphics/HGSMIChSetup.h | 88 + include/VBox/Graphics/HGSMIChannels.h | 77 + include/VBox/Graphics/HGSMIContext.h | 114 + include/VBox/Graphics/HGSMIDefs.h | 128 + include/VBox/Graphics/HGSMIHostCmd.h | 59 + include/VBox/Graphics/HGSMIMemAlloc.h | 113 + include/VBox/Graphics/Makefile.kup | 0 include/VBox/Graphics/VBoxUhgsmi.h | 145 + include/VBox/Graphics/VBoxVideo.h | 1490 +++ include/VBox/Graphics/VBoxVideo3D.h | 186 + include/VBox/Graphics/VBoxVideoErr.h | 76 + include/VBox/Graphics/VBoxVideoGuest.h | 185 + include/VBox/Graphics/VBoxVideoIPRT.h | 114 + include/VBox/Graphics/VBoxVideoVBE.h | 107 + include/VBox/Graphics/VBoxVideoVBEPrivate.h | 245 + include/VBox/GuestHost/DragAndDrop.h | 350 + include/VBox/GuestHost/DragAndDropDefs.h | 112 + include/VBox/GuestHost/GuestControl.h | 236 + include/VBox/GuestHost/HGCMMock.h | 804 ++ include/VBox/GuestHost/HGCMMockUtils.h | 428 + include/VBox/GuestHost/Makefile.kup | 0 include/VBox/GuestHost/SharedClipboard-transfers.h | 993 ++ include/VBox/GuestHost/SharedClipboard-win.h | 419 + include/VBox/GuestHost/SharedClipboard-x11.h | 187 + include/VBox/GuestHost/SharedClipboard.h | 354 + include/VBox/GuestHost/clipboard-helper.h | 250 + include/VBox/HostServices/DragAndDropSvc.h | 1198 +++ include/VBox/HostServices/GuestControlSvc.h | 1500 +++ include/VBox/HostServices/GuestPropertySvc.h | 553 ++ include/VBox/HostServices/Makefile.kup | 0 include/VBox/HostServices/Service.h | 358 + include/VBox/HostServices/VBoxClipboardExt.h | 66 + include/VBox/HostServices/VBoxClipboardSvc.h | 1220 +++ include/VBox/HostServices/VBoxHostChannel.h | 229 + include/VBox/Makefile.kup | 0 include/VBox/RemoteDesktop/Makefile.kup | 0 include/VBox/RemoteDesktop/VRDE.h | 1615 ++++ include/VBox/RemoteDesktop/VRDEImage.h | 256 + include/VBox/RemoteDesktop/VRDEInput.h | 234 + include/VBox/RemoteDesktop/VRDEMousePtr.h | 82 + include/VBox/RemoteDesktop/VRDEOrders.h | 310 + include/VBox/RemoteDesktop/VRDESCard.h | 528 ++ include/VBox/RemoteDesktop/VRDETSMF.h | 154 + include/VBox/RemoteDesktop/VRDEVideoIn.h | 1093 +++ include/VBox/SUPDrvMangling.h | 48 + include/VBox/SUPR0StackWrapper.mac | 180 + include/VBox/VBoxAuth.h | 209 + include/VBox/VBoxCocoa.h | 89 + include/VBox/VBoxCryptoIf.h | 320 + include/VBox/VBoxDrvCfg-win.h | 91 + include/VBox/VBoxGL2D.h | 390 + include/VBox/VBoxGuest.h | 1012 ++ include/VBox/VBoxGuestCoreTypes.h | 238 + include/VBox/VBoxGuestLib.h | 1405 +++ include/VBox/VBoxGuestLibSharedFolders.h | 131 + include/VBox/VBoxGuestLibSharedFoldersInline.h | 1612 ++++ include/VBox/VBoxGuestMangling.h | 49 + include/VBox/VBoxKeyboard.h | 56 + include/VBox/VBoxNetCfg-win.h | 147 + include/VBox/VBoxNetCmn-win.h | 163 + include/VBox/VBoxOGL.h | 70 + include/VBox/VBoxPktDmp.h | 186 + include/VBox/VBoxTpG.h | 455 + include/VBox/VDEPlug.h | 74 + include/VBox/VDEPlugSymDefs.h | 73 + include/VBox/VMMDev.h | 2034 ++++ include/VBox/VMMDevCoreTypes.h | 556 ++ include/VBox/VMMDevTesting.h | 272 + include/VBox/VMMDevTesting.mac | 148 + include/VBox/apic.h | 493 + include/VBox/apic.mac | 213 + include/VBox/asmdefs.mac | 785 ++ include/VBox/ata.h | 222 + include/VBox/bios.h | 56 + include/VBox/bios.mac | 44 + include/VBox/bioslogo.h | 108 + include/VBox/cdefs.h | 493 + include/VBox/com/AutoLock.h | 704 ++ include/VBox/com/ErrorInfo.h | 545 ++ include/VBox/com/EventQueue.h | 151 + include/VBox/com/Guid.h | 526 ++ include/VBox/com/Makefile.kup | 0 include/VBox/com/MultiResult.h | 278 + include/VBox/com/NativeEventQueue.h | 161 + include/VBox/com/VirtualBox.h | 71 + include/VBox/com/array.h | 1833 ++++ include/VBox/com/assert.h | 135 + include/VBox/com/com.h | 102 + include/VBox/com/defs.h | 606 ++ include/VBox/com/errorprint.h | 401 + include/VBox/com/list.h | 223 + include/VBox/com/listeners.h | 194 + include/VBox/com/microatl.h | 1408 +++ include/VBox/com/mtlist.h | 220 + include/VBox/com/ptr.h | 569 ++ include/VBox/com/string.h | 1494 +++ include/VBox/com/utils.h | 132 + include/VBox/dbg.h | 1222 +++ include/VBox/dbggui.h | 191 + include/VBox/dbus-calls.h | 180 + include/VBox/dbus.h | 139 + include/VBox/dis.h | 912 ++ include/VBox/disopcode.h | 1469 +++ include/VBox/err.h | 3148 +++++++ include/VBox/err.mac | 1230 +++ include/VBox/err.sed | 66 + include/VBox/hgcmsvc.h | 745 ++ include/VBox/intnet.h | 1348 +++ include/VBox/intnetinline.h | 837 ++ include/VBox/iommu-amd.h | 2718 ++++++ include/VBox/iommu-intel.h | 2915 ++++++ include/VBox/log.h | 1239 +++ include/VBox/msi.h | 287 + include/VBox/nasm.mac | 44 + include/VBox/ostypes.h | 305 + include/VBox/param.h | 229 + include/VBox/param.mac | 98 + include/VBox/pci.h | 827 ++ include/VBox/rawpci.h | 618 ++ include/VBox/scsi.h | 339 + include/VBox/scsiinline.h | 246 + include/VBox/settings.h | 1539 ++++ include/VBox/shflsvc.h | 2151 +++++ include/VBox/sup.h | 2832 ++++++ include/VBox/sup.mac | 157 + include/VBox/types.h | 1258 +++ include/VBox/usb.h | 280 + include/VBox/usbfilter.h | 271 + include/VBox/usblib-darwin.h | 72 + include/VBox/usblib-solaris.h | 288 + include/VBox/usblib-win.h | 309 + include/VBox/usblib.h | 196 + include/VBox/various.sed | 148 + include/VBox/vd-cache-backend.h | 332 + include/VBox/vd-common.h | 76 + include/VBox/vd-filter-backend.h | 122 + include/VBox/vd-ifs-internal.h | 710 ++ include/VBox/vd-ifs.h | 1765 ++++ include/VBox/vd-image-backend.h | 617 ++ include/VBox/vd-plugin.h | 106 + include/VBox/vd.h | 1847 ++++ include/VBox/vdmedia.h | 226 + include/VBox/version.h | 166 + include/VBox/vmm/Makefile.kup | 0 include/VBox/vmm/apic.h | 107 + include/VBox/vmm/cfgm.h | 245 + include/VBox/vmm/cpuidcall.h | 107 + include/VBox/vmm/cpuidcall.mac | 55 + include/VBox/vmm/cpum.h | 3248 +++++++ include/VBox/vmm/cpum.mac | 275 + include/VBox/vmm/cpumctx-v1_6.h | 263 + include/VBox/vmm/cpumctx.h | 1116 +++ include/VBox/vmm/cpumdis.h | 61 + include/VBox/vmm/dbgf.h | 3192 +++++++ include/VBox/vmm/dbgfcorefmt.h | 188 + include/VBox/vmm/dbgfflowtrace.h | 400 + include/VBox/vmm/dbgfsel.h | 117 + include/VBox/vmm/dbgftrace.h | 168 + include/VBox/vmm/em.h | 345 + include/VBox/vmm/gcm.h | 95 + include/VBox/vmm/gim.h | 218 + include/VBox/vmm/gmm.h | 828 ++ include/VBox/vmm/gvm.h | 351 + include/VBox/vmm/gvm.mac | 118 + include/VBox/vmm/gvmm.h | 364 + include/VBox/vmm/hm.h | 336 + include/VBox/vmm/hm_svm.h | 1169 +++ include/VBox/vmm/hm_vmx.h | 4644 ++++++++++ include/VBox/vmm/hm_vmx.mac | 163 + include/VBox/vmm/hmvmxinline.h | 1172 +++ include/VBox/vmm/iem.h | 422 + include/VBox/vmm/iom.h | 550 ++ include/VBox/vmm/mm.h | 244 + include/VBox/vmm/nem.h | 256 + include/VBox/vmm/pdm.h | 54 + include/VBox/vmm/pdmapi.h | 393 + include/VBox/vmm/pdmasynccompletion.h | 160 + include/VBox/vmm/pdmasynctask.h | 74 + include/VBox/vmm/pdmaudiohostenuminline.h | 463 + include/VBox/vmm/pdmaudioifs.h | 1567 ++++ include/VBox/vmm/pdmaudioinline.h | 1507 +++ include/VBox/vmm/pdmblkcache.h | 432 + include/VBox/vmm/pdmcardreaderinfs.h | 136 + include/VBox/vmm/pdmcommon.h | 192 + include/VBox/vmm/pdmcritsect.h | 143 + include/VBox/vmm/pdmcritsectrw.h | 111 + include/VBox/vmm/pdmdev.h | 9690 ++++++++++++++++++++ include/VBox/vmm/pdmdrv.h | 2497 +++++ include/VBox/vmm/pdmifs.h | 2366 +++++ include/VBox/vmm/pdmins.h | 99 + include/VBox/vmm/pdmnetifs.h | 456 + include/VBox/vmm/pdmnetinline.h | 724 ++ include/VBox/vmm/pdmnetshaper.h | 93 + include/VBox/vmm/pdmpci.h | 408 + include/VBox/vmm/pdmpcidev.h | 803 ++ include/VBox/vmm/pdmpcidevint.h | 238 + include/VBox/vmm/pdmqueue.h | 169 + include/VBox/vmm/pdmserialifs.h | 249 + include/VBox/vmm/pdmsrv.h | 350 + include/VBox/vmm/pdmstorageifs.h | 1059 +++ include/VBox/vmm/pdmtask.h | 162 + include/VBox/vmm/pdmthread.h | 311 + include/VBox/vmm/pdmtpmifs.h | 163 + include/VBox/vmm/pdmusb.h | 1502 +++ include/VBox/vmm/pdmwebcaminfs.h | 156 + include/VBox/vmm/pgm.h | 1129 +++ include/VBox/vmm/selm.h | 114 + include/VBox/vmm/ssm.h | 1354 +++ include/VBox/vmm/stam.h | 1376 +++ include/VBox/vmm/stam.mac | 392 + include/VBox/vmm/tm.h | 322 + include/VBox/vmm/trpm.h | 102 + include/VBox/vmm/trpm.mac | 57 + include/VBox/vmm/uvm.h | 195 + include/VBox/vmm/vm.h | 1519 +++ include/VBox/vmm/vm.mac | 187 + include/VBox/vmm/vmapi.h | 485 + include/VBox/vmm/vmcc.h | 148 + include/VBox/vmm/vmcpuset.h | 124 + include/VBox/vmm/vmm.h | 639 ++ include/VBox/vmm/vmmr3vtable-def.h | 711 ++ include/VBox/vmm/vmmr3vtable.h | 140 + include/VBox/vrdpusb.h | 135 + include/VBox/vscsi.h | 488 + include/VBox/vusb.h | 1472 +++ include/VBox/xrandr-calls.h | 80 + include/VBox/xrandr.h | 125 + 231 files changed, 137228 insertions(+) create mode 100644 include/VBox/AssertGuest.h create mode 100644 include/VBox/ExtPack/ExtPack.h create mode 100644 include/VBox/Graphics/HGSMI.h create mode 100644 include/VBox/Graphics/HGSMIBase.h create mode 100644 include/VBox/Graphics/HGSMIChSetup.h create mode 100644 include/VBox/Graphics/HGSMIChannels.h create mode 100644 include/VBox/Graphics/HGSMIContext.h create mode 100644 include/VBox/Graphics/HGSMIDefs.h create mode 100644 include/VBox/Graphics/HGSMIHostCmd.h create mode 100644 include/VBox/Graphics/HGSMIMemAlloc.h create mode 100644 include/VBox/Graphics/Makefile.kup create mode 100644 include/VBox/Graphics/VBoxUhgsmi.h create mode 100644 include/VBox/Graphics/VBoxVideo.h create mode 100644 include/VBox/Graphics/VBoxVideo3D.h create mode 100644 include/VBox/Graphics/VBoxVideoErr.h create mode 100644 include/VBox/Graphics/VBoxVideoGuest.h create mode 100644 include/VBox/Graphics/VBoxVideoIPRT.h create mode 100644 include/VBox/Graphics/VBoxVideoVBE.h create mode 100644 include/VBox/Graphics/VBoxVideoVBEPrivate.h create mode 100644 include/VBox/GuestHost/DragAndDrop.h create mode 100644 include/VBox/GuestHost/DragAndDropDefs.h create mode 100644 include/VBox/GuestHost/GuestControl.h create mode 100644 include/VBox/GuestHost/HGCMMock.h create mode 100644 include/VBox/GuestHost/HGCMMockUtils.h create mode 100644 include/VBox/GuestHost/Makefile.kup create mode 100644 include/VBox/GuestHost/SharedClipboard-transfers.h create mode 100644 include/VBox/GuestHost/SharedClipboard-win.h create mode 100644 include/VBox/GuestHost/SharedClipboard-x11.h create mode 100644 include/VBox/GuestHost/SharedClipboard.h create mode 100644 include/VBox/GuestHost/clipboard-helper.h create mode 100644 include/VBox/HostServices/DragAndDropSvc.h create mode 100644 include/VBox/HostServices/GuestControlSvc.h create mode 100644 include/VBox/HostServices/GuestPropertySvc.h create mode 100644 include/VBox/HostServices/Makefile.kup create mode 100644 include/VBox/HostServices/Service.h create mode 100644 include/VBox/HostServices/VBoxClipboardExt.h create mode 100644 include/VBox/HostServices/VBoxClipboardSvc.h create mode 100644 include/VBox/HostServices/VBoxHostChannel.h create mode 100644 include/VBox/Makefile.kup create mode 100644 include/VBox/RemoteDesktop/Makefile.kup create mode 100644 include/VBox/RemoteDesktop/VRDE.h create mode 100644 include/VBox/RemoteDesktop/VRDEImage.h create mode 100644 include/VBox/RemoteDesktop/VRDEInput.h create mode 100644 include/VBox/RemoteDesktop/VRDEMousePtr.h create mode 100644 include/VBox/RemoteDesktop/VRDEOrders.h create mode 100644 include/VBox/RemoteDesktop/VRDESCard.h create mode 100644 include/VBox/RemoteDesktop/VRDETSMF.h create mode 100644 include/VBox/RemoteDesktop/VRDEVideoIn.h create mode 100644 include/VBox/SUPDrvMangling.h create mode 100644 include/VBox/SUPR0StackWrapper.mac create mode 100644 include/VBox/VBoxAuth.h create mode 100644 include/VBox/VBoxCocoa.h create mode 100644 include/VBox/VBoxCryptoIf.h create mode 100644 include/VBox/VBoxDrvCfg-win.h create mode 100644 include/VBox/VBoxGL2D.h create mode 100644 include/VBox/VBoxGuest.h create mode 100644 include/VBox/VBoxGuestCoreTypes.h create mode 100644 include/VBox/VBoxGuestLib.h create mode 100644 include/VBox/VBoxGuestLibSharedFolders.h create mode 100644 include/VBox/VBoxGuestLibSharedFoldersInline.h create mode 100644 include/VBox/VBoxGuestMangling.h create mode 100644 include/VBox/VBoxKeyboard.h create mode 100644 include/VBox/VBoxNetCfg-win.h create mode 100644 include/VBox/VBoxNetCmn-win.h create mode 100644 include/VBox/VBoxOGL.h create mode 100644 include/VBox/VBoxPktDmp.h create mode 100644 include/VBox/VBoxTpG.h create mode 100644 include/VBox/VDEPlug.h create mode 100644 include/VBox/VDEPlugSymDefs.h create mode 100644 include/VBox/VMMDev.h create mode 100644 include/VBox/VMMDevCoreTypes.h create mode 100644 include/VBox/VMMDevTesting.h create mode 100644 include/VBox/VMMDevTesting.mac create mode 100644 include/VBox/apic.h create mode 100644 include/VBox/apic.mac create mode 100644 include/VBox/asmdefs.mac create mode 100644 include/VBox/ata.h create mode 100644 include/VBox/bios.h create mode 100644 include/VBox/bios.mac create mode 100644 include/VBox/bioslogo.h create mode 100644 include/VBox/cdefs.h create mode 100644 include/VBox/com/AutoLock.h create mode 100644 include/VBox/com/ErrorInfo.h create mode 100644 include/VBox/com/EventQueue.h create mode 100644 include/VBox/com/Guid.h create mode 100644 include/VBox/com/Makefile.kup create mode 100644 include/VBox/com/MultiResult.h create mode 100644 include/VBox/com/NativeEventQueue.h create mode 100644 include/VBox/com/VirtualBox.h create mode 100644 include/VBox/com/array.h create mode 100644 include/VBox/com/assert.h create mode 100644 include/VBox/com/com.h create mode 100644 include/VBox/com/defs.h create mode 100644 include/VBox/com/errorprint.h create mode 100644 include/VBox/com/list.h create mode 100644 include/VBox/com/listeners.h create mode 100644 include/VBox/com/microatl.h create mode 100644 include/VBox/com/mtlist.h create mode 100644 include/VBox/com/ptr.h create mode 100644 include/VBox/com/string.h create mode 100644 include/VBox/com/utils.h create mode 100644 include/VBox/dbg.h create mode 100644 include/VBox/dbggui.h create mode 100644 include/VBox/dbus-calls.h create mode 100644 include/VBox/dbus.h create mode 100644 include/VBox/dis.h create mode 100644 include/VBox/disopcode.h create mode 100644 include/VBox/err.h create mode 100644 include/VBox/err.mac create mode 100644 include/VBox/err.sed create mode 100644 include/VBox/hgcmsvc.h create mode 100644 include/VBox/intnet.h create mode 100644 include/VBox/intnetinline.h create mode 100644 include/VBox/iommu-amd.h create mode 100644 include/VBox/iommu-intel.h create mode 100644 include/VBox/log.h create mode 100644 include/VBox/msi.h create mode 100644 include/VBox/nasm.mac create mode 100644 include/VBox/ostypes.h create mode 100644 include/VBox/param.h create mode 100644 include/VBox/param.mac create mode 100644 include/VBox/pci.h create mode 100644 include/VBox/rawpci.h create mode 100644 include/VBox/scsi.h create mode 100644 include/VBox/scsiinline.h create mode 100644 include/VBox/settings.h create mode 100644 include/VBox/shflsvc.h create mode 100644 include/VBox/sup.h create mode 100644 include/VBox/sup.mac create mode 100644 include/VBox/types.h create mode 100644 include/VBox/usb.h create mode 100644 include/VBox/usbfilter.h create mode 100644 include/VBox/usblib-darwin.h create mode 100644 include/VBox/usblib-solaris.h create mode 100644 include/VBox/usblib-win.h create mode 100644 include/VBox/usblib.h create mode 100644 include/VBox/various.sed create mode 100644 include/VBox/vd-cache-backend.h create mode 100644 include/VBox/vd-common.h create mode 100644 include/VBox/vd-filter-backend.h create mode 100644 include/VBox/vd-ifs-internal.h create mode 100644 include/VBox/vd-ifs.h create mode 100644 include/VBox/vd-image-backend.h create mode 100644 include/VBox/vd-plugin.h create mode 100644 include/VBox/vd.h create mode 100644 include/VBox/vdmedia.h create mode 100644 include/VBox/version.h create mode 100644 include/VBox/vmm/Makefile.kup create mode 100644 include/VBox/vmm/apic.h create mode 100644 include/VBox/vmm/cfgm.h create mode 100644 include/VBox/vmm/cpuidcall.h create mode 100644 include/VBox/vmm/cpuidcall.mac create mode 100644 include/VBox/vmm/cpum.h create mode 100644 include/VBox/vmm/cpum.mac create mode 100644 include/VBox/vmm/cpumctx-v1_6.h create mode 100644 include/VBox/vmm/cpumctx.h create mode 100644 include/VBox/vmm/cpumdis.h create mode 100644 include/VBox/vmm/dbgf.h create mode 100644 include/VBox/vmm/dbgfcorefmt.h create mode 100644 include/VBox/vmm/dbgfflowtrace.h create mode 100644 include/VBox/vmm/dbgfsel.h create mode 100644 include/VBox/vmm/dbgftrace.h create mode 100644 include/VBox/vmm/em.h create mode 100644 include/VBox/vmm/gcm.h create mode 100644 include/VBox/vmm/gim.h create mode 100644 include/VBox/vmm/gmm.h create mode 100644 include/VBox/vmm/gvm.h create mode 100644 include/VBox/vmm/gvm.mac create mode 100644 include/VBox/vmm/gvmm.h create mode 100644 include/VBox/vmm/hm.h create mode 100644 include/VBox/vmm/hm_svm.h create mode 100644 include/VBox/vmm/hm_vmx.h create mode 100644 include/VBox/vmm/hm_vmx.mac create mode 100644 include/VBox/vmm/hmvmxinline.h create mode 100644 include/VBox/vmm/iem.h create mode 100644 include/VBox/vmm/iom.h create mode 100644 include/VBox/vmm/mm.h create mode 100644 include/VBox/vmm/nem.h create mode 100644 include/VBox/vmm/pdm.h create mode 100644 include/VBox/vmm/pdmapi.h create mode 100644 include/VBox/vmm/pdmasynccompletion.h create mode 100644 include/VBox/vmm/pdmasynctask.h create mode 100644 include/VBox/vmm/pdmaudiohostenuminline.h create mode 100644 include/VBox/vmm/pdmaudioifs.h create mode 100644 include/VBox/vmm/pdmaudioinline.h create mode 100644 include/VBox/vmm/pdmblkcache.h create mode 100644 include/VBox/vmm/pdmcardreaderinfs.h create mode 100644 include/VBox/vmm/pdmcommon.h create mode 100644 include/VBox/vmm/pdmcritsect.h create mode 100644 include/VBox/vmm/pdmcritsectrw.h create mode 100644 include/VBox/vmm/pdmdev.h create mode 100644 include/VBox/vmm/pdmdrv.h create mode 100644 include/VBox/vmm/pdmifs.h create mode 100644 include/VBox/vmm/pdmins.h create mode 100644 include/VBox/vmm/pdmnetifs.h create mode 100644 include/VBox/vmm/pdmnetinline.h create mode 100644 include/VBox/vmm/pdmnetshaper.h create mode 100644 include/VBox/vmm/pdmpci.h create mode 100644 include/VBox/vmm/pdmpcidev.h create mode 100644 include/VBox/vmm/pdmpcidevint.h create mode 100644 include/VBox/vmm/pdmqueue.h create mode 100644 include/VBox/vmm/pdmserialifs.h create mode 100644 include/VBox/vmm/pdmsrv.h create mode 100644 include/VBox/vmm/pdmstorageifs.h create mode 100644 include/VBox/vmm/pdmtask.h create mode 100644 include/VBox/vmm/pdmthread.h create mode 100644 include/VBox/vmm/pdmtpmifs.h create mode 100644 include/VBox/vmm/pdmusb.h create mode 100644 include/VBox/vmm/pdmwebcaminfs.h create mode 100644 include/VBox/vmm/pgm.h create mode 100644 include/VBox/vmm/selm.h create mode 100644 include/VBox/vmm/ssm.h create mode 100644 include/VBox/vmm/stam.h create mode 100644 include/VBox/vmm/stam.mac create mode 100644 include/VBox/vmm/tm.h create mode 100644 include/VBox/vmm/trpm.h create mode 100644 include/VBox/vmm/trpm.mac create mode 100644 include/VBox/vmm/uvm.h create mode 100644 include/VBox/vmm/vm.h create mode 100644 include/VBox/vmm/vm.mac create mode 100644 include/VBox/vmm/vmapi.h create mode 100644 include/VBox/vmm/vmcc.h create mode 100644 include/VBox/vmm/vmcpuset.h create mode 100644 include/VBox/vmm/vmm.h create mode 100644 include/VBox/vmm/vmmr3vtable-def.h create mode 100644 include/VBox/vmm/vmmr3vtable.h create mode 100644 include/VBox/vrdpusb.h create mode 100644 include/VBox/vscsi.h create mode 100644 include/VBox/vusb.h create mode 100644 include/VBox/xrandr-calls.h create mode 100644 include/VBox/xrandr.h (limited to 'include/VBox') diff --git a/include/VBox/AssertGuest.h b/include/VBox/AssertGuest.h new file mode 100644 index 00000000..c4946ff0 --- /dev/null +++ b/include/VBox/AssertGuest.h @@ -0,0 +1,1781 @@ +/** @file + * VirtualBox - Guest input assertions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_AssertGuest_h +#define VBOX_INCLUDED_AssertGuest_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_vbox_assert_guest VBox Guest Input Assertion Macros + * @{ + */ + + +/** @name Guest input assertions + * + * These assertions will only trigger when VBOX_STRICT_GUEST is defined. When + * it is undefined they will all be no-ops and generate no code, unless they + * have other side effected (i.e. the _RETURN, _STMT, _BREAK variations). + * + * The assertions build on top of the functions in iprt/assert.h. + * + * @{ + */ + + +/** @def ASSERT_GUEST_PANIC() + * If VBOX_STRICT_GUEST is defined this macro will invoke RTAssertDoPanic if + * RTAssertShouldPanic returns true. If VBOX_STRICT_GUEST isn't defined it won't + * do any thing. + */ +#if defined(VBOX_STRICT_GUEST) && !defined(VBOX_STRICT_GUEST_DONT_PANIC) +# define ASSERT_GUEST_PANIC() do { if (RTAssertShouldPanic()) RTAssertDoPanic(); } while (0) +#else +# define ASSERT_GUEST_PANIC() do { } while (0) +#endif + +/** Wrapper around RTAssertMsg1Weak that prefixes the expression. */ +#define ASSERT_GUEST_MSG1(szExpr, iLine, pszFile, pszFunction) \ + RTAssertMsg1Weak("guest-input: " szExpr, iLine, pszFile, pszFunction) + + +/** @def ASSERT_GUEST + * Assert that an expression is true. If false, hit breakpoint. + * @param a_Expr Expression which should be true. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST(a_Expr) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + } \ + } while (0) +#else +# define ASSERT_GUEST(a_Expr) do { } while (0) +#endif + + +/** @def ASSERT_GUEST_STMT + * Assert that an expression is true. If false, hit breakpoint and execute the + * statement. + * @param a_Expr Expression which should be true. + * @param a_Stmt Statement to execute on failure. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_STMT(a_Expr, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + } \ + } while (0) +#else +# define ASSERT_GUEST_STMT(a_Expr, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + a_Stmt; \ + } \ + } while (0) +#endif + + +/** @def ASSERT_GUEST_RETURN + * Assert that an expression is true and returns if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a_rc What is to be presented to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_RETURN(a_Expr, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } \ + } while (0) +#else +# define ASSERT_GUEST_RETURN(a_Expr, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + return (a_rc); \ + } while (0) +#endif + +/** @def ASSERT_GUEST_STMT_RETURN + * Assert that an expression is true, if it isn't execute the given statement + * and return rc. + * + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before executing the statement and + * returning. + * + * @param a_Expr Expression which should be true. + * @param a_Stmt Statement to execute before returning on failure. + * @param a_rc What is to be presented to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_STMT_RETURN(a_Expr, a_Stmt, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return (a_rc); \ + } \ + } while (0) +#else +# define ASSERT_GUEST_STMT_RETURN(a_Expr, a_Stmt, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + a_Stmt; \ + return (a_rc); \ + } \ + } while (0) +#endif + +/** @def ASSERT_GUEST_RETURN_VOID + * Assert that an expression is true and returns if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_RETURN_VOID(a_Expr) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return; \ + } \ + } while (0) +#else +# define ASSERT_GUEST_RETURN_VOID(a_Expr) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + return; \ + } while (0) +#endif + +/** @def ASSERT_GUEST_STMT_RETURN_VOID + * Assert that an expression is true, if it isn't execute the given statement + * and return. + * + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a_Stmt Statement to execute before returning on failure. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_STMT_RETURN_VOID(a_Expr, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return; \ + } \ + } while (0) +#else +# define ASSERT_GUEST_STMT_RETURN_VOID(a_Expr, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + a_Stmt; \ + return; \ + } \ + } while (0) +#endif + + +/** @def ASSERT_GUEST_BREAK + * Assert that an expression is true and breaks if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before breaking. + * + * @param a_Expr Expression which should be true. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_BREAK(a_Expr) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_BREAK(a_Expr) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + break +#endif + +/** @def ASSERT_GUEST_CONTINUE + * Assert that an expression is true and continue if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before continuing. + * + * @param a_Expr Expression which should be true. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_CONTINUE(a_Expr) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + continue; \ + } else do {} while (0) +#else +# define ASSERT_GUEST_CONTINUE(a_Expr) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + continue +#endif + +/** @def ASSERT_GUEST_STMT_BREAK + * Assert that an expression is true and breaks if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before doing break. + * + * @param a_Expr Expression which should be true. + * @param a_Stmt Statement to execute before break in case of a failed assertion. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_STMT_BREAK(a_Expr, a_Stmt) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else do {} while (0) +#else +# define ASSERT_GUEST_STMT_BREAK(a_Expr, a_Stmt) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + a_Stmt; \ + break; \ + } else do {} while (0) +#endif + + +/** @def ASSERT_GUEST_MSG + * Assert that an expression is true. If it's not print message and hit breakpoint. + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG(a_Expr, a) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + } \ + } while (0) +#else +# define ASSERT_GUEST_MSG(a_Expr, a) do { } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_STMT + * Assert that an expression is true. If it's not print message and hit + * breakpoint and execute the statement. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute in case of a failed assertion. + * + * @remarks The expression and statement will be evaluated in all build types. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_STMT(a_Expr, a, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + } \ + } while (0) +#else +# define ASSERT_GUEST_MSG_STMT(a_Expr, a, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + a_Stmt; \ + } \ + } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_RETURN + * Assert that an expression is true and returns if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_rc What is to be presented to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_RETURN(a_Expr, a, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } \ + } while (0) +#else +# define ASSERT_GUEST_MSG_RETURN(a_Expr, a, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + return (a_rc); \ + } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_STMT_RETURN + * Assert that an expression is true, if it isn't execute the statement and + * return. + * + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before returning in case of a failed + * assertion. + * @param a_rc What is to be presented to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_STMT_RETURN(a_Expr, a, a_Stmt, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return (a_rc); \ + } \ + } while (0) +#else +# define ASSERT_GUEST_MSG_STMT_RETURN(a_Expr, a, a_Stmt, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + a_Stmt; \ + return (a_rc); \ + } \ + } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_RETURN_VOID + * Assert that an expression is true and returns if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_RETURN_VOID(a_Expr, a) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + return; \ + } \ + } while (0) +#else +# define ASSERT_GUEST_MSG_RETURN_VOID(a_Expr, a) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + return; \ + } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_STMT_RETURN_VOID + * Assert that an expression is true, if it isn't execute the statement and + * return. + * + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before return in case of a failed assertion. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_STMT_RETURN_VOID(a_Expr, a, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return; \ + } \ + } while (0) +#else +# define ASSERT_GUEST_MSG_STMT_RETURN_VOID(a_Expr, a, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + a_Stmt; \ + return; \ + } \ + } while (0) +#endif + + +/** @def ASSERT_GUEST_MSG_BREAK + * Assert that an expression is true and breaks if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before returning. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_BREAK(a_Expr, a) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_MSG_BREAK(a_Expr, a) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + break +#endif + +/** @def ASSERT_GUEST_MSG_STMT_BREAK + * Assert that an expression is true and breaks if it isn't. + * In VBOX_STRICT_GUEST mode it will hit a breakpoint before doing break. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before break in case of a failed assertion. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_STMT_BREAK(a_Expr, a, a_Stmt) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_MSG_STMT_BREAK(a_Expr, a, a_Stmt) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + a_Stmt; \ + break; \ + } else \ + break +#endif + +/** @def ASSERT_GUEST_FAILED + * An assertion failed, hit breakpoint. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED() \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + } while (0) +#else +# define ASSERT_GUEST_FAILED() do { } while (0) +#endif + +/** @def ASSERT_GUEST_FAILED_STMT + * An assertion failed, hit breakpoint and execute statement. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_STMT(a_Stmt) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + } while (0) +#else +# define ASSERT_GUEST_FAILED_STMT(a_Stmt) do { a_Stmt; } while (0) +#endif + +/** @def ASSERT_GUEST_FAILED_RETURN + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only) and return. + * + * @param a_rc The a_rc to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_RETURN(a_rc) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } while (0) +#else +# define ASSERT_GUEST_FAILED_RETURN(a_rc) \ + do { \ + return (a_rc); \ + } while (0) +#endif + +/** @def ASSERT_GUEST_FAILED_STMT_RETURN + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only), execute a + * statement and return a value. + * + * @param a_Stmt The statement to execute before returning. + * @param a_rc The value to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_STMT_RETURN(a_Stmt, a_rc) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return (a_rc); \ + } while (0) +#else +# define ASSERT_GUEST_FAILED_STMT_RETURN(a_Stmt, a_rc) \ + do { \ + a_Stmt; \ + return (a_rc); \ + } while (0) +#endif + +/** @def ASSERT_GUEST_FAILED_RETURN_VOID + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only) and return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_RETURN_VOID() \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return; \ + } while (0) +#else +# define ASSERT_GUEST_FAILED_RETURN_VOID() \ + do { \ + return; \ + } while (0) +#endif + +/** @def ASSERT_GUEST_FAILED_STMT_RETURN_VOID + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only), execute a + * statement and return. + * + * @param a_Stmt The statement to execute before returning. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_STMT_RETURN_VOID(a_Stmt) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return; \ + } while (0) +#else +# define ASSERT_GUEST_FAILED_STMT_RETURN_VOID(a_Stmt) \ + do { \ + a_Stmt; \ + return; \ + } while (0) +#endif + + +/** @def ASSERT_GUEST_FAILED_BREAK + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only) and break. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_BREAK() \ + if (1) { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_FAILED_BREAK() \ + if (1) \ + break; \ + else \ + break +#endif + +/** @def ASSERT_GUEST_FAILED_STMT_BREAK + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only), execute + * the given statement and break. + * + * @param a_Stmt Statement to execute before break. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_FAILED_STMT_BREAK(a_Stmt) \ + if (1) { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_FAILED_STMT_BREAK(a_Stmt) \ + if (1) { \ + a_Stmt; \ + break; \ + } else \ + break +#endif + + +/** @def ASSERT_GUEST_MSG_FAILED + * An assertion failed print a message and a hit breakpoint. + * + * @param a printf argument list (in parenthesis). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_FAILED(a) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, RT_GCC_EXTENSION __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + } while (0) +#else +# define ASSERT_GUEST_MSG_FAILED(a) do { } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_FAILED_RETURN + * An assertion failed, hit breakpoint with message (VBOX_STRICT_GUEST mode only) and return. + * + * @param a printf argument list (in parenthesis). + * @param a_rc What is to be presented to return. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_FAILED_RETURN(a, a_rc) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } while (0) +#else +# define ASSERT_GUEST_MSG_FAILED_RETURN(a, a_rc) \ + do { \ + return (a_rc); \ + } while (0) +#endif + +/** @def ASSERT_GUEST_MSG_FAILED_RETURN_VOID + * An assertion failed, hit breakpoint with message (VBOX_STRICT_GUEST mode only) and return. + * + * @param a printf argument list (in parenthesis). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_FAILED_RETURN_VOID(a) \ + do { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + return; \ + } while (0) +#else +# define ASSERT_GUEST_MSG_FAILED_RETURN_VOID(a) \ + do { \ + return; \ + } while (0) +#endif + + +/** @def ASSERT_GUEST_MSG_FAILED_BREAK + * An assertion failed, hit breakpoint with message (VBOX_STRICT_GUEST mode only) and break. + * + * @param a printf argument list (in parenthesis). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_FAILED_BREAK(a) \ + if (1) { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_MSG_FAILED_BREAK(a) \ + if (1) \ + break; \ + else \ + break +#endif + +/** @def ASSERT_GUEST_MSG_FAILED_STMT_BREAK + * An assertion failed, hit breakpoint (VBOX_STRICT_GUEST mode only), execute + * the given statement and break. + * + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before break. + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_MSG_FAILED_STMT_BREAK(a, a_Stmt) \ + if (1) { \ + ASSERT_GUEST_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + RTAssertMsg2Weak a; \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break +#else +# define ASSERT_GUEST_MSG_FAILED_STMT_BREAK(a, a_Stmt) \ + if (1) { \ + a_Stmt; \ + break; \ + } else \ + break +#endif + +/** @} */ + + + +/** @name Guest input release log assertions + * + * These assertions will work like normal strict assertion when VBOX_STRICT_GUEST is + * defined and LogRel statements when VBOX_STRICT_GUEST is undefined. Typically + * used for important guest input that it would be helpful to find in VBox.log + * if the guest doesn't get it right. + * + * @{ + */ + + +/** @def ASSERT_GUEST_LOGREL_MSG1 + * RTAssertMsg1Weak (strict builds) / LogRel wrapper (non-strict). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_LOGREL_MSG1(szExpr, iLine, pszFile, pszFunction) \ + RTAssertMsg1Weak("guest-input: " szExpr, iLine, pszFile, pszFunction) +#else +# define ASSERT_GUEST_LOGREL_MSG1(szExpr, iLine, pszFile, pszFunction) \ + LogRel(("ASSERT_GUEST_LOGREL %s(%d) %s: %s\n", (pszFile), (iLine), (pszFunction), (szExpr) )) +#endif + +/** @def ASSERT_GUEST_LOGREL_MSG2 + * RTAssertMsg2Weak (strict builds) / LogRel wrapper (non-strict). + */ +#ifdef VBOX_STRICT_GUEST +# define ASSERT_GUEST_LOGREL_MSG2(a) RTAssertMsg2Weak a +#else +# define ASSERT_GUEST_LOGREL_MSG2(a) LogRel(a) +#endif + +/** @def ASSERT_GUEST_LOGREL + * Assert that an expression is true. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + */ +#define ASSERT_GUEST_LOGREL(a_Expr) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_RETURN + * Assert that an expression is true, return \a a_rc if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a_rc What is to be presented to return. + */ +#define ASSERT_GUEST_LOGREL_RETURN(a_Expr, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_RETURN_VOID + * Assert that an expression is true, return void if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + */ +#define ASSERT_GUEST_LOGREL_RETURN_VOID(a_Expr) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return; \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_BREAK + * Assert that an expression is true, break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + */ +#define ASSERT_GUEST_LOGREL_BREAK(a_Expr) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + break; \ + } \ + else \ + break + +/** @def ASSERT_GUEST_LOGREL_STMT_BREAK + * Assert that an expression is true, execute \a a_Stmt and break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a_Stmt Statement to execute before break in case of a failed assertion. + */ +#define ASSERT_GUEST_LOGREL_STMT_BREAK(a_Expr, a_Stmt) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break + +/** @def ASSERT_GUEST_LOGREL_MSG + * Assert that an expression is true. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define ASSERT_GUEST_LOGREL_MSG(a_Expr, a) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else\ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_STMT + * Assert that an expression is true, execute \a a_Stmt and break if it isn't + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute in case of a failed assertion. + */ +#define ASSERT_GUEST_LOGREL_MSG_STMT(a_Expr, a, a_Stmt) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else\ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RETURN + * Assert that an expression is true, return \a a_rc if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_rc What is to be presented to return. + */ +#define ASSERT_GUEST_LOGREL_MSG_RETURN(a_Expr, a, a_rc) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else\ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_STMT_RETURN + * Assert that an expression is true, execute @a a_Stmt and return @a rcRet if it + * isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + */ +#define ASSERT_GUEST_LOGREL_MSG_STMT_RETURN(a_Expr, a, a_Stmt, rcRet) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else\ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return (rcRet); \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RETURN_VOID + * Assert that an expression is true, return (void) if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define ASSERT_GUEST_LOGREL_MSG_RETURN_VOID(a_Expr, a) \ + do { \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else\ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + return; \ + } \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_BREAK + * Assert that an expression is true, break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + */ +#define ASSERT_GUEST_LOGREL_MSG_BREAK(a_Expr, a) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + break; \ + } \ + else \ + break + +/** @def ASSERT_GUEST_LOGREL_MSG_STMT_BREAK + * Assert that an expression is true, execute \a a_Stmt and break if it isn't. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Expr Expression which should be true. + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before break in case of a failed assertion. + */ +#define ASSERT_GUEST_LOGREL_MSG_STMT_BREAK(a_Expr, a, a_Stmt) \ + if (RT_LIKELY(!!(a_Expr))) \ + { /* likely */ } \ + else if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1(#a_Expr, __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break + +/** @def ASSERT_GUEST_LOGREL_FAILED + * An assertion failed. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + */ +#define ASSERT_GUEST_LOGREL_FAILED() \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_FAILED_RETURN + * An assertion failed. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_rc What is to be presented to return. + */ +#define ASSERT_GUEST_LOGREL_FAILED_RETURN(a_rc) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_FAILED_RETURN_VOID + * An assertion failed, hit a breakpoint and return. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + */ +#define ASSERT_GUEST_LOGREL_FAILED_RETURN_VOID() \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + return; \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_FAILED_BREAK + * An assertion failed, break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + */ +#define ASSERT_GUEST_LOGREL_FAILED_BREAK() \ + if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + break; \ + } else \ + break + +/** @def ASSERT_GUEST_LOGREL_FAILED_STMT_BREAK + * An assertion failed, execute \a a_Stmt and break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a_Stmt Statement to execute before break. + */ +#define ASSERT_GUEST_LOGREL_FAILED_STMT_BREAK(a_Stmt) \ + if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED + * An assertion failed. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED(a) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_STMT + * An assertion failed, execute @a a_Stmt. + * + * Strict builds will hit a breakpoint, non-strict will only do LogRel. The + * statement will be executed in regardless of build type. + * + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute after raising/logging the assertion. + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_STMT(a, a_Stmt) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_RETURN + * An assertion failed, return \a a_rc. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param a_rc What is to be presented to return. + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_RETURN(a, a_rc) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + return (a_rc); \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_STMT_RETURN + * An assertion failed, execute @a a_Stmt and return @a a_rc. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before returning in case of a failed + * assertion. + * @param a_rc What is to be presented to return. + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_STMT_RETURN(a, a_Stmt, a_rc) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return (a_rc); \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_RETURN_VOID + * An assertion failed, return void. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_RETURN_VOID(a) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + return; \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_STMT_RETURN_VOID + * An assertion failed, execute @a a_Stmt and return void. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before returning in case of a failed + * assertion. + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_STMT_RETURN_VOID(a, a_Stmt) \ + do { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + return; \ + } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_BREAK + * An assertion failed, break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_BREAK(a) \ + if (1)\ + { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + break; \ + } else \ + break + +/** @def ASSERT_GUEST_LOGREL_MSG_FAILED_STMT_BREAK + * An assertion failed, execute \a a_Stmt and break. + * Strict builds will hit a breakpoint, non-strict will only do LogRel. + * + * @param a printf argument list (in parenthesis). + * @param a_Stmt Statement to execute before break. + */ +#define ASSERT_GUEST_LOGREL_MSG_FAILED_STMT_BREAK(a, a_Stmt) \ + if (1) \ + { \ + ASSERT_GUEST_LOGREL_MSG1("failed", __LINE__, __FILE__, __PRETTY_FUNCTION__); \ + ASSERT_GUEST_LOGREL_MSG2(a); \ + ASSERT_GUEST_PANIC(); \ + a_Stmt; \ + break; \ + } else \ + break + +/** @} */ + + +/** @name Convenience Assertions Macros + * @{ + */ + +/** @def ASSERT_GUEST_RC + * Asserts a iprt status code successful. + * + * On failure it will print info about the rc and hit a breakpoint. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC(rc) ASSERT_GUEST_MSG_RC(rc, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_RC_STMT + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and execute + * @a stmt if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_STMT(rc, stmt) ASSERT_GUEST_MSG_RC_STMT(rc, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_RC_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_RETURN(rc, rcRet) ASSERT_GUEST_MSG_RC_RETURN(rc, ("%Rra\n", (rc)), rcRet) + +/** @def ASSERT_GUEST_RC_STMT_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and returns @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_STMT_RETURN(rc, stmt, rcRet) ASSERT_GUEST_MSG_RC_STMT_RETURN(rc, ("%Rra\n", (rc)), stmt, rcRet) + +/** @def ASSERT_GUEST_RC_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_RETURN_VOID(rc) ASSERT_GUEST_MSG_RC_RETURN_VOID(rc, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_RC_STMT_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), and + * execute the given statement/return if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning on failure. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_STMT_RETURN_VOID(rc, stmt) ASSERT_GUEST_MSG_RC_STMT_RETURN_VOID(rc, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_RC_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_BREAK(rc) ASSERT_GUEST_MSG_RC_BREAK(rc, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_RC_STMT_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_STMT_BREAK(rc, stmt) ASSERT_GUEST_MSG_RC_STMT_BREAK(rc, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_MSG_RC + * Asserts a iprt status code successful. + * + * It prints a custom message and hits a breakpoint on FAILURE. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC(rc, msg) \ + do { ASSERT_GUEST_MSG(RT_SUCCESS_NP(rc), msg); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_MSG_RC_STMT + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and + * execute @a stmt if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_STMT(rc, msg, stmt) \ + do { ASSERT_GUEST_MSG_STMT(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_MSG_RC_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return + * @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_RETURN(rc, msg, rcRet) \ + do { ASSERT_GUEST_MSG_RETURN(RT_SUCCESS_NP(rc), msg, rcRet); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_MSG_RC_STMT_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and return @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_STMT_RETURN(rc, msg, stmt, rcRet) \ + do { ASSERT_GUEST_MSG_STMT_RETURN(RT_SUCCESS_NP(rc), msg, stmt, rcRet); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_MSG_RC_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return + * void if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_RETURN_VOID(rc, msg) \ + do { ASSERT_GUEST_MSG_RETURN_VOID(RT_SUCCESS_NP(rc), msg); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_MSG_RC_STMT_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and return void if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_STMT_RETURN_VOID(rc, msg, stmt) \ + do { ASSERT_GUEST_MSG_STMT_RETURN_VOID(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_MSG_RC_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break + * if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_BREAK(rc, msg) \ + if (1) { ASSERT_GUEST_MSG_BREAK(RT_SUCCESS(rc), msg); NOREF(rc); } else do {} while (0) + +/** @def ASSERT_GUEST_MSG_RC_STMT_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and break if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_MSG_RC_STMT_BREAK(rc, msg, stmt) \ + if (1) { ASSERT_GUEST_MSG_STMT_BREAK(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } else do {} while (0) + +/** @def ASSERT_GUEST_RC_SUCCESS + * Asserts an iprt status code equals VINF_SUCCESS. + * + * On failure it will print info about the rc and hit a breakpoint. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_SUCCESS(rc) do { ASSERT_GUEST_MSG((rc) == VINF_SUCCESS, ("%Rra\n", (rc))); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_RC_SUCCESS_RETURN + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_SUCCESS_RETURN(rc, rcRet) ASSERT_GUEST_MSG_RETURN((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), rcRet) + +/** @def ASSERT_GUEST_RC_SUCCESS_RETURN_VOID + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_SUCCESS_RETURN_VOID(rc) ASSERT_GUEST_MSG_RETURN_VOID((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_RC_SUCCESS_BREAK + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_SUCCESS_BREAK(rc) ASSERT_GUEST_MSG_BREAK((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_RC_SUCCESS_STMT_BREAK + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_RC_SUCCESS_STMT_BREAK(rc, stmt) ASSERT_GUEST_MSG_STMT_BREAK((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_GCPHYS32 + * Asserts that the high dword of a physical address is zero + * + * @param GCPhys The address (RTGCPHYS). + */ +#define ASSERT_GUEST_GCPHYS32(GCPhys) ASSERT_GUEST_MSG(VALID_PHYS32(GCPhys), ("%RGp\n", (RTGCPHYS)(GCPhys))) + + +/** @def ASSERT_GUEST_RC + * Asserts a iprt status code successful. + * + * On failure it will print info about the rc and hit a breakpoint. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC(rc) ASSERT_GUEST_LOGREL_MSG_RC(rc, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_LOGREL_RC_STMT + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and execute + * @a stmt if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_STMT(rc, stmt) ASSERT_GUEST_LOGREL_MSG_RC_STMT(rc, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_LOGREL_RC_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_RETURN(rc, rcRet) ASSERT_GUEST_LOGREL_MSG_RC_RETURN(rc, ("%Rra\n", (rc)), rcRet) + +/** @def ASSERT_GUEST_LOGREL_RC_STMT_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and returns @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_STMT_RETURN(rc, stmt, rcRet) ASSERT_GUEST_LOGREL_MSG_RC_STMT_RETURN(rc, ("%Rra\n", (rc)), stmt, rcRet) + +/** @def ASSERT_GUEST_LOGREL_RC_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_RETURN_VOID(rc) ASSERT_GUEST_LOGREL_MSG_RC_RETURN_VOID(rc, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_LOGREL_RC_STMT_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), and + * execute the given statement/return if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before returning on failure. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_STMT_RETURN_VOID(rc, stmt) ASSERT_GUEST_LOGREL_MSG_RC_STMT_RETURN_VOID(rc, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_LOGREL_RC_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_BREAK(rc) ASSERT_GUEST_LOGREL_MSG_RC_BREAK(rc, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_LOGREL_RC_STMT_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_STMT_BREAK(rc, stmt) ASSERT_GUEST_LOGREL_MSG_RC_STMT_BREAK(rc, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC + * Asserts a iprt status code successful. + * + * It prints a custom message and hits a breakpoint on FAILURE. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC(rc, msg) \ + do { ASSERT_GUEST_LOGREL_MSG(RT_SUCCESS_NP(rc), msg); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_STMT + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and + * execute @a stmt if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_STMT(rc, msg, stmt) \ + do { ASSERT_GUEST_LOGREL_MSG_STMT(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return + * @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_RETURN(rc, msg, rcRet) \ + do { ASSERT_GUEST_LOGREL_MSG_RETURN(RT_SUCCESS_NP(rc), msg, rcRet); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_STMT_RETURN + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and return @a rcRet if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before returning in case of a failed + * assertion. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_STMT_RETURN(rc, msg, stmt, rcRet) \ + do { ASSERT_GUEST_LOGREL_MSG_STMT_RETURN(RT_SUCCESS_NP(rc), msg, stmt, rcRet); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and return + * void if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_RETURN_VOID(rc, msg) \ + do { ASSERT_GUEST_LOGREL_MSG_RETURN_VOID(RT_SUCCESS_NP(rc), msg); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_STMT_RETURN_VOID + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and return void if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_STMT_RETURN_VOID(rc, msg, stmt) \ + do { ASSERT_GUEST_LOGREL_MSG_STMT_RETURN_VOID(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only) and break + * if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_BREAK(rc, msg) \ + if (1) { ASSERT_GUEST_LOGREL_MSG_BREAK(RT_SUCCESS(rc), msg); NOREF(rc); } else do {} while (0) + +/** @def ASSERT_GUEST_LOGREL_MSG_RC_STMT_BREAK + * Asserts a iprt status code successful, bitch (RT_STRICT mode only), execute + * @a stmt and break if it isn't. + * + * @param rc iprt status code. + * @param msg printf argument list (in parenthesis). + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_MSG_RC_STMT_BREAK(rc, msg, stmt) \ + if (1) { ASSERT_GUEST_LOGREL_MSG_STMT_BREAK(RT_SUCCESS_NP(rc), msg, stmt); NOREF(rc); } else do {} while (0) + +/** @def ASSERT_GUEST_LOGREL_RC_SUCCESS + * Asserts an iprt status code equals VINF_SUCCESS. + * + * On failure it will print info about the rc and hit a breakpoint. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_SUCCESS(rc) do { ASSERT_GUEST_LOGREL_MSG((rc) == VINF_SUCCESS, ("%Rra\n", (rc))); NOREF(rc); } while (0) + +/** @def ASSERT_GUEST_LOGREL_RC_SUCCESS_RETURN + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @param rcRet What is to be presented to return. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_SUCCESS_RETURN(rc, rcRet) ASSERT_GUEST_LOGREL_MSG_RETURN((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), rcRet) + +/** @def ASSERT_GUEST_LOGREL_RC_SUCCESS_RETURN_VOID + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and return if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_SUCCESS_RETURN_VOID(rc) ASSERT_GUEST_LOGREL_MSG_RETURN_VOID((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_LOGREL_RC_SUCCESS_BREAK + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_SUCCESS_BREAK(rc) ASSERT_GUEST_LOGREL_MSG_BREAK((rc) == VINF_SUCCESS, ("%Rra\n", (rc))) + +/** @def ASSERT_GUEST_LOGREL_RC_SUCCESS_STMT_BREAK + * Asserts that an iprt status code equals VINF_SUCCESS, bitch (RT_STRICT mode only) and break if it isn't. + * + * @param rc iprt status code. + * @param stmt Statement to execute before break in case of a failed assertion. + * @remark rc is referenced multiple times. In release mode is NOREF()'ed. + */ +#define ASSERT_GUEST_LOGREL_RC_SUCCESS_STMT_BREAK(rc, stmt) ASSERT_GUEST_LOGREL_MSG_STMT_BREAK((rc) == VINF_SUCCESS, ("%Rra\n", (rc)), stmt) + +/** @def ASSERT_GUEST_LOGREL_GCPHYS32 + * Asserts that the high dword of a physical address is zero + * + * @param GCPhys The address (RTGCPHYS). + */ +#define ASSERT_GUEST_LOGREL_GCPHYS32(GCPhys) ASSERT_GUEST_LOGREL_MSG(VALID_PHYS32(GCPhys), ("%RGp\n", (RTGCPHYS)(GCPhys))) + + +/** @} */ + + +/** @} */ + +#endif /* !VBOX_INCLUDED_AssertGuest_h */ + diff --git a/include/VBox/ExtPack/ExtPack.h b/include/VBox/ExtPack/ExtPack.h new file mode 100644 index 00000000..61f415c3 --- /dev/null +++ b/include/VBox/ExtPack/ExtPack.h @@ -0,0 +1,647 @@ +/** @file + * VirtualBox - Extension Pack Interface. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_ExtPack_ExtPack_h +#define VBOX_INCLUDED_ExtPack_ExtPack_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @def VBOXEXTPACK_IF_CS + * Selects 'class' on 'struct' for interface references. + * @param I The interface name + */ +#if defined(__cplusplus) && !defined(RT_OS_WINDOWS) +# define VBOXEXTPACK_IF_CS(I) class I +#else +# define VBOXEXTPACK_IF_CS(I) struct I +#endif + +VBOXEXTPACK_IF_CS(IUnknown); +VBOXEXTPACK_IF_CS(IConsole); +VBOXEXTPACK_IF_CS(IMachine); +VBOXEXTPACK_IF_CS(IVirtualBox); +VBOXEXTPACK_IF_CS(IProgress); +VBOXEXTPACK_IF_CS(IEvent); +VBOXEXTPACK_IF_CS(IVetoEvent); +VBOXEXTPACK_IF_CS(IEventSource); + +/** + * Module kind for use with VBOXEXTPACKHLP::pfnFindModule. + */ +typedef enum VBOXEXTPACKMODKIND +{ + /** Zero is invalid as always. */ + VBOXEXTPACKMODKIND_INVALID = 0, + /** Raw-mode context module. */ + VBOXEXTPACKMODKIND_RC, + /** Ring-0 context module. */ + VBOXEXTPACKMODKIND_R0, + /** Ring-3 context module. */ + VBOXEXTPACKMODKIND_R3, + /** End of the valid values (exclusive). */ + VBOXEXTPACKMODKIND_END, + /** The usual 32-bit type hack. */ + VBOXEXTPACKMODKIND_32BIT_HACK = 0x7fffffff +} VBOXEXTPACKMODKIND; + +/** + * Contexts returned by VBOXEXTPACKHLP::pfnGetContext. + */ +typedef enum VBOXEXTPACKCTX +{ + /** Zero is invalid as always. */ + VBOXEXTPACKCTX_INVALID = 0, + /** The per-user daemon process (VBoxSVC). */ + VBOXEXTPACKCTX_PER_USER_DAEMON, + /** A VM process. */ + VBOXEXTPACKCTX_VM_PROCESS, + /** An API client process. + * @remarks This will not be returned by VirtualBox yet. */ + VBOXEXTPACKCTX_CLIENT_PROCESS, + /** End of the valid values (exclusive). */ + VBOXEXTPACKCTX_END, + /** The usual 32-bit type hack. */ + VBOXEXTPACKCTX_32BIT_HACK = 0x7fffffff +} VBOXEXTPACKCTX; + + +/** Pointer to const helpers passed to the VBoxExtPackRegister() call. */ +typedef const struct VBOXEXTPACKHLP *PCVBOXEXTPACKHLP; +/** + * Extension pack helpers passed to VBoxExtPackRegister(). + * + * This will be valid until the module is unloaded. + */ +typedef struct VBOXEXTPACKHLP +{ + /** Interface version. + * This is set to VBOXEXTPACKHLP_VERSION. */ + uint32_t u32Version; + + /** The VirtualBox full version (see VBOX_FULL_VERSION). */ + uint32_t uVBoxFullVersion; + /** The VirtualBox subversion tree revision. */ + uint32_t uVBoxInternalRevision; + /** Explicit alignment padding, must be zero. */ + uint32_t u32Padding; + /** Pointer to the version string (read-only). */ + const char *pszVBoxVersion; + + /** + * Finds a module belonging to this extension pack. + * + * @returns VBox status code. + * @param pHlp Pointer to this helper structure. + * @param pszName The module base name. + * @param pszExt The extension. If NULL the default ring-3 + * library extension will be used. + * @param enmKind The kind of module to locate. + * @param pszFound Where to return the path to the module on + * success. + * @param cbFound The size of the buffer @a pszFound points to. + * @param pfNative Where to return the native/agnostic indicator. + */ + DECLR3CALLBACKMEMBER(int, pfnFindModule,(PCVBOXEXTPACKHLP pHlp, const char *pszName, const char *pszExt, + VBOXEXTPACKMODKIND enmKind, + char *pszFound, size_t cbFound, bool *pfNative)); + + /** + * Gets the path to a file belonging to this extension pack. + * + * @returns VBox status code. + * @retval VERR_INVALID_POINTER if any of the pointers are invalid. + * @retval VERR_BUFFER_OVERFLOW if the buffer is too small. The buffer + * will contain nothing. + * + * @param pHlp Pointer to this helper structure. + * @param pszFilename The filename. + * @param pszPath Where to return the path to the file on + * success. + * @param cbPath The size of the buffer @a pszPath. + */ + DECLR3CALLBACKMEMBER(int, pfnGetFilePath,(PCVBOXEXTPACKHLP pHlp, const char *pszFilename, char *pszPath, size_t cbPath)); + + /** + * Gets the context the extension pack is operating in. + * + * @returns The context. + * @retval VBOXEXTPACKCTX_INVALID if @a pHlp is invalid. + * + * @param pHlp Pointer to this helper structure. + */ + DECLR3CALLBACKMEMBER(VBOXEXTPACKCTX, pfnGetContext,(PCVBOXEXTPACKHLP pHlp)); + + /** + * Loads a HGCM service provided by an extension pack. + * + * @returns VBox status code. + * @param pHlp Pointer to this helper structure. + * @param pConsole Pointer to the VM's console object. + * @param pszServiceLibrary Name of the library file containing the + * service implementation, without extension. + * @param pszServiceName Name of HGCM service. + */ + DECLR3CALLBACKMEMBER(int, pfnLoadHGCMService,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IConsole) *pConsole, + const char *pszServiceLibrary, const char *pszServiceName)); + + /** + * Loads a VD plugin provided by an extension pack. + * + * This makes sense only in the context of the per-user service (VBoxSVC). + * + * @returns VBox status code. + * @param pHlp Pointer to this helper structure. + * @param pVirtualBox Pointer to the VirtualBox object. + * @param pszPluginLibrary Name of the library file containing the plugin + * implementation, without extension. + */ + DECLR3CALLBACKMEMBER(int, pfnLoadVDPlugin,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox, + const char *pszPluginLibrary)); + + /** + * Unloads a VD plugin provided by an extension pack. + * + * This makes sense only in the context of the per-user service (VBoxSVC). + * + * @returns VBox status code. + * @param pHlp Pointer to this helper structure. + * @param pVirtualBox Pointer to the VirtualBox object. + * @param pszPluginLibrary Name of the library file containing the plugin + * implementation, without extension. + */ + DECLR3CALLBACKMEMBER(int, pfnUnloadVDPlugin,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox, + const char *pszPluginLibrary)); + + /** + * Creates an IProgress object instance for a long running extension + * pack provided API operation which is executed asynchronously. + * + * This implicitly creates a cancellable progress object, since anything + * else is user unfriendly. You need to design your code to handle + * cancellation with reasonable response time. + * + * @returns COM status code. + * @param pHlp Pointer to this helper structure. + * @param pInitiator Pointer to the initiating object. + * @param pcszDescription Description of the overall task. + * @param cOperations Number of operations for this task. + * @param uTotalOperationsWeight Overall weight for the entire task. + * @param pcszFirstOperationDescription Description of the first operation. + * @param uFirstOperationWeight Weight for the first operation. + * @param ppProgressOut Output parameter for the IProgress object reference. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnCreateProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IUnknown) *pInitiator, + const char *pcszDescription, uint32_t cOperations, + uint32_t uTotalOperationsWeight, const char *pcszFirstOperationDescription, + uint32_t uFirstOperationWeight, VBOXEXTPACK_IF_CS(IProgress) **ppProgressOut)); + + /** + * Checks if the Progress object is marked as canceled. + * + * @returns COM status code. + * @param pHlp Pointer to this helper structure. + * @param pProgress Pointer to the IProgress object reference returned + * by pfnCreateProgress. + * @param pfCanceled @c true if canceled, @c false otherwise. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetCanceledProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress, + bool *pfCanceled)); + + /** + * Updates the percentage value of the current operation of the + * Progress object. + * + * @returns COM status code. + * @param pHlp Pointer to this helper structure. + * @param pProgress Pointer to the IProgress object reference returned + * by pfnCreateProgress. + * @param uPercent Result of the overall task. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnUpdateProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress, + uint32_t uPercent)); + + /** + * Signals that the current operation is successfully completed and + * advances to the next operation. The operation percentage is reset + * to 0. + * + * If the operation count is exceeded this returns an error. + * + * @returns COM status code. + * @param pHlp Pointer to this helper structure. + * @param pProgress Pointer to the IProgress object reference returned + * by pfnCreateProgress. + * @param pcszNextOperationDescription Description of the next operation. + * @param uNextOperationWeight Weight for the next operation. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnNextOperationProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress, + const char *pcszNextOperationDescription, + uint32_t uNextOperationWeight)); + + /** + * Waits until the other task is completed (including all sub-operations) + * and forward all changes from the other progress to this progress. This + * means sub-operation number, description, percent and so on. + * + * The caller is responsible for having at least the same count of + * sub-operations in this progress object as there are in the other + * progress object. + * + * If the other progress object supports cancel and this object gets any + * cancel request (when here enabled as well), it will be forwarded to + * the other progress object. + * + * Error information is automatically preserved (by transferring it to + * the current thread's error information). If the caller wants to set it + * as the completion state of this progress it needs to be done separately. + * + * @returns COM status code. + * @param pHlp Pointer to this helper structure. + * @param pProgress Pointer to the IProgress object reference returned + * by pfnCreateProgress. + * @param pProgressOther Pointer to an IProgress object reference, the one + * to be waited for. + * @param cTimeoutMS Timeout in milliseconds, 0 for indefinite wait. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnWaitOtherProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress, + VBOXEXTPACK_IF_CS(IProgress) *pProgressOther, + uint32_t cTimeoutMS)); + + /** + * Marks the whole task as complete and sets the result code. + * + * If the result code indicates a failure then this method will store + * the currently set COM error info from the current thread in the + * the errorInfo attribute of this Progress object instance. If there + * is no error information available then an error is returned. + * + * If the result code indicates success then the task is terminated, + * without paying attention to the current operation being the last. + * + * Note that this must be called only once for the given Progress + * object. Subsequent calls will return errors. + * + * @returns COM status code. + * @param pHlp Pointer to this helper structure. + * @param pProgress Pointer to the IProgress object reference returned + * by pfnCreateProgress. + * @param uResultCode Result of the overall task. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnCompleteProgress,(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress, + uint32_t uResultCode)); + + + DECLR3CALLBACKMEMBER(uint32_t, pfnCreateEvent,(PCVBOXEXTPACKHLP pHlp, + VBOXEXTPACK_IF_CS(IEventSource) *aSource, + /* VBoxEventType_T */ uint32_t aType, bool aWaitable, + VBOXEXTPACK_IF_CS(IEvent) **ppEventOut)); + + DECLR3CALLBACKMEMBER(uint32_t, pfnCreateVetoEvent,(PCVBOXEXTPACKHLP pHlp, + VBOXEXTPACK_IF_CS(IEventSource) *aSource, + /* VBoxEventType_T */ uint32_t aType, + VBOXEXTPACK_IF_CS(IVetoEvent) **ppEventOut)); + + /** + * Translate the string using registered translation files. + * + * Translation files are excluded from translation engine. Although + * the already loaded translation remains in the translation cache the new + * translation will not be loaded after returning from the function if the + * user changes the language. + * + * @returns Translated string on success the pszSourceText otherwise. + * @param pHlp Pointer to this helper structure. + * @param aComponent Translation context e.g. class name + * @param pszSourceText String to translate + * @param pszComment Comment to the string to resolve possible ambiguities + * (NULL means no comment). + * @param aNum Number used to define plural form of the translation + */ + DECLR3CALLBACKMEMBER(const char *, pfnTranslate,(PCVBOXEXTPACKHLP pHlp, + const char *pszComponent, + const char *pszSourceText, + const char *pszComment, + const size_t aNum)); + + DECLR3CALLBACKMEMBER(int, pfnReserved1,(PCVBOXEXTPACKHLP pHlp)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved2,(PCVBOXEXTPACKHLP pHlp)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved3,(PCVBOXEXTPACKHLP pHlp)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved4,(PCVBOXEXTPACKHLP pHlp)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved5,(PCVBOXEXTPACKHLP pHlp)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved6,(PCVBOXEXTPACKHLP pHlp)); /**< Reserved for minor structure revisions. */ + + /** Reserved for minor structure revisions. */ + uint32_t uReserved7; + + /** End of structure marker (VBOXEXTPACKHLP_VERSION). */ + uint32_t u32EndMarker; +} VBOXEXTPACKHLP; +/** Current version of the VBOXEXTPACKHLP structure. */ +#define VBOXEXTPACKHLP_VERSION RT_MAKE_U32(0, 5) + + +/** Pointer to the extension pack callback table. */ +typedef struct VBOXEXTPACKREG const *PCVBOXEXTPACKREG; +/** + * Callback table returned by VBoxExtPackRegister. + * + * All the callbacks are called the context of the per-user service (VBoxSVC). + * + * This must be valid until the extension pack main module is unloaded. + */ +typedef struct VBOXEXTPACKREG +{ + /** Interface version. + * This is set to VBOXEXTPACKREG_VERSION. */ + uint32_t u32Version; + /** The VirtualBox version this extension pack was built against. */ + uint32_t uVBoxVersion; + /** Translation files base name. Set to NULL if no translation files. */ + const char *pszNlsBaseName; + + /** + * Hook for doing setups after the extension pack was installed. + * + * @returns VBox status code. + * @retval VERR_EXTPACK_UNSUPPORTED_HOST_UNINSTALL if the extension pack + * requires some different host version or a prerequisite is + * missing from the host. Automatic uninstall will be attempted. + * Must set error info. + * + * @param pThis Pointer to this structure. + * @param pVirtualBox The VirtualBox interface. + * @param pErrInfo Where to return extended error information. + */ + DECLCALLBACKMEMBER(int, pfnInstalled,(PCVBOXEXTPACKREG pThis, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox, + PRTERRINFO pErrInfo)); + + /** + * Hook for cleaning up before the extension pack is uninstalled. + * + * @returns VBox status code. + * @param pThis Pointer to this structure. + * @param pVirtualBox The VirtualBox interface. + * + * @todo This is currently called holding locks making pVirtualBox + * relatively unusable. + */ + DECLCALLBACKMEMBER(int, pfnUninstall,(PCVBOXEXTPACKREG pThis, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox)); + + /** + * Hook for doing work after the VirtualBox object is ready. + * + * @param pThis Pointer to this structure. + * @param pVirtualBox The VirtualBox interface. + */ + DECLCALLBACKMEMBER(void, pfnVirtualBoxReady,(PCVBOXEXTPACKREG pThis, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox)); + + /** + * Hook for doing work before unloading. + * + * @param pThis Pointer to this structure. + * + * @remarks The helpers are not available at this point in time. + * @remarks This is not called on uninstall, then pfnUninstall will be the + * last callback. + */ + DECLCALLBACKMEMBER(void, pfnUnload,(PCVBOXEXTPACKREG pThis)); + + /** + * Hook for changing the default VM configuration upon creation. + * + * @returns VBox status code. + * @param pThis Pointer to this structure. + * @param pVirtualBox The VirtualBox interface. + * @param pMachine The machine interface. + */ + DECLCALLBACKMEMBER(int, pfnVMCreated,(PCVBOXEXTPACKREG pThis, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox, + VBOXEXTPACK_IF_CS(IMachine) *pMachine)); + + /** + * Query the IUnknown interface to an object in the main module. + * + * @returns IUnknown pointer (referenced) on success, NULL on failure. + * @param pThis Pointer to this structure. + * @param pObjectId Pointer to the object ID (UUID). + */ + DECLCALLBACKMEMBER(void *, pfnQueryObject,(PCVBOXEXTPACKREG pThis, PCRTUUID pObjectId)); + + DECLR3CALLBACKMEMBER(int, pfnReserved1,(PCVBOXEXTPACKREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved2,(PCVBOXEXTPACKREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved3,(PCVBOXEXTPACKREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved4,(PCVBOXEXTPACKREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved5,(PCVBOXEXTPACKREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved6,(PCVBOXEXTPACKREG pThis)); /**< Reserved for minor structure revisions. */ + + /** Reserved for minor structure revisions. */ + uint32_t uReserved7; + + /** End of structure marker (VBOXEXTPACKREG_VERSION). */ + uint32_t u32EndMarker; +} VBOXEXTPACKREG; +/** Current version of the VBOXEXTPACKREG structure. */ +#define VBOXEXTPACKREG_VERSION RT_MAKE_U32(0, 3) + + +/** + * The VBoxExtPackRegister callback function. + * + * The Main API (as in VBoxSVC) will invoke this function after loading an + * extension pack Main module. Its job is to do version compatibility checking + * and returning the extension pack registration structure. + * + * @returns VBox status code. + * @param pHlp Pointer to the extension pack helper function + * table. This is valid until the module is unloaded. + * @param ppReg Where to return the pointer to the registration + * structure containing all the hooks. This structure + * be valid and unchanged until the module is unloaded + * (i.e. use some static const data for it). + * @param pErrInfo Where to return extended error information. + */ +typedef DECLCALLBACKTYPE(int, FNVBOXEXTPACKREGISTER,(PCVBOXEXTPACKHLP pHlp, PCVBOXEXTPACKREG *ppReg, PRTERRINFO pErrInfo)); +/** Pointer to a FNVBOXEXTPACKREGISTER. */ +typedef FNVBOXEXTPACKREGISTER *PFNVBOXEXTPACKREGISTER; + +/** The name of the main module entry point. */ +#define VBOX_EXTPACK_MAIN_MOD_ENTRY_POINT "VBoxExtPackRegister" + + +/** Pointer to the extension pack VM callback table. */ +typedef struct VBOXEXTPACKVMREG const *PCVBOXEXTPACKVMREG; +/** + * Callback table returned by VBoxExtPackVMRegister. + * + * All the callbacks are called the context of a VM process. + * + * This must be valid until the extension pack main VM module is unloaded. + */ +typedef struct VBOXEXTPACKVMREG +{ + /** Interface version. + * This is set to VBOXEXTPACKVMREG_VERSION. */ + uint32_t u32Version; + /** The VirtualBox version this extension pack was built against. */ + uint32_t uVBoxVersion; + /** Translation files base name. Set to NULL if no translation files. */ + const char *pszNlsBaseName; + + /** + * Hook for doing work after the Console object is ready. + * + * @param pThis Pointer to this structure. + * @param pConsole The Console interface. + */ + DECLCALLBACKMEMBER(void, pfnConsoleReady,(PCVBOXEXTPACKVMREG pThis, VBOXEXTPACK_IF_CS(IConsole) *pConsole)); + + /** + * Hook for doing work before unloading. + * + * @param pThis Pointer to this structure. + * + * @remarks The helpers are not available at this point in time. + */ + DECLCALLBACKMEMBER(void, pfnUnload,(PCVBOXEXTPACKVMREG pThis)); + + /** + * Hook for configuring the VMM for a VM. + * + * @returns VBox status code. + * @param pThis Pointer to this structure. + * @param pConsole The console interface. + * @param pVM The cross context VM structure. + * @param pVMM The VMM function table. + */ + DECLCALLBACKMEMBER(int, pfnVMConfigureVMM,(PCVBOXEXTPACKVMREG pThis, VBOXEXTPACK_IF_CS(IConsole) *pConsole, + PVM pVM, PCVMMR3VTABLE pVMM)); + + /** + * Hook for doing work right before powering on the VM. + * + * @returns VBox status code. + * @param pThis Pointer to this structure. + * @param pConsole The console interface. + * @param pVM The cross context VM structure. + * @param pVMM The VMM function table. + */ + DECLCALLBACKMEMBER(int, pfnVMPowerOn,(PCVBOXEXTPACKVMREG pThis, VBOXEXTPACK_IF_CS(IConsole) *pConsole, + PVM pVM, PCVMMR3VTABLE pVMM)); + + /** + * Hook for doing work after powering off the VM. + * + * @param pThis Pointer to this structure. + * @param pConsole The console interface. + * @param pVM The cross context VM structure. Can be NULL. + * @param pVMM The VMM function table. + */ + DECLCALLBACKMEMBER(void, pfnVMPowerOff,(PCVBOXEXTPACKVMREG pThis, VBOXEXTPACK_IF_CS(IConsole) *pConsole, + PVM pVM, PCVMMR3VTABLE pVMM)); + + /** + * Query the IUnknown interface to an object in the main VM module. + * + * @returns IUnknown pointer (referenced) on success, NULL on failure. + * @param pThis Pointer to this structure. + * @param pObjectId Pointer to the object ID (UUID). + */ + DECLCALLBACKMEMBER(void *, pfnQueryObject,(PCVBOXEXTPACKVMREG pThis, PCRTUUID pObjectId)); + + DECLR3CALLBACKMEMBER(int, pfnReserved1,(PCVBOXEXTPACKVMREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved2,(PCVBOXEXTPACKVMREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved3,(PCVBOXEXTPACKVMREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved4,(PCVBOXEXTPACKVMREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved5,(PCVBOXEXTPACKVMREG pThis)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved6,(PCVBOXEXTPACKVMREG pThis)); /**< Reserved for minor structure revisions. */ + + /** Reserved for minor structure revisions. */ + uint32_t uReserved7; + + /** End of structure marker (VBOXEXTPACKVMREG_VERSION). */ + uint32_t u32EndMarker; +} VBOXEXTPACKVMREG; +/** Current version of the VBOXEXTPACKVMREG structure. */ +#define VBOXEXTPACKVMREG_VERSION RT_MAKE_U32(1, 0) + + +/** + * The VBoxExtPackVMRegister callback function. + * + * The Main API (in a VM process) will invoke this function after loading an + * extension pack VM module. Its job is to do version compatibility checking + * and returning the extension pack registration structure for a VM. + * + * @returns VBox status code. + * @param pHlp Pointer to the extension pack helper function + * table. This is valid until the module is unloaded. + * @param ppReg Where to return the pointer to the registration + * structure containing all the hooks. This structure + * be valid and unchanged until the module is unloaded + * (i.e. use some static const data for it). + * @param pErrInfo Where to return extended error information. + */ +typedef DECLCALLBACKTYPE(int, FNVBOXEXTPACKVMREGISTER,(PCVBOXEXTPACKHLP pHlp, PCVBOXEXTPACKVMREG *ppReg, PRTERRINFO pErrInfo)); +/** Pointer to a FNVBOXEXTPACKVMREGISTER. */ +typedef FNVBOXEXTPACKVMREGISTER *PFNVBOXEXTPACKVMREGISTER; + +/** The name of the main VM module entry point. */ +#define VBOX_EXTPACK_MAIN_VM_MOD_ENTRY_POINT "VBoxExtPackVMRegister" + + +/** + * Checks if extension pack interface version is compatible. + * + * @returns true if the do, false if they don't. + * @param u32Provider The provider version. + * @param u32User The user version. + */ +#define VBOXEXTPACK_IS_VER_COMPAT(u32Provider, u32User) \ + ( VBOXEXTPACK_IS_MAJOR_VER_EQUAL(u32Provider, u32User) \ + && (int32_t)RT_LOWORD(u32Provider) >= (int32_t)RT_LOWORD(u32User) ) /* stupid casts to shut up gcc */ + +/** + * Check if two extension pack interface versions has the same major version. + * + * @returns true if the do, false if they don't. + * @param u32Ver1 The first version number. + * @param u32Ver2 The second version number. + */ +#define VBOXEXTPACK_IS_MAJOR_VER_EQUAL(u32Ver1, u32Ver2) (RT_HIWORD(u32Ver1) == RT_HIWORD(u32Ver2)) + +#endif /* !VBOX_INCLUDED_ExtPack_ExtPack_h */ + diff --git a/include/VBox/Graphics/HGSMI.h b/include/VBox/Graphics/HGSMI.h new file mode 100644 index 00000000..da485add --- /dev/null +++ b/include/VBox/Graphics/HGSMI.h @@ -0,0 +1,251 @@ +/* $Id: HGSMI.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - Host/Guest shared part. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMI_h +#define VBOX_INCLUDED_Graphics_HGSMI_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBoxVideoIPRT.h" + +#include "HGSMIDefs.h" +#include "HGSMIChannels.h" +#include "HGSMIMemAlloc.h" + +/** + * Basic mechanism for the HGSMI is to prepare and pass data buffer to the host and the guest. + * Data inside these buffers are opaque for the HGSMI and are interpreted by higher levels. + * + * Every shared memory buffer passed between the guest/host has the following structure: + * + * HGSMIBUFFERHEADER header; + * uint8_t data[header.u32BufferSize]; + * HGSMIBUFFERTAIL tail; + * + * Note: Offset of the 'header' in the memory is used for virtual hardware IO. + * + * Buffers are verifyed using the offset and the content of the header and the tail, + * which are constant during a call. + * + * Invalid buffers are ignored. + * + * Actual 'data' is not verifyed, as it is expected that the data can be changed by the + * called function. + * + * Since only the offset of the buffer is passed in a IO operation, the header and tail + * must contain: + * * size of data in this buffer; + * * checksum for buffer verification. + * + * For segmented transfers: + * * the sequence identifier; + * * offset of the current segment in the sequence; + * * total bytes in the transfer. + * + * Additionally contains: + * * the channel ID; + * * the channel information. + */ + +typedef struct HGSMIHEAP +{ + HGSMIAREA area; /**< Description. */ + HGSMIMADATA ma; /**< Memory allocator */ +} HGSMIHEAP; + +/* The size of the array of channels. Array indexes are uint8_t. Note: the value must not be changed. */ +#define HGSMI_NUMBER_OF_CHANNELS 0x100 + +/** + * Channel handler called when the guest submits a buffer. + * + * @returns stuff + * @param pvHandler Value specified when registring. + * @param u16ChannelInfo Command code. + * @param pvBuffer HGSMI buffer with command data. This is shared with + * the guest. Consider untrusted and volatile! + * @param cbBuffer Size of command data. + * @thread EMT on the host side. + */ +typedef DECLCALLBACKTYPE(int, FNHGSMICHANNELHANDLER,(void *pvHandler, uint16_t u16ChannelInfo, + RT_UNTRUSTED_VOLATILE_HSTGST void *pvBuffer, HGSMISIZE cbBuffer)); +/** Pointer to a channel handler callback. */ +typedef FNHGSMICHANNELHANDLER *PFNHGSMICHANNELHANDLER; + +/** Information about a handler: pfn + context. */ +typedef struct _HGSMICHANNELHANDLER +{ + PFNHGSMICHANNELHANDLER pfnHandler; + void *pvHandler; +} HGSMICHANNELHANDLER; + +/** Channel description. */ +typedef struct _HGSMICHANNEL +{ + HGSMICHANNELHANDLER handler; /**< The channel handler. */ + const char *pszName; /**< NULL for hardcoded channels or RTStrDup'ed name. */ + uint8_t u8Channel; /**< The channel id, equal to the channel index in the array. */ + uint8_t u8Flags; /**< HGSMI_CH_F_* */ +} HGSMICHANNEL; + +typedef struct _HGSMICHANNELINFO +{ + /** Channel handlers indexed by the channel id. + * The array is accessed under the instance lock. */ + HGSMICHANNEL Channels[HGSMI_NUMBER_OF_CHANNELS]; +} HGSMICHANNELINFO; + + +RT_C_DECLS_BEGIN + +DECLINLINE(HGSMIBUFFERHEADER *) HGSMIBufferHeaderFromPtr(void RT_UNTRUSTED_VOLATILE_HSTGST *pvBuffer) +{ + return (HGSMIBUFFERHEADER *)pvBuffer; +} + +DECLINLINE(uint8_t RT_UNTRUSTED_VOLATILE_HSTGST *) HGSMIBufferDataFromPtr(void RT_UNTRUSTED_VOLATILE_HSTGST *pvBuffer) +{ + return (uint8_t RT_UNTRUSTED_VOLATILE_HSTGST *)pvBuffer + sizeof(HGSMIBUFFERHEADER); +} + +DECLINLINE(HGSMIBUFFERTAIL RT_UNTRUSTED_VOLATILE_HSTGST *) +HGSMIBufferTailFromPtr(void RT_UNTRUSTED_VOLATILE_HSTGST *pvBuffer, uint32_t u32DataSize) +{ + return (HGSMIBUFFERTAIL RT_UNTRUSTED_VOLATILE_HSTGST *)(HGSMIBufferDataFromPtr(pvBuffer) + u32DataSize); +} + +DECLINLINE(HGSMISIZE) HGSMIBufferMinimumSize(void) +{ + return sizeof(HGSMIBUFFERHEADER) + sizeof(HGSMIBUFFERTAIL); +} + +DECLINLINE(HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_HSTGST *) HGSMIBufferHeaderFromData(const void RT_UNTRUSTED_VOLATILE_HSTGST *pvData) +{ + return (HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_HSTGST *)((uint8_t *)pvData - sizeof(HGSMIBUFFERHEADER)); +} + +DECLINLINE(HGSMISIZE) HGSMIBufferRequiredSize(uint32_t u32DataSize) +{ + return HGSMIBufferMinimumSize() + u32DataSize; +} + +DECLINLINE(HGSMIOFFSET) HGSMIPointerToOffset(const HGSMIAREA *pArea, const void RT_UNTRUSTED_VOLATILE_HSTGST *pv) +{ + return pArea->offBase + (HGSMIOFFSET)((uint8_t *)pv - pArea->pu8Base); +} + +DECLINLINE(void RT_UNTRUSTED_VOLATILE_HSTGST *) HGSMIOffsetToPointer(const HGSMIAREA *pArea, HGSMIOFFSET offBuffer) +{ + return pArea->pu8Base + (offBuffer - pArea->offBase); +} + +DECLINLINE(uint8_t RT_UNTRUSTED_VOLATILE_HSTGST*) HGSMIBufferDataFromOffset(const HGSMIAREA *pArea, HGSMIOFFSET offBuffer) +{ + void RT_UNTRUSTED_VOLATILE_HSTGST *pvBuffer = HGSMIOffsetToPointer(pArea, offBuffer); + return HGSMIBufferDataFromPtr(pvBuffer); +} + +DECLINLINE(HGSMIOFFSET) HGSMIBufferOffsetFromData(const HGSMIAREA *pArea, void RT_UNTRUSTED_VOLATILE_HSTGST *pvData) +{ + HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_HSTGST *pHeader = HGSMIBufferHeaderFromData(pvData); + return HGSMIPointerToOffset(pArea, pHeader); +} + +DECLINLINE(uint8_t RT_UNTRUSTED_VOLATILE_HSTGST *) HGSMIBufferDataAndChInfoFromOffset(const HGSMIAREA *pArea, + HGSMIOFFSET offBuffer, + uint16_t *pu16ChannelInfo) +{ + HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_HSTGST *pHeader = + (HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_HSTGST *)HGSMIOffsetToPointer(pArea, offBuffer); + *pu16ChannelInfo = pHeader->u16ChannelInfo; + return HGSMIBufferDataFromPtr(pHeader); +} + +uint32_t HGSMIChecksum(HGSMIOFFSET offBuffer, const HGSMIBUFFERHEADER RT_UNTRUSTED_VOLATILE_HSTGST *pHeader, + const HGSMIBUFFERTAIL RT_UNTRUSTED_VOLATILE_HSTGST *pTail); + +int HGSMIAreaInitialize(HGSMIAREA *pArea, void *pvBase, HGSMISIZE cbArea, HGSMIOFFSET offBase); +void HGSMIAreaClear(HGSMIAREA *pArea); + +DECLINLINE(bool) HGSMIAreaContainsOffset(const HGSMIAREA *pArea, HGSMIOFFSET off) +{ + return off >= pArea->offBase && off - pArea->offBase < pArea->cbArea; +} + +DECLINLINE(bool) HGSMIAreaContainsPointer(const HGSMIAREA *pArea, const void RT_UNTRUSTED_VOLATILE_HSTGST *pv) +{ + return (uintptr_t)pv - (uintptr_t)pArea->pu8Base < pArea->cbArea; +} + +HGSMIOFFSET HGSMIBufferInitializeSingle(const HGSMIAREA *pArea, HGSMIBUFFERHEADER *pHeader, HGSMISIZE cbBuffer, + uint8_t u8Channel, uint16_t u16ChannelInfo); + +int HGSMIHeapSetup(HGSMIHEAP *pHeap, void *pvBase, HGSMISIZE cbArea, HGSMIOFFSET offBase, const HGSMIENV *pEnv); +void HGSMIHeapDestroy(HGSMIHEAP *pHeap); +void RT_UNTRUSTED_VOLATILE_HSTGST *HGSMIHeapBufferAlloc(HGSMIHEAP *pHeap, HGSMISIZE cbBuffer); +void HGSMIHeapBufferFree(HGSMIHEAP *pHeap, void RT_UNTRUSTED_VOLATILE_HSTGST *pvBuf); + +void RT_UNTRUSTED_VOLATILE_HOST *HGSMIHeapAlloc(HGSMIHEAP *pHeap, + HGSMISIZE cbData, + uint8_t u8Channel, + uint16_t u16ChannelInfo); + +void HGSMIHeapFree(HGSMIHEAP *pHeap, void RT_UNTRUSTED_VOLATILE_HSTGST *pvData); + +DECLINLINE(const HGSMIAREA *) HGSMIHeapArea(HGSMIHEAP *pHeap) +{ + return &pHeap->area; +} + +DECLINLINE(HGSMIOFFSET) HGSMIHeapOffset(HGSMIHEAP *pHeap) +{ + return HGSMIHeapArea(pHeap)->offBase; +} + +DECLINLINE(HGSMISIZE) HGSMIHeapSize(HGSMIHEAP *pHeap) +{ + return HGSMIHeapArea(pHeap)->cbArea; +} + +DECLINLINE(HGSMIOFFSET) HGSMIHeapBufferOffset(HGSMIHEAP *pHeap, void RT_UNTRUSTED_VOLATILE_HOST *pvData) +{ + return HGSMIBufferOffsetFromData(HGSMIHeapArea(pHeap), pvData); +} + +HGSMICHANNEL *HGSMIChannelFindById(HGSMICHANNELINFO *pChannelInfo, uint8_t u8Channel); + +int HGSMIChannelRegister(HGSMICHANNELINFO *pChannelInfo, uint8_t u8Channel, const char *pszName, + PFNHGSMICHANNELHANDLER pfnChannelHandler, void *pvChannelHandler); +int HGSMIBufferProcess(const HGSMIAREA *pArea, HGSMICHANNELINFO *pChannelInfo, HGSMIOFFSET offBuffer); +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_Graphics_HGSMI_h */ + diff --git a/include/VBox/Graphics/HGSMIBase.h b/include/VBox/Graphics/HGSMIBase.h new file mode 100644 index 00000000..aad0bfbe --- /dev/null +++ b/include/VBox/Graphics/HGSMIBase.h @@ -0,0 +1,60 @@ +/* $Id: HGSMIBase.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - buffer management. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIBase_h +#define VBOX_INCLUDED_Graphics_HGSMIBase_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "HGSMI.h" +#include "HGSMIContext.h" +#include "VBoxVideoIPRT.h" + +RT_C_DECLS_BEGIN + +/** @name Base HGSMI Buffer APIs + * @{ */ + +/** Acknowlege an IRQ. */ +DECLINLINE(void) VBoxHGSMIClearIrq(PHGSMIHOSTCOMMANDCONTEXT pCtx) +{ + VBVO_PORT_WRITE_U32(pCtx->port, HGSMIOFFSET_VOID); +} + +DECLHIDDEN(void RT_UNTRUSTED_VOLATILE_HOST *) VBoxHGSMIBufferAlloc(PHGSMIGUESTCOMMANDCONTEXT pCtx, HGSMISIZE cbData, + uint8_t u8Ch, uint16_t u16Op); +DECLHIDDEN(void) VBoxHGSMIBufferFree(PHGSMIGUESTCOMMANDCONTEXT pCtx, void RT_UNTRUSTED_VOLATILE_HOST *pvBuffer); +DECLHIDDEN(int) VBoxHGSMIBufferSubmit(PHGSMIGUESTCOMMANDCONTEXT pCtx, void RT_UNTRUSTED_VOLATILE_HOST *pvBuffer); +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIBase_h */ diff --git a/include/VBox/Graphics/HGSMIChSetup.h b/include/VBox/Graphics/HGSMIChSetup.h new file mode 100644 index 00000000..0e11b580 --- /dev/null +++ b/include/VBox/Graphics/HGSMIChSetup.h @@ -0,0 +1,88 @@ +/* $Id: HGSMIChSetup.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI), Host/Guest shared part. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIChSetup_h +#define VBOX_INCLUDED_Graphics_HGSMIChSetup_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "HGSMIDefs.h" + +/* HGSMI setup and configuration channel commands and data structures. */ +/* + * Tell the host the location of hgsmi_host_flags structure, where the host + * can write information about pending buffers, etc, and which can be quickly + * polled by the guest without a need to port IO. + */ +#define HGSMI_CC_HOST_FLAGS_LOCATION 0 + +typedef struct HGSMIBUFFERLOCATION +{ + HGSMIOFFSET offLocation; + HGSMISIZE cbLocation; +} HGSMIBUFFERLOCATION; +AssertCompileSize(HGSMIBUFFERLOCATION, 8); + +/* HGSMI setup and configuration data structures. */ +/* host->guest commands pending, should be accessed under FIFO lock only */ +#define HGSMIHOSTFLAGS_COMMANDS_PENDING UINT32_C(0x01) +/* IRQ is fired, should be accessed under VGAState::lock only */ +#define HGSMIHOSTFLAGS_IRQ UINT32_C(0x02) +#ifdef VBOX_WITH_WDDM +/* one or more guest commands is completed, should be accessed under FIFO lock only */ +# define HGSMIHOSTFLAGS_GCOMMAND_COMPLETED UINT32_C(0x04) +#endif +/* vsync interrupt flag, should be accessed under VGAState::lock only */ +#define HGSMIHOSTFLAGS_VSYNC UINT32_C(0x10) +/** monitor hotplug flag, should be accessed under VGAState::lock only */ +#define HGSMIHOSTFLAGS_HOTPLUG UINT32_C(0x20) +/** + * Cursor capability state change flag, should be accessed under + * VGAState::lock only. @see VBVACONF32. + */ +#define HGSMIHOSTFLAGS_CURSOR_CAPABILITIES UINT32_C(0x40) + +typedef struct HGSMIHOSTFLAGS +{ + /* + * Host flags can be accessed and modified in multiple threads + * concurrently, e.g. CrOpenGL HGCM and GUI threads when completing + * HGSMI 3D and Video Accel respectively, EMT thread when dealing with + * HGSMI command processing, etc. + * Besides settings/cleaning flags atomically, some flags have their + * own special sync restrictions, see comments for flags above. + */ + volatile uint32_t u32HostFlags; + uint32_t au32Reserved[3]; +} HGSMIHOSTFLAGS; +AssertCompileSize(HGSMIHOSTFLAGS, 16); + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIChSetup_h */ diff --git a/include/VBox/Graphics/HGSMIChannels.h b/include/VBox/Graphics/HGSMIChannels.h new file mode 100644 index 00000000..c957040b --- /dev/null +++ b/include/VBox/Graphics/HGSMIChannels.h @@ -0,0 +1,77 @@ +/* $Id: HGSMIChannels.h $ */ +/** @file + * + * VBox Host Guest Shared Memory Interface (HGSMI). + * Host/Guest shared part. + * Channel identifiers. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIChannels_h +#define VBOX_INCLUDED_Graphics_HGSMIChannels_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/* + * Each channel has an 8 bit identifier. There are a number of predefined + * (hardcoded) channels. + * + * HGSMI_CH_HGSMI channel can be used to map a string channel identifier + * to a free 16 bit numerical value. values are allocated in range + * [HGSMI_CH_STRING_FIRST;HGSMI_CH_STRING_LAST]. + */ + + +/* Predefined channel identifiers. Used internally by VBOX to simplify the channel setup. */ +/* A reserved channel value */ +#define HGSMI_CH_RESERVED 0x00 +/* HGCMI: setup and configuration */ +#define HGSMI_CH_HGSMI 0x01 +/* Graphics: VBVA */ +#define HGSMI_CH_VBVA 0x02 +/* Graphics: Seamless with a single guest region */ +#define HGSMI_CH_SEAMLESS 0x03 +/* Graphics: Seamless with separate host windows */ +#define HGSMI_CH_SEAMLESS2 0x04 +/* Graphics: OpenGL HW acceleration */ +#define HGSMI_CH_OPENGL 0x05 + + +/* Dynamically allocated channel identifiers. */ +/* The first channel index to be used for string mappings (inclusive) */ +#define HGSMI_CH_STRING_FIRST 0x20 +/* The last channel index for string mappings (inclusive) */ +#define HGSMI_CH_STRING_LAST 0xff + + +/* Check whether the channel identifier is allocated for a dynamic channel */ +#define HGSMI_IS_DYNAMIC_CHANNEL(_channel) (((uint8_t)(_channel) & 0xE0) != 0) + + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIChannels_h */ diff --git a/include/VBox/Graphics/HGSMIContext.h b/include/VBox/Graphics/HGSMIContext.h new file mode 100644 index 00000000..23e810c0 --- /dev/null +++ b/include/VBox/Graphics/HGSMIContext.h @@ -0,0 +1,114 @@ +/* $Id: HGSMIContext.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - command contexts. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIContext_h +#define VBOX_INCLUDED_Graphics_HGSMIContext_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "HGSMI.h" +#include "HGSMIChSetup.h" +#include "VBoxVideoIPRT.h" + +#ifdef VBOX_WDDM_MINIPORT +# include "wddm/VBoxMPShgsmi.h" + typedef VBOXSHGSMI HGSMIGUESTCMDHEAP; +# define HGSMIGUESTCMDHEAP_GET(_p) (&(_p)->Heap) +#else + typedef HGSMIHEAP HGSMIGUESTCMDHEAP; +# define HGSMIGUESTCMDHEAP_GET(_p) (_p) +#endif + +RT_C_DECLS_BEGIN + +/** + * Structure grouping the context needed for submitting commands to the host + * via HGSMI + */ +typedef struct HGSMIGUESTCOMMANDCONTEXT +{ + /** Information about the memory heap located in VRAM from which data + * structures to be sent to the host are allocated. */ + HGSMIGUESTCMDHEAP heapCtx; + /** The I/O port used for submitting commands to the host by writing their + * offsets into the heap. */ + RTIOPORT port; +} HGSMIGUESTCOMMANDCONTEXT, *PHGSMIGUESTCOMMANDCONTEXT; + + +/** + * Structure grouping the context needed for receiving commands from the host + * via HGSMI + */ +typedef struct HGSMIHOSTCOMMANDCONTEXT +{ + /** Information about the memory area located in VRAM in which the host + * places data structures to be read by the guest. */ + HGSMIAREA areaCtx; + /** Convenience structure used for matching host commands to handlers. */ + /** @todo handlers are registered individually in code rather than just + * passing a static structure in order to gain extra flexibility. There is + * currently no expected usage case for this though. Is the additional + * complexity really justified? */ + HGSMICHANNELINFO channels; + /** Flag to indicate that one thread is currently processing the command + * queue. */ + volatile bool fHostCmdProcessing; + /* Pointer to the VRAM location where the HGSMI host flags are kept. */ + volatile HGSMIHOSTFLAGS *pfHostFlags; + /** The I/O port used for receiving commands from the host as offsets into + * the memory area and sending back confirmations (command completion, + * IRQ acknowlegement). */ + RTIOPORT port; +} HGSMIHOSTCOMMANDCONTEXT, *PHGSMIHOSTCOMMANDCONTEXT; + +/** @name HGSMI context initialisation APIs. + * @{ */ + +/** @todo we should provide a cleanup function too as part of the API */ +DECLHIDDEN(int) VBoxHGSMISetupGuestContext(PHGSMIGUESTCOMMANDCONTEXT pCtx, + void *pvGuestHeapMemory, + uint32_t cbGuestHeapMemory, + uint32_t offVRAMGuestHeapMemory, + const HGSMIENV *pEnv); +DECLHIDDEN(void) VBoxHGSMISetupHostContext(PHGSMIHOSTCOMMANDCONTEXT pCtx, + void *pvBaseMapping, + uint32_t offHostFlags, + void *pvHostAreaMapping, + uint32_t offVRAMHostArea, + uint32_t cbHostArea); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIContext_h */ + diff --git a/include/VBox/Graphics/HGSMIDefs.h b/include/VBox/Graphics/HGSMIDefs.h new file mode 100644 index 00000000..adbceafe --- /dev/null +++ b/include/VBox/Graphics/HGSMIDefs.h @@ -0,0 +1,128 @@ +/* $Id: HGSMIDefs.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - shared part - types and defines. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIDefs_h +#define VBOX_INCLUDED_Graphics_HGSMIDefs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBoxVideoIPRT.h" + +/* HGSMI uses 32 bit offsets and sizes. */ +typedef uint32_t HGSMISIZE; +typedef uint32_t HGSMIOFFSET; + +#define HGSMIOFFSET_VOID ((HGSMIOFFSET)~0) + +/** + * Describes a shared memory area buffer. + * + * Used for calculations with offsets and for buffers verification. + */ +typedef struct HGSMIAREA +{ + uint8_t *pu8Base; /**< The starting address of the area. Corresponds to offset 'offBase'. */ + HGSMIOFFSET offBase; /**< The starting offset of the area. */ + HGSMIOFFSET offLast; /**< The last valid offset: offBase + cbArea - 1 - (sizeof(header) + sizeof(tail)). */ + HGSMISIZE cbArea; /**< Size of the area. */ +} HGSMIAREA; + + +/* The buffer description flags. */ +#define HGSMI_BUFFER_HEADER_F_SEQ_MASK 0x03 /* Buffer sequence type mask. */ +#define HGSMI_BUFFER_HEADER_F_SEQ_SINGLE 0x00 /* Single buffer, not a part of a sequence. */ +#define HGSMI_BUFFER_HEADER_F_SEQ_START 0x01 /* The first buffer in a sequence. */ +#define HGSMI_BUFFER_HEADER_F_SEQ_CONTINUE 0x02 /* A middle buffer in a sequence. */ +#define HGSMI_BUFFER_HEADER_F_SEQ_END 0x03 /* The last buffer in a sequence. */ + + +#pragma pack(1) /** @todo not necessary. use AssertCompileSize instead. */ +/* 16 bytes buffer header. */ +typedef struct HGSMIBUFFERHEADER +{ + uint32_t u32DataSize; /* Size of data that follows the header. */ + + uint8_t u8Flags; /* The buffer description: HGSMI_BUFFER_HEADER_F_* */ + + uint8_t u8Channel; /* The channel the data must be routed to. */ + uint16_t u16ChannelInfo; /* Opaque to the HGSMI, used by the channel. */ + + union { + uint8_t au8Union[8]; /* Opaque placeholder to make the union 8 bytes. */ + + struct + { /* HGSMI_BUFFER_HEADER_F_SEQ_SINGLE */ + uint32_t u32Reserved1; /* A reserved field, initialize to 0. */ + uint32_t u32Reserved2; /* A reserved field, initialize to 0. */ + } Buffer; + + struct + { /* HGSMI_BUFFER_HEADER_F_SEQ_START */ + uint32_t u32SequenceNumber; /* The sequence number, the same for all buffers in the sequence. */ + uint32_t u32SequenceSize; /* The total size of the sequence. */ + } SequenceStart; + + struct + { /* HGSMI_BUFFER_HEADER_F_SEQ_CONTINUE and HGSMI_BUFFER_HEADER_F_SEQ_END */ + uint32_t u32SequenceNumber; /* The sequence number, the same for all buffers in the sequence. */ + uint32_t u32SequenceOffset; /* Data offset in the entire sequence. */ + } SequenceContinue; + } u; +} HGSMIBUFFERHEADER; + +/* 8 bytes buffer tail. */ +typedef struct HGSMIBUFFERTAIL +{ + uint32_t u32Reserved; /* Reserved, must be initialized to 0. */ + uint32_t u32Checksum; /* Verifyer for the buffer header and offset and for first 4 bytes of the tail. */ +} HGSMIBUFFERTAIL; +#pragma pack() + +AssertCompileSize(HGSMIBUFFERHEADER, 16); +AssertCompileSize(HGSMIBUFFERTAIL, 8); + +/* The size of the array of channels. Array indexes are uint8_t. Note: the value must not be changed. */ +#define HGSMI_NUMBER_OF_CHANNELS 0x100 + +typedef struct HGSMIENV +{ + /* Environment context pointer. */ + void *pvEnv; + + /* Allocate system memory. */ + DECLCALLBACKMEMBER(void *, pfnAlloc,(void *pvEnv, HGSMISIZE cb)); + + /* Free system memory. */ + DECLCALLBACKMEMBER(void, pfnFree,(void *pvEnv, void *pv)); +} HGSMIENV; + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIDefs_h */ + diff --git a/include/VBox/Graphics/HGSMIHostCmd.h b/include/VBox/Graphics/HGSMIHostCmd.h new file mode 100644 index 00000000..9c8b0b9e --- /dev/null +++ b/include/VBox/Graphics/HGSMIHostCmd.h @@ -0,0 +1,59 @@ +/* $Id: HGSMIHostCmd.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - buffer management. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIHostCmd_h +#define VBOX_INCLUDED_Graphics_HGSMIHostCmd_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "HGSMI.h" +#include "HGSMIContext.h" +#include "VBoxVideoIPRT.h" + +RT_C_DECLS_BEGIN + +/** @name Base HGSMI host command APIs. + * @{ */ + +DECLHIDDEN(void) VBoxHGSMIHostCmdComplete(PHGSMIHOSTCOMMANDCONTEXT pCtx, void RT_UNTRUSTED_VOLATILE_HOST *pvMem); +DECLHIDDEN(void) VBoxHGSMIProcessHostQueue(PHGSMIHOSTCOMMANDCONTEXT pCtx); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIHostCmd_h */ diff --git a/include/VBox/Graphics/HGSMIMemAlloc.h b/include/VBox/Graphics/HGSMIMemAlloc.h new file mode 100644 index 00000000..a837dc34 --- /dev/null +++ b/include/VBox/Graphics/HGSMIMemAlloc.h @@ -0,0 +1,113 @@ +/* $Id: HGSMIMemAlloc.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - Memory allocator. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_Graphics_HGSMIMemAlloc_h +#define VBOX_INCLUDED_Graphics_HGSMIMemAlloc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "HGSMIDefs.h" +#include "VBoxVideoIPRT.h" + + +/* Descriptor. */ +#define HGSMI_MA_DESC_OFFSET_MASK UINT32_C(0xFFFFFFE0) +#define HGSMI_MA_DESC_FREE_MASK UINT32_C(0x00000010) +#define HGSMI_MA_DESC_ORDER_MASK UINT32_C(0x0000000F) + +#define HGSMI_MA_DESC_OFFSET(d) ((d) & HGSMI_MA_DESC_OFFSET_MASK) +#define HGSMI_MA_DESC_IS_FREE(d) (((d) & HGSMI_MA_DESC_FREE_MASK) != 0) +#define HGSMI_MA_DESC_ORDER(d) ((d) & HGSMI_MA_DESC_ORDER_MASK) + +#define HGSMI_MA_DESC_ORDER_BASE UINT32_C(5) + +#define HGSMI_MA_BLOCK_SIZE_MIN (UINT32_C(1) << (HGSMI_MA_DESC_ORDER_BASE + 0)) +#define HGSMI_MA_BLOCK_SIZE_MAX (UINT32_C(1) << (HGSMI_MA_DESC_ORDER_BASE + HGSMI_MA_DESC_ORDER_MASK)) + +/* HGSMI_MA_DESC_ORDER_BASE must correspond to HGSMI_MA_DESC_OFFSET_MASK. */ +AssertCompile((~HGSMI_MA_DESC_OFFSET_MASK + 1) == HGSMI_MA_BLOCK_SIZE_MIN); + + +typedef struct HGSMIMABLOCK +{ + RTLISTNODE nodeBlock; + RTLISTNODE nodeFree; + HGSMIOFFSET descriptor; +} HGSMIMABLOCK; + +typedef struct HGSMIMADATA +{ + HGSMIAREA area; + HGSMIENV env; + HGSMISIZE cbMaxBlock; + + uint32_t cBlocks; /* How many blocks in the listBlocks. */ + RTLISTANCHOR listBlocks; /* All memory blocks, sorted. */ + RTLISTANCHOR aListFreeBlocks[HGSMI_MA_DESC_ORDER_MASK + 1]; /* For free blocks of each order. */ +} HGSMIMADATA; + +RT_C_DECLS_BEGIN + +int HGSMIMAInit(HGSMIMADATA *pMA, const HGSMIAREA *pArea, + HGSMIOFFSET *paDescriptors, uint32_t cDescriptors, HGSMISIZE cbMaxBlock, + const HGSMIENV *pEnv); +void HGSMIMAUninit(HGSMIMADATA *pMA); + +void RT_UNTRUSTED_VOLATILE_HSTGST *HGSMIMAAlloc(HGSMIMADATA *pMA, HGSMISIZE cb); +void HGSMIMAFree(HGSMIMADATA *pMA, void RT_UNTRUSTED_VOLATILE_GUEST *pv); + +HGSMIMABLOCK *HGSMIMASearchOffset(HGSMIMADATA *pMA, HGSMIOFFSET off); + +uint32_t HGSMIPopCnt32(uint32_t u32); + +DECLINLINE(HGSMISIZE) HGSMIMAOrder2Size(HGSMIOFFSET order) +{ + return (UINT32_C(1) << (HGSMI_MA_DESC_ORDER_BASE + order)); +} + +DECLINLINE(HGSMIOFFSET) HGSMIMASize2Order(HGSMISIZE cb) +{ + HGSMIOFFSET order = HGSMIPopCnt32(cb - 1) - HGSMI_MA_DESC_ORDER_BASE; +#ifdef HGSMI_STRICT + Assert(HGSMIMAOrder2Size(order) == cb); +#endif + return order; +} + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_Graphics_HGSMIMemAlloc_h */ diff --git a/include/VBox/Graphics/Makefile.kup b/include/VBox/Graphics/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/VBox/Graphics/VBoxUhgsmi.h b/include/VBox/Graphics/VBoxUhgsmi.h new file mode 100644 index 00000000..8f1328e2 --- /dev/null +++ b/include/VBox/Graphics/VBoxUhgsmi.h @@ -0,0 +1,145 @@ +/* $Id: VBoxUhgsmi.h $ */ +/** @file + * Document me, pretty please. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxUhgsmi_h +#define VBOX_INCLUDED_Graphics_VBoxUhgsmi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +typedef struct VBOXUHGSMI *PVBOXUHGSMI; + +typedef struct VBOXUHGSMI_BUFFER *PVBOXUHGSMI_BUFFER; + +typedef union VBOXUHGSMI_BUFFER_TYPE_FLAGS +{ + uint32_t Value; + struct + { + uint32_t fCommand : 1; + uint32_t Reserved : 31; + } s; +} VBOXUHGSMI_BUFFER_TYPE_FLAGS; + +typedef union VBOXUHGSMI_BUFFER_LOCK_FLAGS +{ + uint32_t Value; + struct + { + uint32_t fReadOnly : 1; + uint32_t fWriteOnly : 1; + uint32_t fDonotWait : 1; + uint32_t fDiscard : 1; + uint32_t fLockEntire : 1; + uint32_t Reserved : 27; + } s; +} VBOXUHGSMI_BUFFER_LOCK_FLAGS; + +typedef union VBOXUHGSMI_BUFFER_SUBMIT_FLAGS +{ + uint32_t Value; + struct + { + uint32_t fHostReadOnly : 1; + uint32_t fHostWriteOnly : 1; + uint32_t fDoNotRetire : 1; /**< the buffer will be used in a subsequent command */ + uint32_t fEntireBuffer : 1; + uint32_t Reserved : 28; + } s; +} VBOXUHGSMI_BUFFER_SUBMIT_FLAGS, *PVBOXUHGSMI_BUFFER_SUBMIT_FLAGS; + +/* the caller can specify NULL as a hSynch and specify a valid enmSynchType to make UHGSMI create a proper object itself, + * */ +typedef DECLCALLBACKTYPE(int, FNVBOXUHGSMI_BUFFER_CREATE,(PVBOXUHGSMI pHgsmi, uint32_t cbBuf, VBOXUHGSMI_BUFFER_TYPE_FLAGS fType, + PVBOXUHGSMI_BUFFER* ppBuf)); +typedef FNVBOXUHGSMI_BUFFER_CREATE *PFNVBOXUHGSMI_BUFFER_CREATE; + +typedef struct VBOXUHGSMI_BUFFER_SUBMIT +{ + PVBOXUHGSMI_BUFFER pBuf; + uint32_t offData; + uint32_t cbData; + VBOXUHGSMI_BUFFER_SUBMIT_FLAGS fFlags; +} VBOXUHGSMI_BUFFER_SUBMIT, *PVBOXUHGSMI_BUFFER_SUBMIT; + +typedef DECLCALLBACKTYPE(int, FNVBOXUHGSMI_BUFFER_SUBMIT,(PVBOXUHGSMI pHgsmi, PVBOXUHGSMI_BUFFER_SUBMIT aBuffers, + uint32_t cBuffers)); +typedef FNVBOXUHGSMI_BUFFER_SUBMIT *PFNVBOXUHGSMI_BUFFER_SUBMIT; + +typedef DECLCALLBACKTYPE(int, FNVBOXUHGSMI_BUFFER_DESTROY,(PVBOXUHGSMI_BUFFER pBuf)); +typedef FNVBOXUHGSMI_BUFFER_DESTROY *PFNVBOXUHGSMI_BUFFER_DESTROY; + +typedef DECLCALLBACKTYPE(int, FNVBOXUHGSMI_BUFFER_LOCK,(PVBOXUHGSMI_BUFFER pBuf, uint32_t offLock, uint32_t cbLock, + VBOXUHGSMI_BUFFER_LOCK_FLAGS fFlags, void**pvLock)); +typedef FNVBOXUHGSMI_BUFFER_LOCK *PFNVBOXUHGSMI_BUFFER_LOCK; + +typedef DECLCALLBACKTYPE(int, FNVBOXUHGSMI_BUFFER_UNLOCK,(PVBOXUHGSMI_BUFFER pBuf)); +typedef FNVBOXUHGSMI_BUFFER_UNLOCK *PFNVBOXUHGSMI_BUFFER_UNLOCK; + +typedef struct VBOXUHGSMI +{ + PFNVBOXUHGSMI_BUFFER_CREATE pfnBufferCreate; + PFNVBOXUHGSMI_BUFFER_SUBMIT pfnBufferSubmit; + /** User custom data. */ + void *pvUserData; +} VBOXUHGSMI; + +typedef struct VBOXUHGSMI_BUFFER +{ + PFNVBOXUHGSMI_BUFFER_LOCK pfnLock; + PFNVBOXUHGSMI_BUFFER_UNLOCK pfnUnlock; + PFNVBOXUHGSMI_BUFFER_DESTROY pfnDestroy; + + /* r/o data added for ease of access and simplicity + * modifying it leads to unpredictable behavior */ + VBOXUHGSMI_BUFFER_TYPE_FLAGS fType; + uint32_t cbBuffer; + /** User custom data. */ + void *pvUserData; +} VBOXUHGSMI_BUFFER; + +#define VBoxUhgsmiBufferCreate(_pUhgsmi, _cbBuf, _fType, _ppBuf) ((_pUhgsmi)->pfnBufferCreate(_pUhgsmi, _cbBuf, _fType, _ppBuf)) +#define VBoxUhgsmiBufferSubmit(_pUhgsmi, _aBuffers, _cBuffers) ((_pUhgsmi)->pfnBufferSubmit(_pUhgsmi, _aBuffers, _cBuffers)) + +#define VBoxUhgsmiBufferLock(_pBuf, _offLock, _cbLock, _fFlags, _pvLock) ((_pBuf)->pfnLock(_pBuf, _offLock, _cbLock, _fFlags, _pvLock)) +#define VBoxUhgsmiBufferUnlock(_pBuf) ((_pBuf)->pfnUnlock(_pBuf)) +#define VBoxUhgsmiBufferDestroy(_pBuf) ((_pBuf)->pfnDestroy(_pBuf)) + +#endif /* !VBOX_INCLUDED_Graphics_VBoxUhgsmi_h */ + diff --git a/include/VBox/Graphics/VBoxVideo.h b/include/VBox/Graphics/VBoxVideo.h new file mode 100644 index 00000000..ca779315 --- /dev/null +++ b/include/VBox/Graphics/VBoxVideo.h @@ -0,0 +1,1490 @@ +/* $Id: VBoxVideo.h $ */ +/** @file + * VirtualBox Video interface. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideo_h +#define VBOX_INCLUDED_Graphics_VBoxVideo_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBoxVideoIPRT.h" + +/* this should be in sync with monitorCount in src/VBox/Main/xml/VirtualBox-settings-common.xsd */ +#define VBOX_VIDEO_MAX_SCREENS 64 + +/* + * The last 4096 bytes of the guest VRAM contains the generic info for all + * DualView chunks: sizes and offsets of chunks. This is filled by miniport. + * + * Last 4096 bytes of each chunk contain chunk specific data: framebuffer info, + * etc. This is used exclusively by the corresponding instance of a display driver. + * + * The VRAM layout: + * Last 4096 bytes - Adapter information area. + * 4096 bytes aligned miniport heap (value specified in the config rouded up). + * Slack - what left after dividing the VRAM. + * 4096 bytes aligned framebuffers: + * last 4096 bytes of each framebuffer is the display information area. + * + * The Virtual Graphics Adapter information in the guest VRAM is stored by the + * guest video driver using structures prepended by VBOXVIDEOINFOHDR. + * + * When the guest driver writes dword 0 to the VBE_DISPI_INDEX_VBOX_VIDEO + * the host starts to process the info. The first element at the start of + * the 4096 bytes region should be normally be a LINK that points to + * actual information chain. That way the guest driver can have some + * fixed layout of the information memory block and just rewrite + * the link to point to relevant memory chain. + * + * The processing stops at the END element. + * + * The host can access the memory only when the port IO is processed. + * All data that will be needed later must be copied from these 4096 bytes. + * But other VRAM can be used by host until the mode is disabled. + * + * The guest driver writes dword 0xffffffff to the VBE_DISPI_INDEX_VBOX_VIDEO + * to disable the mode. + * + * VBE_DISPI_INDEX_VBOX_VIDEO is used to read the configuration information + * from the host and issue commands to the host. + * + * The guest writes the VBE_DISPI_INDEX_VBOX_VIDEO index register, the the + * following operations with the VBE data register can be performed: + * + * Operation Result + * write 16 bit value NOP + * read 16 bit value count of monitors + * write 32 bit value sets the vbox command value and the command processed by the host + * read 32 bit value result of the last vbox command is returned + */ + +#define VBOX_VIDEO_PRIMARY_SCREEN 0 +#define VBOX_VIDEO_NO_SCREEN ~0 + +/** + * VBVA command header. + * + * @todo Where does this fit in? + */ +typedef struct VBVACMDHDR +{ + /** Coordinates of affected rectangle. */ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; +} VBVACMDHDR; +AssertCompileSize(VBVACMDHDR, 8); + +/** @name VBVA ring defines. + * + * The VBVA ring buffer is suitable for transferring large (< 2GB) amount of + * data. For example big bitmaps which do not fit to the buffer. + * + * Guest starts writing to the buffer by initializing a record entry in the + * aRecords queue. VBVA_F_RECORD_PARTIAL indicates that the record is being + * written. As data is written to the ring buffer, the guest increases off32End + * for the record. + * + * The host reads the aRecords on flushes and processes all completed records. + * When host encounters situation when only a partial record presents and + * cbRecord & ~VBVA_F_RECORD_PARTIAL >= VBVA_RING_BUFFER_SIZE - + * VBVA_RING_BUFFER_THRESHOLD, the host fetched all record data and updates + * off32Head. After that on each flush the host continues fetching the data + * until the record is completed. + * + */ +#define VBVA_RING_BUFFER_SIZE (_4M - _1K) +#define VBVA_RING_BUFFER_THRESHOLD (4 * _1K) + +#define VBVA_MAX_RECORDS (64) + +#define VBVA_F_MODE_ENABLED UINT32_C(0x00000001) +#define VBVA_F_MODE_VRDP UINT32_C(0x00000002) +#define VBVA_F_MODE_VRDP_RESET UINT32_C(0x00000004) +#define VBVA_F_MODE_VRDP_ORDER_MASK UINT32_C(0x00000008) + +#define VBVA_F_STATE_PROCESSING UINT32_C(0x00010000) + +#define VBVA_F_RECORD_PARTIAL UINT32_C(0x80000000) + +/** + * VBVA record. + */ +typedef struct VBVARECORD +{ + /** The length of the record. Changed by guest. */ + uint32_t cbRecord; +} VBVARECORD; +AssertCompileSize(VBVARECORD, 4); + +/* The size of the information. */ +/* + * The minimum HGSMI heap size is PAGE_SIZE (4096 bytes) and is a restriction of the + * runtime heapsimple API. Use minimum 2 pages here, because the info area also may + * contain other data (for example HGSMIHOSTFLAGS structure). + */ +#ifndef VBOX_XPDM_MINIPORT +# define VBVA_ADAPTER_INFORMATION_SIZE (64*_1K) +#else +#define VBVA_ADAPTER_INFORMATION_SIZE (16*_1K) +#define VBVA_DISPLAY_INFORMATION_SIZE (64*_1K) +#endif +#define VBVA_MIN_BUFFER_SIZE (64*_1K) + + +/* The value for port IO to let the adapter to interpret the adapter memory. */ +#define VBOX_VIDEO_DISABLE_ADAPTER_MEMORY 0xFFFFFFFF + +/* The value for port IO to let the adapter to interpret the adapter memory. */ +#define VBOX_VIDEO_INTERPRET_ADAPTER_MEMORY 0x00000000 + +/* The value for port IO to let the adapter to interpret the display memory. + * The display number is encoded in low 16 bits. + */ +#define VBOX_VIDEO_INTERPRET_DISPLAY_MEMORY_BASE 0x00010000 + + +/* The end of the information. */ +#define VBOX_VIDEO_INFO_TYPE_END 0 +/* Instructs the host to fetch the next VBOXVIDEOINFOHDR at the given offset of VRAM. */ +#define VBOX_VIDEO_INFO_TYPE_LINK 1 +/* Information about a display memory position. */ +#define VBOX_VIDEO_INFO_TYPE_DISPLAY 2 +/* Information about a screen. */ +#define VBOX_VIDEO_INFO_TYPE_SCREEN 3 +/* Information about host notifications for the driver. */ +#define VBOX_VIDEO_INFO_TYPE_HOST_EVENTS 4 +/* Information about non-volatile guest VRAM heap. */ +#define VBOX_VIDEO_INFO_TYPE_NV_HEAP 5 +/* VBVA enable/disable. */ +#define VBOX_VIDEO_INFO_TYPE_VBVA_STATUS 6 +/* VBVA flush. */ +#define VBOX_VIDEO_INFO_TYPE_VBVA_FLUSH 7 +/* Query configuration value. */ +#define VBOX_VIDEO_INFO_TYPE_QUERY_CONF32 8 + + +#pragma pack(1) +typedef struct VBOXVIDEOINFOHDR +{ + uint8_t u8Type; + uint8_t u8Reserved; + uint16_t u16Length; +} VBOXVIDEOINFOHDR; + + +typedef struct VBOXVIDEOINFOLINK +{ + /* Relative offset in VRAM */ + int32_t i32Offset; +} VBOXVIDEOINFOLINK; + + +/* Resides in adapter info memory. Describes a display VRAM chunk. */ +typedef struct VBOXVIDEOINFODISPLAY +{ + /* Index of the framebuffer assigned by guest. */ + uint32_t u32Index; + + /* Absolute offset in VRAM of the framebuffer to be displayed on the monitor. */ + uint32_t u32Offset; + + /* The size of the memory that can be used for the screen. */ + uint32_t u32FramebufferSize; + + /* The size of the memory that is used for the Display information. + * The information is at u32Offset + u32FramebufferSize + */ + uint32_t u32InformationSize; + +} VBOXVIDEOINFODISPLAY; + + +/* Resides in display info area, describes the current video mode. */ +#define VBOX_VIDEO_INFO_SCREEN_F_NONE 0x00 +#define VBOX_VIDEO_INFO_SCREEN_F_ACTIVE 0x01 + +typedef struct VBOXVIDEOINFOSCREEN +{ + /* Physical X origin relative to the primary screen. */ + int32_t xOrigin; + + /* Physical Y origin relative to the primary screen. */ + int32_t yOrigin; + + /* The scan line size in bytes. */ + uint32_t u32LineSize; + + /* Width of the screen. */ + uint16_t u16Width; + + /* Height of the screen. */ + uint16_t u16Height; + + /* Color depth. */ + uint8_t bitsPerPixel; + + /* VBOX_VIDEO_INFO_SCREEN_F_* */ + uint8_t u8Flags; +} VBOXVIDEOINFOSCREEN; + +/* The guest initializes the structure to 0. The positions of the structure in the + * display info area must not be changed, host will update the structure. Guest checks + * the events and modifies the structure as a response to host. + */ +#define VBOX_VIDEO_INFO_HOST_EVENTS_F_NONE 0x00000000 +#define VBOX_VIDEO_INFO_HOST_EVENTS_F_VRDP_RESET 0x00000080 + +typedef struct VBOXVIDEOINFOHOSTEVENTS +{ + /* Host events. */ + uint32_t fu32Events; +} VBOXVIDEOINFOHOSTEVENTS; + +/* Resides in adapter info memory. Describes the non-volatile VRAM heap. */ +typedef struct VBOXVIDEOINFONVHEAP +{ + /* Absolute offset in VRAM of the start of the heap. */ + uint32_t u32HeapOffset; + + /* The size of the heap. */ + uint32_t u32HeapSize; + +} VBOXVIDEOINFONVHEAP; + +/* Display information area. */ +typedef struct VBOXVIDEOINFOVBVASTATUS +{ + /* Absolute offset in VRAM of the start of the VBVA QUEUE. 0 to disable VBVA. */ + uint32_t u32QueueOffset; + + /* The size of the VBVA QUEUE. 0 to disable VBVA. */ + uint32_t u32QueueSize; + +} VBOXVIDEOINFOVBVASTATUS; + +typedef struct VBOXVIDEOINFOVBVAFLUSH +{ + uint32_t u32DataStart; + + uint32_t u32DataEnd; + +} VBOXVIDEOINFOVBVAFLUSH; + +#define VBOX_VIDEO_QCI32_MONITOR_COUNT 0 +#define VBOX_VIDEO_QCI32_OFFSCREEN_HEAP_SIZE 1 + +typedef struct VBOXVIDEOINFOQUERYCONF32 +{ + uint32_t u32Index; + + uint32_t u32Value; + +} VBOXVIDEOINFOQUERYCONF32; +#pragma pack() + +#ifdef VBOX_WITH_VIDEOHWACCEL +#pragma pack(1) + +#define VBOXVHWA_VERSION_MAJ 0 +#define VBOXVHWA_VERSION_MIN 0 +#define VBOXVHWA_VERSION_BLD 6 +#define VBOXVHWA_VERSION_RSV 0 + +typedef enum +{ + VBOXVHWACMD_TYPE_SURF_CANCREATE = 1, + VBOXVHWACMD_TYPE_SURF_CREATE, + VBOXVHWACMD_TYPE_SURF_DESTROY, + VBOXVHWACMD_TYPE_SURF_LOCK, + VBOXVHWACMD_TYPE_SURF_UNLOCK, + VBOXVHWACMD_TYPE_SURF_BLT, + VBOXVHWACMD_TYPE_SURF_FLIP, + VBOXVHWACMD_TYPE_SURF_OVERLAY_UPDATE, + VBOXVHWACMD_TYPE_SURF_OVERLAY_SETPOSITION, + VBOXVHWACMD_TYPE_SURF_COLORKEY_SET, + VBOXVHWACMD_TYPE_QUERY_INFO1, + VBOXVHWACMD_TYPE_QUERY_INFO2, + VBOXVHWACMD_TYPE_ENABLE, + VBOXVHWACMD_TYPE_DISABLE, + VBOXVHWACMD_TYPE_HH_CONSTRUCT, + VBOXVHWACMD_TYPE_HH_RESET +#ifdef VBOX_WITH_WDDM + , VBOXVHWACMD_TYPE_SURF_GETINFO + , VBOXVHWACMD_TYPE_SURF_COLORFILL +#endif + , VBOXVHWACMD_TYPE_HH_DISABLE + , VBOXVHWACMD_TYPE_HH_ENABLE + , VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEBEGIN + , VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEEND + , VBOXVHWACMD_TYPE_HH_SAVESTATE_SAVEPERFORM + , VBOXVHWACMD_TYPE_HH_SAVESTATE_LOADPERFORM +} VBOXVHWACMD_TYPE; + +/** The command processing was asynch, set by the host to indicate asynch + * command completion. Must not be cleared once set, the command completion is + * performed by issuing a host->guest completion command while keeping this + * flag unchanged */ +#define VBOXVHWACMD_FLAG_HG_ASYNCH UINT32_C(0x00010000) +/** asynch completion is performed by issuing the event */ +#define VBOXVHWACMD_FLAG_GH_ASYNCH_EVENT UINT32_C(0x00000001) +/** issue interrupt on asynch completion */ +#define VBOXVHWACMD_FLAG_GH_ASYNCH_IRQ UINT32_C(0x00000002) +/** Guest does not do any op on completion of this command, the host may copy + * the command and indicate that it does not need the command anymore + * by setting the VBOXVHWACMD_FLAG_HG_ASYNCH_RETURNED flag */ +#define VBOXVHWACMD_FLAG_GH_ASYNCH_NOCOMPLETION UINT32_C(0x00000004) +/** the host has copied the VBOXVHWACMD_FLAG_GH_ASYNCH_NOCOMPLETION command and returned it to the guest */ +#define VBOXVHWACMD_FLAG_HG_ASYNCH_RETURNED UINT32_C(0x00020000) +/** this is the host->host cmd, i.e. a configuration command posted by the host to the framebuffer */ +#define VBOXVHWACMD_FLAG_HH_CMD UINT32_C(0x10000000) + +typedef struct VBOXVHWACMD +{ + VBOXVHWACMD_TYPE enmCmd; /**< command type */ + volatile int32_t rc; /**< command result */ + int32_t iDisplay; /**< display index */ + volatile int32_t Flags; /**< ORed VBOXVHWACMD_FLAG_xxx values */ + uint64_t GuestVBVAReserved1; /**< field internally used by the guest VBVA cmd handling, must NOT be modified by clients */ + uint64_t GuestVBVAReserved2; /**< field internally used by the guest VBVA cmd handling, must NOT be modified by clients */ + volatile uint32_t cRefs; + int32_t Reserved; + union + { + struct VBOXVHWACMD *pNext; + uint32_t offNext; + uint64_t Data; /**< the body is 64-bit aligned */ + } u; + char body[1]; +} VBOXVHWACMD; + +#define VBOXVHWACMD_HEADSIZE() (RT_OFFSETOF(VBOXVHWACMD, body)) +#define VBOXVHWACMD_SIZE_FROMBODYSIZE(a_cbBody) (VBOXVHWACMD_HEADSIZE() + (a_cbBody)) +#define VBOXVHWACMD_SIZE(a_tTypeCmd) (VBOXVHWACMD_SIZE_FROMBODYSIZE(sizeof(a_tTypeCmd))) +typedef unsigned int VBOXVHWACMD_LENGTH; +typedef uint64_t VBOXVHWA_SURFHANDLE; +#define VBOXVHWA_SURFHANDLE_INVALID UINT64_C(0) +#define VBOXVHWACMD_BODY(a_pHdr, a_TypeBody) ( (a_TypeBody RT_UNTRUSTED_VOLATILE_HSTGST *)&(a_pHdr)->body[0] ) +#if !defined(IN_GUEST) && defined(IN_RING3) +# define VBOXVHWACMD_BODY_HOST_HEAP(a_pHdr, a_TypeBody) ( (a_TypeBody *)&(a_pHdr)->body[0] ) +#endif +#define VBOXVHWACMD_HEAD(a_pBody)\ + ( (VBOXVHWACMD RT_UNTRUSTED_VOLATILE_HSTGST *)((uint8_t *)(a_pBody) - RT_OFFSETOF(VBOXVHWACMD, body))) + +typedef struct VBOXVHWA_RECTL +{ + int32_t left; + int32_t top; + int32_t right; + int32_t bottom; +} VBOXVHWA_RECTL; + +typedef struct VBOXVHWA_COLORKEY +{ + uint32_t low; + uint32_t high; +} VBOXVHWA_COLORKEY; + +typedef struct VBOXVHWA_PIXELFORMAT +{ + uint32_t flags; + uint32_t fourCC; + union + { + uint32_t rgbBitCount; + uint32_t yuvBitCount; + } c; + + union + { + uint32_t rgbRBitMask; + uint32_t yuvYBitMask; + } m1; + + union + { + uint32_t rgbGBitMask; + uint32_t yuvUBitMask; + } m2; + + union + { + uint32_t rgbBBitMask; + uint32_t yuvVBitMask; + } m3; + + union + { + uint32_t rgbABitMask; + } m4; + + uint32_t Reserved; +} VBOXVHWA_PIXELFORMAT; + +typedef struct VBOXVHWA_SURFACEDESC +{ + uint32_t flags; + uint32_t height; + uint32_t width; + uint32_t pitch; + uint32_t sizeX; + uint32_t sizeY; + uint32_t cBackBuffers; + uint32_t Reserved; + VBOXVHWA_COLORKEY DstOverlayCK; + VBOXVHWA_COLORKEY DstBltCK; + VBOXVHWA_COLORKEY SrcOverlayCK; + VBOXVHWA_COLORKEY SrcBltCK; + VBOXVHWA_PIXELFORMAT PixelFormat; + uint32_t surfCaps; + uint32_t Reserved2; + VBOXVHWA_SURFHANDLE hSurf; + uint64_t offSurface; +} VBOXVHWA_SURFACEDESC; + +typedef struct VBOXVHWA_BLTFX +{ + uint32_t flags; + uint32_t rop; + uint32_t rotationOp; + uint32_t rotation; + uint32_t fillColor; + uint32_t Reserved; + VBOXVHWA_COLORKEY DstCK; + VBOXVHWA_COLORKEY SrcCK; +} VBOXVHWA_BLTFX; + +typedef struct VBOXVHWA_OVERLAYFX +{ + uint32_t flags; + uint32_t Reserved1; + uint32_t fxFlags; + uint32_t Reserved2; + VBOXVHWA_COLORKEY DstCK; + VBOXVHWA_COLORKEY SrcCK; +} VBOXVHWA_OVERLAYFX; + +#define VBOXVHWA_CAPS_BLT 0x00000040 +#define VBOXVHWA_CAPS_BLTCOLORFILL 0x04000000 +#define VBOXVHWA_CAPS_BLTFOURCC 0x00000100 +#define VBOXVHWA_CAPS_BLTSTRETCH 0x00000200 +#define VBOXVHWA_CAPS_BLTQUEUE 0x00000080 + +#define VBOXVHWA_CAPS_OVERLAY 0x00000800 +#define VBOXVHWA_CAPS_OVERLAYFOURCC 0x00002000 +#define VBOXVHWA_CAPS_OVERLAYSTRETCH 0x00004000 +#define VBOXVHWA_CAPS_OVERLAYCANTCLIP 0x00001000 + +#define VBOXVHWA_CAPS_COLORKEY 0x00400000 +#define VBOXVHWA_CAPS_COLORKEYHWASSIST 0x01000000 + +#define VBOXVHWA_SCAPS_BACKBUFFER 0x00000004 +#define VBOXVHWA_SCAPS_COMPLEX 0x00000008 +#define VBOXVHWA_SCAPS_FLIP 0x00000010 +#define VBOXVHWA_SCAPS_FRONTBUFFER 0x00000020 +#define VBOXVHWA_SCAPS_OFFSCREENPLAIN 0x00000040 +#define VBOXVHWA_SCAPS_OVERLAY 0x00000080 +#define VBOXVHWA_SCAPS_PRIMARYSURFACE 0x00000200 +#define VBOXVHWA_SCAPS_SYSTEMMEMORY 0x00000800 +#define VBOXVHWA_SCAPS_VIDEOMEMORY 0x00004000 +#define VBOXVHWA_SCAPS_VISIBLE 0x00008000 +#define VBOXVHWA_SCAPS_LOCALVIDMEM 0x10000000 + +#define VBOXVHWA_PF_PALETTEINDEXED8 0x00000020 +#define VBOXVHWA_PF_RGB 0x00000040 +#define VBOXVHWA_PF_RGBTOYUV 0x00000100 +#define VBOXVHWA_PF_YUV 0x00000200 +#define VBOXVHWA_PF_FOURCC 0x00000004 + +#define VBOXVHWA_LOCK_DISCARDCONTENTS 0x00002000 + +#define VBOXVHWA_CFG_ENABLED 0x00000001 + +#define VBOXVHWA_SD_BACKBUFFERCOUNT 0x00000020 +#define VBOXVHWA_SD_CAPS 0x00000001 +#define VBOXVHWA_SD_CKDESTBLT 0x00004000 +#define VBOXVHWA_SD_CKDESTOVERLAY 0x00002000 +#define VBOXVHWA_SD_CKSRCBLT 0x00010000 +#define VBOXVHWA_SD_CKSRCOVERLAY 0x00008000 +#define VBOXVHWA_SD_HEIGHT 0x00000002 +#define VBOXVHWA_SD_PITCH 0x00000008 +#define VBOXVHWA_SD_PIXELFORMAT 0x00001000 +/*#define VBOXVHWA_SD_REFRESHRATE 0x00040000*/ +#define VBOXVHWA_SD_WIDTH 0x00000004 + +#define VBOXVHWA_CKEYCAPS_DESTBLT 0x00000001 +#define VBOXVHWA_CKEYCAPS_DESTBLTCLRSPACE 0x00000002 +#define VBOXVHWA_CKEYCAPS_DESTBLTCLRSPACEYUV 0x00000004 +#define VBOXVHWA_CKEYCAPS_DESTBLTYUV 0x00000008 +#define VBOXVHWA_CKEYCAPS_DESTOVERLAY 0x00000010 +#define VBOXVHWA_CKEYCAPS_DESTOVERLAYCLRSPACE 0x00000020 +#define VBOXVHWA_CKEYCAPS_DESTOVERLAYCLRSPACEYUV 0x00000040 +#define VBOXVHWA_CKEYCAPS_DESTOVERLAYONEACTIVE 0x00000080 +#define VBOXVHWA_CKEYCAPS_DESTOVERLAYYUV 0x00000100 +#define VBOXVHWA_CKEYCAPS_SRCBLT 0x00000200 +#define VBOXVHWA_CKEYCAPS_SRCBLTCLRSPACE 0x00000400 +#define VBOXVHWA_CKEYCAPS_SRCBLTCLRSPACEYUV 0x00000800 +#define VBOXVHWA_CKEYCAPS_SRCBLTYUV 0x00001000 +#define VBOXVHWA_CKEYCAPS_SRCOVERLAY 0x00002000 +#define VBOXVHWA_CKEYCAPS_SRCOVERLAYCLRSPACE 0x00004000 +#define VBOXVHWA_CKEYCAPS_SRCOVERLAYCLRSPACEYUV 0x00008000 +#define VBOXVHWA_CKEYCAPS_SRCOVERLAYONEACTIVE 0x00010000 +#define VBOXVHWA_CKEYCAPS_SRCOVERLAYYUV 0x00020000 +#define VBOXVHWA_CKEYCAPS_NOCOSTOVERLAY 0x00040000 + +#define VBOXVHWA_BLT_COLORFILL 0x00000400 +#define VBOXVHWA_BLT_DDFX 0x00000800 +#define VBOXVHWA_BLT_EXTENDED_FLAGS 0x40000000 +#define VBOXVHWA_BLT_EXTENDED_LINEAR_CONTENT 0x00000004 +#define VBOXVHWA_BLT_EXTENDED_PRESENTATION_STRETCHFACTOR 0x00000010 +#define VBOXVHWA_BLT_KEYDESTOVERRIDE 0x00004000 +#define VBOXVHWA_BLT_KEYSRCOVERRIDE 0x00010000 +#define VBOXVHWA_BLT_LAST_PRESENTATION 0x20000000 +#define VBOXVHWA_BLT_PRESENTATION 0x10000000 +#define VBOXVHWA_BLT_ROP 0x00020000 + + +#define VBOXVHWA_OVER_DDFX 0x00080000 +#define VBOXVHWA_OVER_HIDE 0x00000200 +#define VBOXVHWA_OVER_KEYDEST 0x00000400 +#define VBOXVHWA_OVER_KEYDESTOVERRIDE 0x00000800 +#define VBOXVHWA_OVER_KEYSRC 0x00001000 +#define VBOXVHWA_OVER_KEYSRCOVERRIDE 0x00002000 +#define VBOXVHWA_OVER_SHOW 0x00004000 + +#define VBOXVHWA_CKEY_COLORSPACE 0x00000001 +#define VBOXVHWA_CKEY_DESTBLT 0x00000002 +#define VBOXVHWA_CKEY_DESTOVERLAY 0x00000004 +#define VBOXVHWA_CKEY_SRCBLT 0x00000008 +#define VBOXVHWA_CKEY_SRCOVERLAY 0x00000010 + +#define VBOXVHWA_BLT_ARITHSTRETCHY 0x00000001 +#define VBOXVHWA_BLT_MIRRORLEFTRIGHT 0x00000002 +#define VBOXVHWA_BLT_MIRRORUPDOWN 0x00000004 + +#define VBOXVHWA_OVERFX_ARITHSTRETCHY 0x00000001 +#define VBOXVHWA_OVERFX_MIRRORLEFTRIGHT 0x00000002 +#define VBOXVHWA_OVERFX_MIRRORUPDOWN 0x00000004 + +#define VBOXVHWA_CAPS2_CANRENDERWINDOWED 0x00080000 +#define VBOXVHWA_CAPS2_WIDESURFACES 0x00001000 +#define VBOXVHWA_CAPS2_COPYFOURCC 0x00008000 +/*#define VBOXVHWA_CAPS2_FLIPINTERVAL 0x00200000*/ +/*#define VBOXVHWA_CAPS2_FLIPNOVSYNC 0x00400000*/ + + +#define VBOXVHWA_OFFSET64_VOID (UINT64_MAX) + +typedef struct VBOXVHWA_VERSION +{ + uint32_t maj; + uint32_t min; + uint32_t bld; + uint32_t reserved; +} VBOXVHWA_VERSION; + +#define VBOXVHWA_VERSION_INIT(_pv) do { \ + (_pv)->maj = VBOXVHWA_VERSION_MAJ; \ + (_pv)->min = VBOXVHWA_VERSION_MIN; \ + (_pv)->bld = VBOXVHWA_VERSION_BLD; \ + (_pv)->reserved = VBOXVHWA_VERSION_RSV; \ + } while(0) + +typedef struct VBOXVHWACMD_QUERYINFO1 +{ + union + { + struct + { + VBOXVHWA_VERSION guestVersion; + } in; + + struct + { + uint32_t cfgFlags; + uint32_t caps; + + uint32_t caps2; + uint32_t colorKeyCaps; + + uint32_t stretchCaps; + uint32_t surfaceCaps; + + uint32_t numOverlays; + uint32_t curOverlays; + + uint32_t numFourCC; + uint32_t reserved; + } out; + } u; +} VBOXVHWACMD_QUERYINFO1; + +typedef struct VBOXVHWACMD_QUERYINFO2 +{ + uint32_t numFourCC; + uint32_t FourCC[1]; +} VBOXVHWACMD_QUERYINFO2; + +#define VBOXVHWAINFO2_SIZE(_cFourCC) RT_UOFFSETOF_DYN(VBOXVHWACMD_QUERYINFO2, FourCC[_cFourCC]) + +typedef struct VBOXVHWACMD_SURF_CANCREATE +{ + VBOXVHWA_SURFACEDESC SurfInfo; + union + { + struct + { + uint32_t bIsDifferentPixelFormat; + uint32_t Reserved; + } in; + + struct + { + int32_t ErrInfo; + } out; + } u; +} VBOXVHWACMD_SURF_CANCREATE; + +typedef struct VBOXVHWACMD_SURF_CREATE +{ + VBOXVHWA_SURFACEDESC SurfInfo; +} VBOXVHWACMD_SURF_CREATE; + +#ifdef VBOX_WITH_WDDM +typedef struct VBOXVHWACMD_SURF_GETINFO +{ + VBOXVHWA_SURFACEDESC SurfInfo; +} VBOXVHWACMD_SURF_GETINFO; +#endif + +typedef struct VBOXVHWACMD_SURF_DESTROY +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hSurf; + } in; + } u; +} VBOXVHWACMD_SURF_DESTROY; + +typedef struct VBOXVHWACMD_SURF_LOCK +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hSurf; + uint64_t offSurface; + uint32_t flags; + uint32_t rectValid; + VBOXVHWA_RECTL rect; + } in; + } u; +} VBOXVHWACMD_SURF_LOCK; + +typedef struct VBOXVHWACMD_SURF_UNLOCK +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hSurf; + uint32_t xUpdatedMemValid; + uint32_t reserved; + VBOXVHWA_RECTL xUpdatedMemRect; + } in; + } u; +} VBOXVHWACMD_SURF_UNLOCK; + +typedef struct VBOXVHWACMD_SURF_BLT +{ + uint64_t DstGuestSurfInfo; + uint64_t SrcGuestSurfInfo; + union + { + struct + { + VBOXVHWA_SURFHANDLE hDstSurf; + uint64_t offDstSurface; + VBOXVHWA_RECTL dstRect; + VBOXVHWA_SURFHANDLE hSrcSurf; + uint64_t offSrcSurface; + VBOXVHWA_RECTL srcRect; + uint32_t flags; + uint32_t xUpdatedSrcMemValid; + VBOXVHWA_BLTFX desc; + VBOXVHWA_RECTL xUpdatedSrcMemRect; + } in; + } u; +} VBOXVHWACMD_SURF_BLT; + +#ifdef VBOX_WITH_WDDM +typedef struct VBOXVHWACMD_SURF_COLORFILL +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hSurf; + uint64_t offSurface; + uint32_t u32Reserved; + uint32_t cRects; + VBOXVHWA_RECTL aRects[1]; + } in; + } u; +} VBOXVHWACMD_SURF_COLORFILL; +#endif + +typedef struct VBOXVHWACMD_SURF_FLIP +{ + uint64_t TargGuestSurfInfo; + uint64_t CurrGuestSurfInfo; + union + { + struct + { + VBOXVHWA_SURFHANDLE hTargSurf; + uint64_t offTargSurface; + VBOXVHWA_SURFHANDLE hCurrSurf; + uint64_t offCurrSurface; + uint32_t flags; + uint32_t xUpdatedTargMemValid; + VBOXVHWA_RECTL xUpdatedTargMemRect; + } in; + } u; +} VBOXVHWACMD_SURF_FLIP; + +typedef struct VBOXVHWACMD_SURF_COLORKEY_SET +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hSurf; + uint64_t offSurface; + VBOXVHWA_COLORKEY CKey; + uint32_t flags; + uint32_t reserved; + } in; + } u; +} VBOXVHWACMD_SURF_COLORKEY_SET; + +#define VBOXVHWACMD_SURF_OVERLAY_UPDATE_F_SRCMEMRECT 0x00000001 +#define VBOXVHWACMD_SURF_OVERLAY_UPDATE_F_DSTMEMRECT 0x00000002 + +typedef struct VBOXVHWACMD_SURF_OVERLAY_UPDATE +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hDstSurf; + uint64_t offDstSurface; + VBOXVHWA_RECTL dstRect; + VBOXVHWA_SURFHANDLE hSrcSurf; + uint64_t offSrcSurface; + VBOXVHWA_RECTL srcRect; + uint32_t flags; + uint32_t xFlags; + VBOXVHWA_OVERLAYFX desc; + VBOXVHWA_RECTL xUpdatedSrcMemRect; + VBOXVHWA_RECTL xUpdatedDstMemRect; + } in; + } u; +}VBOXVHWACMD_SURF_OVERLAY_UPDATE; + +typedef struct VBOXVHWACMD_SURF_OVERLAY_SETPOSITION +{ + union + { + struct + { + VBOXVHWA_SURFHANDLE hDstSurf; + uint64_t offDstSurface; + VBOXVHWA_SURFHANDLE hSrcSurf; + uint64_t offSrcSurface; + uint32_t xPos; + uint32_t yPos; + uint32_t flags; + uint32_t reserved; + } in; + } u; +} VBOXVHWACMD_SURF_OVERLAY_SETPOSITION; + +typedef struct VBOXVHWACMD_HH_CONSTRUCT +{ + void *pVM; + /* VRAM info for the backend to be able to properly translate VRAM offsets */ + void *pvVRAM; + uint32_t cbVRAM; +} VBOXVHWACMD_HH_CONSTRUCT; + +typedef struct VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM +{ + struct SSMHANDLE * pSSM; +} VBOXVHWACMD_HH_SAVESTATE_SAVEPERFORM; + +typedef struct VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM +{ + struct SSMHANDLE * pSSM; +} VBOXVHWACMD_HH_SAVESTATE_LOADPERFORM; + +typedef DECLCALLBACKTYPE(void, FNVBOXVHWA_HH_CALLBACK,(void *)); +typedef FNVBOXVHWA_HH_CALLBACK *PFNVBOXVHWA_HH_CALLBACK; + +#define VBOXVHWA_HH_CALLBACK_SET(_pCmd, _pfn, _parg) \ + do { \ + (_pCmd)->GuestVBVAReserved1 = (uint64_t)(uintptr_t)(_pfn); \ + (_pCmd)->GuestVBVAReserved2 = (uint64_t)(uintptr_t)(_parg); \ + }while(0) + +#define VBOXVHWA_HH_CALLBACK_GET(_pCmd) ((PFNVBOXVHWA_HH_CALLBACK)(_pCmd)->GuestVBVAReserved1) +#define VBOXVHWA_HH_CALLBACK_GET_ARG(_pCmd) ((void*)(_pCmd)->GuestVBVAReserved2) + +#pragma pack() +#endif /* #ifdef VBOX_WITH_VIDEOHWACCEL */ + +/* All structures are without alignment. */ +#pragma pack(1) + +typedef struct VBVAHOSTFLAGS +{ + uint32_t u32HostEvents; + uint32_t u32SupportedOrders; +} VBVAHOSTFLAGS; + +typedef struct VBVABUFFER +{ + VBVAHOSTFLAGS hostFlags; + + /* The offset where the data start in the buffer. */ + uint32_t off32Data; + /* The offset where next data must be placed in the buffer. */ + uint32_t off32Free; + + /* The queue of record descriptions. */ + VBVARECORD aRecords[VBVA_MAX_RECORDS]; + uint32_t indexRecordFirst; + uint32_t indexRecordFree; + + /* Space to leave free in the buffer when large partial records are transferred. */ + uint32_t cbPartialWriteThreshold; + + uint32_t cbData; + uint8_t au8Data[1]; /* variable size for the rest of the VBVABUFFER area in VRAM. */ +} VBVABUFFER; + +#define VBVA_MAX_RECORD_SIZE (128*_1M) + +/* guest->host commands */ +#define VBVA_QUERY_CONF32 1 +#define VBVA_SET_CONF32 2 +#define VBVA_INFO_VIEW 3 +#define VBVA_INFO_HEAP 4 +#define VBVA_FLUSH 5 +#define VBVA_INFO_SCREEN 6 +/** Enables or disables VBVA. Enabling VBVA without disabling it before + * causes a complete screen update. */ +#define VBVA_ENABLE 7 +#define VBVA_MOUSE_POINTER_SHAPE 8 +#ifdef VBOX_WITH_VIDEOHWACCEL +# define VBVA_VHWA_CMD 9 +#endif /* # ifdef VBOX_WITH_VIDEOHWACCEL */ +#ifdef VBOX_WITH_VDMA +# define VBVA_VDMA_CTL 10 /* setup G<->H DMA channel info */ +# define VBVA_VDMA_CMD 11 /* G->H DMA command */ +#endif +#define VBVA_INFO_CAPS 12 /* informs host about HGSMI caps. see VBVACAPS below */ +#define VBVA_SCANLINE_CFG 13 /* configures scanline, see VBVASCANLINECFG below */ +#define VBVA_SCANLINE_INFO 14 /* requests scanline info, see VBVASCANLINEINFO below */ +#define VBVA_CMDVBVA_SUBMIT 16 /* inform host about VBVA Command submission */ +#define VBVA_CMDVBVA_FLUSH 17 /* inform host about VBVA Command submission */ +#define VBVA_CMDVBVA_CTL 18 /* G->H DMA command */ +#define VBVA_QUERY_MODE_HINTS 19 /* Query most recent mode hints sent. */ +/** Report the guest virtual desktop position and size for mapping host and + * guest pointer positions. */ +#define VBVA_REPORT_INPUT_MAPPING 20 +/** Report the guest cursor position and query the host position. */ +#define VBVA_CURSOR_POSITION 21 + +/* host->guest commands */ +#define VBVAHG_EVENT 1 +#define VBVAHG_DISPLAY_CUSTOM 2 +#ifdef VBOX_WITH_VDMA +#define VBVAHG_SHGSMI_COMPLETION 3 +#endif + +#ifdef VBOX_WITH_VIDEOHWACCEL +#define VBVAHG_DCUSTOM_VHWA_CMDCOMPLETE 1 +#pragma pack(1) +typedef struct VBVAHOSTCMDVHWACMDCOMPLETE +{ + uint32_t offCmd; +}VBVAHOSTCMDVHWACMDCOMPLETE; +#pragma pack() +#endif /* # ifdef VBOX_WITH_VIDEOHWACCEL */ + +#pragma pack(1) +typedef enum +{ + VBVAHOSTCMD_OP_EVENT = 1, + VBVAHOSTCMD_OP_CUSTOM +}VBVAHOSTCMD_OP_TYPE; + +typedef struct VBVAHOSTCMDEVENT +{ + uint64_t pEvent; +}VBVAHOSTCMDEVENT; + + +typedef struct VBVAHOSTCMD +{ + /* destination ID if >=0 specifies display index, otherwize the command is directed to the miniport */ + int32_t iDstID; + int32_t customOpCode; + union + { + struct VBVAHOSTCMD *pNext; + uint32_t offNext; + uint64_t Data; /* the body is 64-bit aligned */ + } u; + char body[1]; +} VBVAHOSTCMD; + +#define VBVAHOSTCMD_SIZE(a_cb) (sizeof(VBVAHOSTCMD) + (a_cb)) +#define VBVAHOSTCMD_BODY(a_pCmd, a_TypeBody) ((a_TypeBody RT_UNTRUSTED_VOLATILE_HSTGST *)&(a_pCmd)->body[0]) +#define VBVAHOSTCMD_HDR(a_pBody) \ + ( (VBVAHOSTCMD RT_UNTRUSTED_VOLATILE_HSTGST *)( (uint8_t *)(a_pBody) - RT_OFFSETOF(VBVAHOSTCMD, body)) ) +#define VBVAHOSTCMD_HDRSIZE (RT_OFFSETOF(VBVAHOSTCMD, body)) + +#pragma pack() + +/* VBVACONF32::u32Index */ +#define VBOX_VBVA_CONF32_MONITOR_COUNT 0 +#define VBOX_VBVA_CONF32_HOST_HEAP_SIZE 1 +/** Returns VINF_SUCCESS if the host can report mode hints via VBVA. + * Set value to VERR_NOT_SUPPORTED before calling. */ +#define VBOX_VBVA_CONF32_MODE_HINT_REPORTING 2 +/** Returns VINF_SUCCESS if the host can report guest cursor enabled status via + * VBVA. Set value to VERR_NOT_SUPPORTED before calling. */ +#define VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING 3 +/** Returns the currently available host cursor capabilities. Available if + * VBVACONF32::VBOX_VBVA_CONF32_GUEST_CURSOR_REPORTING returns success. + * @see VMMDevReqMouseStatus::mouseFeatures. */ +#define VBOX_VBVA_CONF32_CURSOR_CAPABILITIES 4 +/** Returns the supported flags in VBVAINFOSCREEN::u8Flags. */ +#define VBOX_VBVA_CONF32_SCREEN_FLAGS 5 +/** Returns the max size of VBVA record. */ +#define VBOX_VBVA_CONF32_MAX_RECORD_SIZE 6 + +typedef struct VBVACONF32 +{ + uint32_t u32Index; + uint32_t u32Value; +} VBVACONF32; + +/** Reserved for historical reasons. */ +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED0 RT_BIT(0) +/** Guest cursor capability: can the host show a hardware cursor at the host + * pointer location? */ +#define VBOX_VBVA_CURSOR_CAPABILITY_HARDWARE RT_BIT(1) +/** Reserved for historical reasons. */ +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED2 RT_BIT(2) +/** Reserved for historical reasons. Must always be unset. */ +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED3 RT_BIT(3) +/** Reserved for historical reasons. */ +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED4 RT_BIT(4) +/** Reserved for historical reasons. */ +#define VBOX_VBVA_CURSOR_CAPABILITY_RESERVED5 RT_BIT(5) + +typedef struct VBVAINFOVIEW +{ + /* Index of the screen, assigned by the guest. */ + uint32_t u32ViewIndex; + + /* The screen offset in VRAM, the framebuffer starts here. */ + uint32_t u32ViewOffset; + + /* The size of the VRAM memory that can be used for the view. */ + uint32_t u32ViewSize; + + /* The recommended maximum size of the VRAM memory for the screen. */ + uint32_t u32MaxScreenSize; +} VBVAINFOVIEW; + +typedef struct VBVAINFOHEAP +{ + /* Absolute offset in VRAM of the start of the heap. */ + uint32_t u32HeapOffset; + + /* The size of the heap. */ + uint32_t u32HeapSize; + +} VBVAINFOHEAP; + +typedef struct VBVAFLUSH +{ + uint32_t u32Reserved; + +} VBVAFLUSH; + +typedef struct VBVACMDVBVASUBMIT +{ + uint32_t u32Reserved; +} VBVACMDVBVASUBMIT; + +/* flush is requested because due to guest command buffer overflow */ +#define VBVACMDVBVAFLUSH_F_GUEST_BUFFER_OVERFLOW 1 + +typedef struct VBVACMDVBVAFLUSH +{ + uint32_t u32Flags; +} VBVACMDVBVAFLUSH; + + +/* VBVAINFOSCREEN::u8Flags */ +#define VBVA_SCREEN_F_NONE 0x0000 +#define VBVA_SCREEN_F_ACTIVE 0x0001 +/** The virtual monitor has been disabled by the guest and should be removed + * by the host and ignored for purposes of pointer position calculation. */ +#define VBVA_SCREEN_F_DISABLED 0x0002 +/** The virtual monitor has been blanked by the guest and should be blacked + * out by the host using width, height, etc values from the VBVAINFOSCREEN request. */ +#define VBVA_SCREEN_F_BLANK 0x0004 +/** The virtual monitor has been blanked by the guest and should be blacked + * out by the host using the previous mode values for width. height, etc. */ +#define VBVA_SCREEN_F_BLANK2 0x0008 + +typedef struct VBVAINFOSCREEN +{ + /* Which view contains the screen. */ + uint32_t u32ViewIndex; + + /* Physical X origin relative to the primary screen. */ + int32_t i32OriginX; + + /* Physical Y origin relative to the primary screen. */ + int32_t i32OriginY; + + /* Offset of visible framebuffer relative to the framebuffer start. */ + uint32_t u32StartOffset; + + /* The scan line size in bytes. */ + uint32_t u32LineSize; + + /* Width of the screen. */ + uint32_t u32Width; + + /* Height of the screen. */ + uint32_t u32Height; + + /* Color depth. */ + uint16_t u16BitsPerPixel; + + /* VBVA_SCREEN_F_* */ + uint16_t u16Flags; +} VBVAINFOSCREEN; + + +/* VBVAENABLE::u32Flags */ +#define VBVA_F_NONE 0x00000000 +#define VBVA_F_ENABLE 0x00000001 +#define VBVA_F_DISABLE 0x00000002 +/* extended VBVA to be used with WDDM */ +#define VBVA_F_EXTENDED 0x00000004 +/* vbva offset is absolute VRAM offset */ +#define VBVA_F_ABSOFFSET 0x00000008 + +typedef struct VBVAENABLE +{ + uint32_t u32Flags; + uint32_t u32Offset; + int32_t i32Result; +} VBVAENABLE; + +typedef struct VBVAENABLE_EX +{ + VBVAENABLE Base; + uint32_t u32ScreenId; +} VBVAENABLE_EX; + + +typedef struct VBVAMOUSEPOINTERSHAPE +{ + /* The host result. */ + int32_t i32Result; + + /* VBOX_MOUSE_POINTER_* bit flags. */ + uint32_t fu32Flags; + + /* X coordinate of the hot spot. */ + uint32_t u32HotX; + + /* Y coordinate of the hot spot. */ + uint32_t u32HotY; + + /* Width of the pointer in pixels. */ + uint32_t u32Width; + + /* Height of the pointer in scanlines. */ + uint32_t u32Height; + + /* Pointer data. + * + **** + * The data consists of 1 bpp AND mask followed by 32 bpp XOR (color) mask. + * + * For pointers without alpha channel the XOR mask pixels are 32 bit values: (lsb)BGR0(msb). + * For pointers with alpha channel the XOR mask consists of (lsb)BGRA(msb) 32 bit values. + * + * Guest driver must create the AND mask for pointers with alpha channel, so if host does not + * support alpha, the pointer could be displayed as a normal color pointer. The AND mask can + * be constructed from alpha values. For example alpha value >= 0xf0 means bit 0 in the AND mask. + * + * The AND mask is 1 bpp bitmap with byte aligned scanlines. Size of AND mask, + * therefore, is cbAnd = (width + 7) / 8 * height. The padding bits at the + * end of any scanline are undefined. + * + * The XOR mask follows the AND mask on the next 4 bytes aligned offset: + * uint8_t *pXor = pAnd + (cbAnd + 3) & ~3 + * Bytes in the gap between the AND and the XOR mask are undefined. + * XOR mask scanlines have no gap between them and size of XOR mask is: + * cXor = width * 4 * height. + **** + * + * Preallocate 4 bytes for accessing actual data as p->au8Data. + */ + uint8_t au8Data[4]; + +} VBVAMOUSEPOINTERSHAPE; + +/** @name VBVAMOUSEPOINTERSHAPE::fu32Flags + * @note The VBOX_MOUSE_POINTER_* flags are used in the guest video driver, + * values must be <= 0x8000 and must not be changed. (try make more sense + * of this, please). + * @{ + */ +/** pointer is visible */ +#define VBOX_MOUSE_POINTER_VISIBLE (0x0001) +/** pointer has alpha channel */ +#define VBOX_MOUSE_POINTER_ALPHA (0x0002) +/** pointerData contains new pointer shape */ +#define VBOX_MOUSE_POINTER_SHAPE (0x0004) +/** @} */ + +/* the guest driver can handle asynch guest cmd completion by reading the command offset from io port */ +#define VBVACAPS_COMPLETEGCMD_BY_IOREAD 0x00000001 +/* the guest driver can handle video adapter IRQs */ +#define VBVACAPS_IRQ 0x00000002 +/** The guest can read video mode hints sent via VBVA. */ +#define VBVACAPS_VIDEO_MODE_HINTS 0x00000004 +/** The guest can switch to a software cursor on demand. */ +#define VBVACAPS_DISABLE_CURSOR_INTEGRATION 0x00000008 +/** The guest does not depend on host handling the VBE registers. */ +#define VBVACAPS_USE_VBVA_ONLY 0x00000010 +typedef struct VBVACAPS +{ + int32_t rc; + uint32_t fCaps; +} VBVACAPS; + +/* makes graphics device generate IRQ on VSYNC */ +#define VBVASCANLINECFG_ENABLE_VSYNC_IRQ 0x00000001 +/* guest driver may request the current scanline */ +#define VBVASCANLINECFG_ENABLE_SCANLINE_INFO 0x00000002 +/* request the current refresh period, returned in u32RefreshPeriodMs */ +#define VBVASCANLINECFG_QUERY_REFRESH_PERIOD 0x00000004 +/* set new refresh period specified in u32RefreshPeriodMs. + * if used with VBVASCANLINECFG_QUERY_REFRESH_PERIOD, + * u32RefreshPeriodMs is set to the previous refresh period on return */ +#define VBVASCANLINECFG_SET_REFRESH_PERIOD 0x00000008 + +typedef struct VBVASCANLINECFG +{ + int32_t rc; + uint32_t fFlags; + uint32_t u32RefreshPeriodMs; + uint32_t u32Reserved; +} VBVASCANLINECFG; + +typedef struct VBVASCANLINEINFO +{ + int32_t rc; + uint32_t u32ScreenId; + uint32_t u32InVBlank; + uint32_t u32ScanLine; +} VBVASCANLINEINFO; + +/** Query the most recent mode hints received from the host. */ +typedef struct VBVAQUERYMODEHINTS +{ + /** The maximum number of screens to return hints for. */ + uint16_t cHintsQueried; + /** The size of the mode hint structures directly following this one. */ + uint16_t cbHintStructureGuest; + /** The return code for the operation. Initialise to VERR_NOT_SUPPORTED. */ + int32_t rc; +} VBVAQUERYMODEHINTS; + +/** Structure in which a mode hint is returned. The guest allocates an array + * of these immediately after the VBVAQUERYMODEHINTS structure. To accomodate + * future extensions, the VBVAQUERYMODEHINTS structure specifies the size of + * the VBVAMODEHINT structures allocated by the guest, and the host only fills + * out structure elements which fit into that size. The host should fill any + * unused members (e.g. dx, dy) or structure space on the end with ~0. The + * whole structure can legally be set to ~0 to skip a screen. */ +typedef struct VBVAMODEHINT +{ + uint32_t magic; + uint32_t cx; + uint32_t cy; + uint32_t cBPP; /* Which has never been used... */ + uint32_t cDisplay; + uint32_t dx; /**< X offset into the virtual frame-buffer. */ + uint32_t dy; /**< Y offset into the virtual frame-buffer. */ + uint32_t fEnabled; /* Not fFlags. Add new members for new flags. */ +} VBVAMODEHINT; + +#define VBVAMODEHINT_MAGIC UINT32_C(0x0801add9) + +/** Report the rectangle relative to which absolute pointer events should be + * expressed. This information remains valid until the next VBVA resize event + * for any screen, at which time it is reset to the bounding rectangle of all + * virtual screens and must be re-set. + * @see VBVA_REPORT_INPUT_MAPPING. */ +typedef struct VBVAREPORTINPUTMAPPING +{ + int32_t x; /**< Upper left X co-ordinate relative to the first screen. */ + int32_t y; /**< Upper left Y co-ordinate relative to the first screen. */ + uint32_t cx; /**< Rectangle width. */ + uint32_t cy; /**< Rectangle height. */ +} VBVAREPORTINPUTMAPPING; + +/** Report the guest cursor position and query the host one. The host may wish + * to use the guest information to re-position its own cursor, particularly + * when the cursor is captured and the guest does not support switching to a + * software cursor. After every mode switch the guest must signal that it + * supports sending position information by sending an event with + * @a fReportPosition set to false. + * @see VBVA_CURSOR_POSITION */ +typedef struct VBVACURSORPOSITION +{ + uint32_t fReportPosition; /**< Are we reporting a position? */ + uint32_t x; /**< Guest cursor X position */ + uint32_t y; /**< Guest cursor Y position */ +} VBVACURSORPOSITION; + +#pragma pack() + +typedef uint64_t VBOXVIDEOOFFSET; + +#define VBOXVIDEOOFFSET_VOID ((VBOXVIDEOOFFSET)~0) + +#pragma pack(1) + +/* + * VBOXSHGSMI made on top HGSMI and allows receiving notifications + * about G->H command completion + */ +/* SHGSMI command header */ +typedef struct VBOXSHGSMIHEADER +{ + uint64_t pvNext; /*<- completion processing queue */ + uint32_t fFlags; /*<- see VBOXSHGSMI_FLAG_XXX Flags */ + uint32_t cRefs; /*<- command referece count */ + uint64_t u64Info1; /*<- contents depends on the fFlags value */ + uint64_t u64Info2; /*<- contents depends on the fFlags value */ +} VBOXSHGSMIHEADER, *PVBOXSHGSMIHEADER; + +typedef enum +{ + VBOXVDMACMD_TYPE_UNDEFINED = 0, + VBOXVDMACMD_TYPE_DMA_PRESENT_BLT = 1, + VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER, + VBOXVDMACMD_TYPE_DMA_BPB_FILL, + VBOXVDMACMD_TYPE_DMA_PRESENT_SHADOW2PRIMARY, + VBOXVDMACMD_TYPE_DMA_PRESENT_CLRFILL, + VBOXVDMACMD_TYPE_DMA_PRESENT_FLIP, + VBOXVDMACMD_TYPE_DMA_NOP, + VBOXVDMACMD_TYPE_CHROMIUM_CMD, /* chromium cmd */ + VBOXVDMACMD_TYPE_DMA_BPB_TRANSFER_VRAMSYS, + VBOXVDMACMD_TYPE_CHILD_STATUS_IRQ /* make the device notify child (monitor) state change IRQ */ +} VBOXVDMACMD_TYPE; + +#pragma pack() + +/* the command processing was asynch, set by the host to indicate asynch command completion + * must not be cleared once set, the command completion is performed by issuing a host->guest completion command + * while keeping this flag unchanged */ +#define VBOXSHGSMI_FLAG_HG_ASYNCH 0x00010000 +#if 0 +/* if set - asynch completion is performed by issuing the event, + * if cleared - asynch completion is performed by calling a callback */ +#define VBOXSHGSMI_FLAG_GH_ASYNCH_EVENT 0x00000001 +#endif +/* issue interrupt on asynch completion, used for critical G->H commands, + * i.e. for completion of which guest is waiting. */ +#define VBOXSHGSMI_FLAG_GH_ASYNCH_IRQ 0x00000002 +/* guest does not do any op on completion of this command, + * the host may copy the command and indicate that it does not need the command anymore + * by not setting VBOXSHGSMI_FLAG_HG_ASYNCH */ +#define VBOXSHGSMI_FLAG_GH_ASYNCH_NOCOMPLETION 0x00000004 +/* guest requires the command to be processed asynchronously, + * not setting VBOXSHGSMI_FLAG_HG_ASYNCH by the host in this case is treated as command failure */ +#define VBOXSHGSMI_FLAG_GH_ASYNCH_FORCE 0x00000008 +/* force IRQ on cmd completion */ +#define VBOXSHGSMI_FLAG_GH_ASYNCH_IRQ_FORCE 0x00000010 +/* an IRQ-level callback is associated with the command */ +#define VBOXSHGSMI_FLAG_GH_ASYNCH_CALLBACK_IRQ 0x00000020 +/* guest expects this command to be completed synchronously */ +#define VBOXSHGSMI_FLAG_GH_SYNCH 0x00000040 + + +DECLINLINE(uint8_t RT_UNTRUSTED_VOLATILE_GUEST *) +VBoxSHGSMIBufferData(const VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_GUEST *pHeader) +{ + return (uint8_t RT_UNTRUSTED_VOLATILE_GUEST *)pHeader + sizeof(VBOXSHGSMIHEADER); +} + +#define VBoxSHGSMIBufferHeaderSize() (sizeof(VBOXSHGSMIHEADER)) + +DECLINLINE(VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_GUEST *) VBoxSHGSMIBufferHeader(const void RT_UNTRUSTED_VOLATILE_GUEST *pvData) +{ + return (VBOXSHGSMIHEADER RT_UNTRUSTED_VOLATILE_GUEST *)((uintptr_t)pvData - sizeof(VBOXSHGSMIHEADER)); +} + +#ifdef VBOX_WITH_VDMA +# pragma pack(1) + +/* VDMA - Video DMA */ + +/* VDMA Control API */ +/* VBOXVDMA_CTL::u32Flags */ +typedef enum +{ + VBOXVDMA_CTL_TYPE_NONE = 0, + VBOXVDMA_CTL_TYPE_ENABLE, + VBOXVDMA_CTL_TYPE_DISABLE, + VBOXVDMA_CTL_TYPE_FLUSH, + VBOXVDMA_CTL_TYPE_WATCHDOG, + VBOXVDMA_CTL_TYPE_END +} VBOXVDMA_CTL_TYPE; + +typedef struct VBOXVDMA_CTL +{ + VBOXVDMA_CTL_TYPE enmCtl; + uint32_t u32Offset; + int32_t i32Result; +} VBOXVDMA_CTL; + +/* VBOXVDMACBUF_DR::phBuf specifies offset in VRAM */ +#define VBOXVDMACBUF_FLAG_BUF_VRAM_OFFSET 0x00000001 +/* command buffer follows the VBOXVDMACBUF_DR in VRAM, VBOXVDMACBUF_DR::phBuf is ignored */ +#define VBOXVDMACBUF_FLAG_BUF_FOLLOWS_DR 0x00000002 + +/** + * We can not submit the DMA command via VRAM since we do not have control over + * DMA command buffer [de]allocation, i.e. we only control the buffer contents. + * In other words the system may call one of our callbacks to fill a command buffer + * with the necessary commands and then discard the buffer w/o any notification. + * + * We have only DMA command buffer physical address at submission time. + * + * so the only way is to */ +typedef struct VBOXVDMACBUF_DR +{ + uint16_t fFlags; + uint16_t cbBuf; + /* RT_SUCCESS() - on success + * VERR_INTERRUPTED - on preemption + * VERR_xxx - on error */ + int32_t rc; + union + { + uint64_t phBuf; + VBOXVIDEOOFFSET offVramBuf; + } Location; + uint64_t aGuestData[7]; +} VBOXVDMACBUF_DR, *PVBOXVDMACBUF_DR; + +#define VBOXVDMACBUF_DR_TAIL(a_pCmd, a_TailType) \ + ( (a_TailType RT_UNTRUSTED_VOLATILE_HSTGST *)( ((uint8_t*)(a_pCmd)) + sizeof(VBOXVDMACBUF_DR)) ) +#define VBOXVDMACBUF_DR_FROM_TAIL(a_pCmd) \ + ( (VBOXVDMACBUF_DR RT_UNTRUSTED_VOLATILE_HSTGST *)( ((uint8_t*)(a_pCmd)) - sizeof(VBOXVDMACBUF_DR)) ) + +typedef struct VBOXVDMACMD +{ + VBOXVDMACMD_TYPE enmType; + uint32_t u32CmdSpecific; +} VBOXVDMACMD; + +#define VBOXVDMACMD_HEADER_SIZE() sizeof(VBOXVDMACMD) +#define VBOXVDMACMD_SIZE_FROMBODYSIZE(_s) ((uint32_t)(VBOXVDMACMD_HEADER_SIZE() + (_s))) +#define VBOXVDMACMD_SIZE(_t) (VBOXVDMACMD_SIZE_FROMBODYSIZE(sizeof(_t))) +#define VBOXVDMACMD_BODY(a_pCmd, a_TypeBody) \ + ( (a_TypeBody RT_UNTRUSTED_VOLATILE_HSTGST *)( ((uint8_t *)(a_pCmd)) + VBOXVDMACMD_HEADER_SIZE()) ) +#define VBOXVDMACMD_BODY_SIZE(_s) ( (_s) - VBOXVDMACMD_HEADER_SIZE() ) +#define VBOXVDMACMD_FROM_BODY(a_pBody) \ + ( (VBOXVDMACMD RT_UNTRUSTED_VOLATILE_HSTGST *)( ((uint8_t *)(a_pBody)) - VBOXVDMACMD_HEADER_SIZE()) ) +#define VBOXVDMACMD_BODY_FIELD_OFFSET(_ot, _t, _f) ( (_ot)(uintptr_t)( VBOXVDMACMD_BODY(0, uint8_t) + RT_UOFFSETOF_DYN(_t, _f) ) ) + +# pragma pack() +#endif /* #ifdef VBOX_WITH_VDMA */ + + +#define VBOXVDMA_CHILD_STATUS_F_CONNECTED 0x01 +#define VBOXVDMA_CHILD_STATUS_F_DISCONNECTED 0x02 +#define VBOXVDMA_CHILD_STATUS_F_ROTATED 0x04 + +typedef struct VBOXVDMA_CHILD_STATUS +{ + uint32_t iChild; + uint8_t fFlags; + uint8_t u8RotationAngle; + uint16_t u16Reserved; +} VBOXVDMA_CHILD_STATUS, *PVBOXVDMA_CHILD_STATUS; + +/* apply the aInfos are applied to all targets, the iTarget is ignored */ +#define VBOXVDMACMD_CHILD_STATUS_IRQ_F_APPLY_TO_ALL 0x00000001 + +typedef struct VBOXVDMACMD_CHILD_STATUS_IRQ +{ + uint32_t cInfos; + uint32_t fFlags; + VBOXVDMA_CHILD_STATUS aInfos[1]; +} VBOXVDMACMD_CHILD_STATUS_IRQ, *PVBOXVDMACMD_CHILD_STATUS_IRQ; + +#define VBOXCMDVBVA_SCREENMAP_SIZE(_elType) ((VBOX_VIDEO_MAX_SCREENS + sizeof (_elType) - 1) / sizeof (_elType)) +#define VBOXCMDVBVA_SCREENMAP_DECL(_elType, _name) _elType _name[VBOXCMDVBVA_SCREENMAP_SIZE(_elType)] + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideo_h */ + diff --git a/include/VBox/Graphics/VBoxVideo3D.h b/include/VBox/Graphics/VBoxVideo3D.h new file mode 100644 index 00000000..b1545d6f --- /dev/null +++ b/include/VBox/Graphics/VBoxVideo3D.h @@ -0,0 +1,186 @@ +/* $Id: VBoxVideo3D.h $ */ +/** @file + * VirtualBox 3D common tooling + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideo3D_h +#define VBOX_INCLUDED_Graphics_VBoxVideo3D_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#ifndef VBoxTlsRefGetImpl +# ifdef VBoxTlsRefSetImpl +# error "VBoxTlsRefSetImpl is defined, unexpected!" +# endif +# include +# define VBoxTlsRefGetImpl(_tls) (RTTlsGet((RTTLS)(_tls))) +# define VBoxTlsRefSetImpl(_tls, _val) (RTTlsSet((RTTLS)(_tls), (_val))) +#else +# ifndef VBoxTlsRefSetImpl +# error "VBoxTlsRefSetImpl is NOT defined, unexpected!" +# endif +#endif + +#ifndef VBoxTlsRefAssertImpl +# define VBoxTlsRefAssertImpl(_a) do {} while (0) +#endif + +typedef DECLCALLBACKTYPE(void, FNVBOXTLSREFDTOR,(void *)); +typedef FNVBOXTLSREFDTOR *PFNVBOXTLSREFDTOR; + +typedef enum { + VBOXTLSREFDATA_STATE_UNDEFINED = 0, + VBOXTLSREFDATA_STATE_INITIALIZED, + VBOXTLSREFDATA_STATE_TOBE_DESTROYED, + VBOXTLSREFDATA_STATE_DESTROYING, + VBOXTLSREFDATA_STATE_32BIT_HACK = 0x7fffffff +} VBOXTLSREFDATA_STATE; + +#define VBOXTLSREFDATA \ + volatile int32_t cTlsRefs; \ + VBOXTLSREFDATA_STATE enmTlsRefState; \ + PFNVBOXTLSREFDTOR pfnTlsRefDtor; \ + +struct VBOXTLSREFDATA_DUMMY +{ + VBOXTLSREFDATA +}; + +#define VBOXTLSREFDATA_OFFSET(_t) RT_OFFSETOF(_t, cTlsRefs) +#define VBOXTLSREFDATA_ASSERT_OFFSET(_t) RTASSERT_OFFSET_OF(_t, cTlsRefs) +#define VBOXTLSREFDATA_SIZE() (sizeof (struct VBOXTLSREFDATA_DUMMY)) +#define VBOXTLSREFDATA_COPY(_pDst, _pSrc) do { \ + (_pDst)->cTlsRefs = (_pSrc)->cTlsRefs; \ + (_pDst)->enmTlsRefState = (_pSrc)->enmTlsRefState; \ + (_pDst)->pfnTlsRefDtor = (_pSrc)->pfnTlsRefDtor; \ + } while (0) + +#define VBOXTLSREFDATA_EQUAL(_pDst, _pSrc) ( \ + (_pDst)->cTlsRefs == (_pSrc)->cTlsRefs \ + && (_pDst)->enmTlsRefState == (_pSrc)->enmTlsRefState \ + && (_pDst)->pfnTlsRefDtor == (_pSrc)->pfnTlsRefDtor \ + ) + + +#define VBoxTlsRefInit(_p, _pfnDtor) do { \ + (_p)->cTlsRefs = 1; \ + (_p)->enmTlsRefState = VBOXTLSREFDATA_STATE_INITIALIZED; \ + (_p)->pfnTlsRefDtor = (_pfnDtor); \ + } while (0) + +#define VBoxTlsRefIsFunctional(_p) (!!((_p)->enmTlsRefState == VBOXTLSREFDATA_STATE_INITIALIZED)) + +#define VBoxTlsRefAddRef(_p) do { \ + int cRefs = ASMAtomicIncS32(&(_p)->cTlsRefs); \ + VBoxTlsRefAssertImpl(cRefs > 1 || (_p)->enmTlsRefState == VBOXTLSREFDATA_STATE_DESTROYING); \ + RT_NOREF(cRefs); \ + } while (0) + +#define VBoxTlsRefCountGet(_p) (ASMAtomicReadS32(&(_p)->cTlsRefs)) + +#define VBoxTlsRefRelease(_p) do { \ + int cRefs = ASMAtomicDecS32(&(_p)->cTlsRefs); \ + VBoxTlsRefAssertImpl(cRefs >= 0); \ + if (!cRefs && (_p)->enmTlsRefState != VBOXTLSREFDATA_STATE_DESTROYING /* <- avoid recursion if VBoxTlsRefAddRef/Release is called from dtor */) { \ + (_p)->enmTlsRefState = VBOXTLSREFDATA_STATE_DESTROYING; \ + (_p)->pfnTlsRefDtor((_p)); \ + } \ + } while (0) + +#define VBoxTlsRefMarkDestroy(_p) do { \ + (_p)->enmTlsRefState = VBOXTLSREFDATA_STATE_TOBE_DESTROYED; \ + } while (0) + +#define VBoxTlsRefGetCurrent(_t, _Tsd) ((_t*) VBoxTlsRefGetImpl((_Tsd))) + +#define VBoxTlsRefGetCurrentFunctional(_val, _t, _Tsd) do { \ + _t * cur = VBoxTlsRefGetCurrent(_t, _Tsd); \ + if (!cur || VBoxTlsRefIsFunctional(cur)) { \ + (_val) = cur; \ + } else { \ + VBoxTlsRefSetCurrent(_t, _Tsd, NULL); \ + (_val) = NULL; \ + } \ + } while (0) + +#define VBoxTlsRefSetCurrent(_t, _Tsd, _p) do { \ + _t * oldCur = VBoxTlsRefGetCurrent(_t, _Tsd); \ + if (oldCur != (_p)) { \ + VBoxTlsRefSetImpl((_Tsd), (_p)); \ + if (oldCur) { \ + VBoxTlsRefRelease(oldCur); \ + } \ + if ((_p)) { \ + VBoxTlsRefAddRef((_t*)(_p)); \ + } \ + } \ + } while (0) + + +/* host 3D->Fe[/Qt] notification mechanism defines */ +typedef enum +{ + VBOX3D_NOTIFY_TYPE_TEST_FUNCTIONAL = 3, + VBOX3D_NOTIFY_TYPE_3DDATA_VISIBLE = 4, + VBOX3D_NOTIFY_TYPE_3DDATA_HIDDEN = 5, + + VBOX3D_NOTIFY_TYPE_HW_SCREEN_FIRST = 100, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_IS_SUPPORTED = 100, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_CREATED = 101, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_DESTROYED = 102, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_UPDATE_BEGIN = 103, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_UPDATE_END = 104, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_BIND_SURFACE = 105, + VBOX3D_NOTIFY_TYPE_HW_SCREEN_LAST = 105, + + VBOX3D_NOTIFY_TYPE_HW_OVERLAY_CREATED = 200, + VBOX3D_NOTIFY_TYPE_HW_OVERLAY_DESTROYED = 201, + VBOX3D_NOTIFY_TYPE_HW_OVERLAY_GET_ID = 202, + + VBOX3D_NOTIFY_TYPE_32BIT_HACK = 0x7fffffff +} VBOX3D_NOTIFY_TYPE; + +typedef struct VBOX3DNOTIFY +{ + VBOX3D_NOTIFY_TYPE enmNotification; + int32_t iDisplay; + uint32_t u32Reserved; + uint32_t cbData; + uint8_t au8Data[sizeof(uint64_t)]; +} VBOX3DNOTIFY; + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideo3D_h */ diff --git a/include/VBox/Graphics/VBoxVideoErr.h b/include/VBox/Graphics/VBoxVideoErr.h new file mode 100644 index 00000000..a934d16a --- /dev/null +++ b/include/VBox/Graphics/VBoxVideoErr.h @@ -0,0 +1,76 @@ +/* $Id: VBoxVideoErr.h $ */ +/** @file + * VirtualBox Video driver, common code - iprt and VirtualBox macros and + * definitions. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideoErr_h +#define VBOX_INCLUDED_Graphics_VBoxVideoErr_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** @name VirtualBox error macros + * @{ */ + +#define VINF_SUCCESS 0 +#define VERR_INVALID_PARAMETER (-2) +#define VERR_INVALID_POINTER (-6) +#define VERR_NO_MEMORY (-8) +#define VERR_NOT_IMPLEMENTED (-12) +#define VERR_INVALID_FUNCTION (-36) +#define VERR_NOT_SUPPORTED (-37) +#define VERR_TOO_MUCH_DATA (-42) +#define VERR_NOT_FOUND (-78) +#define VERR_INVALID_STATE (-79) +#define VERR_OUT_OF_RESOURCES (-80) +#define VERR_ALREADY_EXISTS (-105) +#define VERR_INTERNAL_ERROR (-225) + +#define RT_SUCCESS_NP(rc) ( (int)(rc) >= VINF_SUCCESS ) +#define RT_SUCCESS(rc) ( likely(RT_SUCCESS_NP(rc)) ) +#define RT_FAILURE(rc) ( unlikely(!RT_SUCCESS_NP(rc)) ) + +/** @} */ + +/** @name VirtualBox assertions + * @{ */ + +/* Unlike BUILD_BUG_ON(), these can be used outside of functions. */ +extern int vbox_assert_var[1]; +#define assert_compile(expr) \ + extern int vbox_assert_var[1] __attribute__((__unused__)), \ + vbox_assert_var[(expr) ? 1 : 0] __attribute__((__unused__)) +#define assert_compile_size(type, size) \ + assert_compile(sizeof(type) == (size)) +#define assert_ptr_return(ptr,ret) \ + do { if (unlikely(!(ptr))) { WARN_ON_ONCE(!(ptr)); return ret; } } while (0) + +/** @} */ + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideoErr_h */ diff --git a/include/VBox/Graphics/VBoxVideoGuest.h b/include/VBox/Graphics/VBoxVideoGuest.h new file mode 100644 index 00000000..82018737 --- /dev/null +++ b/include/VBox/Graphics/VBoxVideoGuest.h @@ -0,0 +1,185 @@ +/* $Id: VBoxVideoGuest.h $ */ +/** @file + * VBox Host Guest Shared Memory Interface (HGSMI) - OS-independent guest structures. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideoGuest_h +#define VBOX_INCLUDED_Graphics_VBoxVideoGuest_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBoxVideoIPRT.h" +#include "HGSMIBase.h" +#include "VBoxVideo.h" + +RT_C_DECLS_BEGIN + +/** + * Structure grouping the context needed for sending graphics acceleration + * information to the host via VBVA. Each screen has its own VBVA buffer. + */ +typedef struct VBVABUFFERCONTEXT +{ + /** Offset of the buffer in the VRAM section for the screen */ + uint32_t offVRAMBuffer; + /** Length of the buffer in bytes */ + uint32_t cbBuffer; + /** This flag is set if we wrote to the buffer faster than the host could + * read it. */ + bool fHwBufferOverflow; + /** The VBVA record that we are currently preparing for the host, NULL if + * none. */ + struct VBVARECORD *pRecord; + /** Pointer to the VBVA buffer mapped into the current address space. Will + * be NULL if VBVA is not enabled. */ + struct VBVABUFFER *pVBVA; +} VBVABUFFERCONTEXT, *PVBVABUFFERCONTEXT; + +/** @name Base HGSMI APIs + * @{ */ + +DECLHIDDEN(bool) VBoxHGSMIIsSupported(void); +DECLHIDDEN(void) VBoxHGSMIGetBaseMappingInfo(uint32_t cbVRAM, + uint32_t *poffVRAMBaseMapping, + uint32_t *pcbMapping, + uint32_t *poffGuestHeapMemory, + uint32_t *pcbGuestHeapMemory, + uint32_t *poffHostFlags); +DECLHIDDEN(int) VBoxHGSMIReportFlagsLocation(PHGSMIGUESTCOMMANDCONTEXT pCtx, + HGSMIOFFSET offLocation); +DECLHIDDEN(int) VBoxHGSMISendCapsInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t fCaps); +DECLHIDDEN(void) VBoxHGSMIGetHostAreaMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t cbVRAM, + uint32_t offVRAMBaseMapping, + uint32_t *poffVRAMHostArea, + uint32_t *pcbHostArea); +DECLHIDDEN(int) VBoxHGSMISendHostCtxInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx, + HGSMIOFFSET offVRAMFlagsLocation, + uint32_t fCaps, + uint32_t offVRAMHostArea, + uint32_t cbHostArea); +DECLHIDDEN(int) VBoxQueryConfHGSMI(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t u32Index, uint32_t *pulValue); +DECLHIDDEN(int) VBoxQueryConfHGSMIDef(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t u32Index, uint32_t u32DefValue, uint32_t *pulValue); +DECLHIDDEN(int) VBoxHGSMIUpdatePointerShape(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t fFlags, + uint32_t cHotX, + uint32_t cHotY, + uint32_t cWidth, + uint32_t cHeight, + uint8_t *pPixels, + uint32_t cbLength); +DECLHIDDEN(int) VBoxHGSMICursorPosition(PHGSMIGUESTCOMMANDCONTEXT pCtx, bool fReportPosition, uint32_t x, uint32_t y, + uint32_t *pxHost, uint32_t *pyHost); + +/** @} */ + +/** @name VBVA APIs + * @{ */ +DECLHIDDEN(bool) VBoxVBVAEnable(PVBVABUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, + struct VBVABUFFER *pVBVA, int32_t cScreen); +DECLHIDDEN(void) VBoxVBVADisable(PVBVABUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, + int32_t cScreen); +DECLHIDDEN(bool) VBoxVBVABufferBeginUpdate(PVBVABUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx); +DECLHIDDEN(void) VBoxVBVABufferEndUpdate(PVBVABUFFERCONTEXT pCtx); +DECLHIDDEN(bool) VBoxVBVAWrite(PVBVABUFFERCONTEXT pCtx, + PHGSMIGUESTCOMMANDCONTEXT pHGSMICtx, + const void *pv, uint32_t cb); +DECLHIDDEN(bool) VBoxVBVAOrderSupported(PVBVABUFFERCONTEXT pCtx, unsigned code); +DECLHIDDEN(void) VBoxVBVASetupBufferContext(PVBVABUFFERCONTEXT pCtx, + uint32_t offVRAMBuffer, + uint32_t cbBuffer); + +/** @} */ + +/** @name Modesetting APIs + * @{ */ + +DECLHIDDEN(uint32_t) VBoxHGSMIGetMonitorCount(PHGSMIGUESTCOMMANDCONTEXT pCtx); +DECLHIDDEN(bool) VBoxVGACfgAvailable(void); +DECLHIDDEN(bool) VBoxVGACfgQuery(uint16_t u16Id, uint32_t *pu32Value, uint32_t u32DefValue); +DECLHIDDEN(uint32_t) VBoxVideoGetVRAMSize(void); +DECLHIDDEN(bool) VBoxVideoAnyWidthAllowed(void); +DECLHIDDEN(uint16_t) VBoxHGSMIGetScreenFlags(PHGSMIGUESTCOMMANDCONTEXT pCtx); + +struct VBVAINFOVIEW; +/** + * Callback funtion called from @a VBoxHGSMISendViewInfo to initialise + * the @a VBVAINFOVIEW structure for each screen. + * + * @returns iprt status code + * @param pvData context data for the callback, passed to @a + * VBoxHGSMISendViewInfo along with the callback + * @param pInfo array of @a VBVAINFOVIEW structures to be filled in + * @todo explicitly pass the array size + */ +typedef DECLCALLBACKTYPE(int, FNHGSMIFILLVIEWINFO,(void *pvData, struct VBVAINFOVIEW *pInfo, uint32_t cViews)); +/** Pointer to a FNHGSMIFILLVIEWINFO callback */ +typedef FNHGSMIFILLVIEWINFO *PFNHGSMIFILLVIEWINFO; + +DECLHIDDEN(int) VBoxHGSMISendViewInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t u32Count, + PFNHGSMIFILLVIEWINFO pfnFill, + void *pvData); +DECLHIDDEN(void) VBoxVideoSetModeRegisters(uint16_t cWidth, uint16_t cHeight, + uint16_t cVirtWidth, uint16_t cBPP, + uint16_t fFlags, + uint16_t cx, uint16_t cy); +DECLHIDDEN(bool) VBoxVideoGetModeRegisters(uint16_t *pcWidth, + uint16_t *pcHeight, + uint16_t *pcVirtWidth, + uint16_t *pcBPP, + uint16_t *pfFlags); +DECLHIDDEN(void) VBoxVideoDisableVBE(void); +DECLHIDDEN(void) VBoxHGSMIProcessDisplayInfo(PHGSMIGUESTCOMMANDCONTEXT pCtx, + uint32_t cDisplay, + int32_t cOriginX, + int32_t cOriginY, + uint32_t offStart, + uint32_t cbPitch, + uint32_t cWidth, + uint32_t cHeight, + uint16_t cBPP, + uint16_t fFlags); +DECLHIDDEN(int) VBoxHGSMIUpdateInputMapping(PHGSMIGUESTCOMMANDCONTEXT pCtx, int32_t cOriginX, int32_t cOriginY, + uint32_t cWidth, uint32_t cHeight); +DECLHIDDEN(int) VBoxHGSMIGetModeHints(PHGSMIGUESTCOMMANDCONTEXT pCtx, + unsigned cScreens, VBVAMODEHINT *paHints); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideoGuest_h */ + diff --git a/include/VBox/Graphics/VBoxVideoIPRT.h b/include/VBox/Graphics/VBoxVideoIPRT.h new file mode 100644 index 00000000..b1533e72 --- /dev/null +++ b/include/VBox/Graphics/VBoxVideoIPRT.h @@ -0,0 +1,114 @@ +/* $Id: VBoxVideoIPRT.h $ */ +/** @file + * VirtualBox Video driver, common code - iprt and VirtualBox macros and definitions. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideoIPRT_h +#define VBOX_INCLUDED_Graphics_VBoxVideoIPRT_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#if !defined(RT_OS_OS2) || !defined(__IBMC__) /* IBM VACpp 3.08 doesn't properly eliminate unused inline functions */ +# include +# include +#endif +#include +#include +#include +#include +#include +#include +#include + +#if !defined(VBOX_XPDM_MINIPORT) && !defined(RT_OS_OS2) && (defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)) +# include +#endif + +#ifdef VBOX_XPDM_MINIPORT +# include +# include /* sdk, clean */ +# include +#endif + +/** @name Port I/O helpers + * @{ */ + +#ifdef VBOX_XPDM_MINIPORT + +/** Write an 8-bit value to an I/O port. */ +# define VBVO_PORT_WRITE_U8(Port, Value) \ + VideoPortWritePortUchar((PUCHAR)Port, Value) +/** Write a 16-bit value to an I/O port. */ +# define VBVO_PORT_WRITE_U16(Port, Value) \ + VideoPortWritePortUshort((PUSHORT)Port, Value) +/** Write a 32-bit value to an I/O port. */ +# define VBVO_PORT_WRITE_U32(Port, Value) \ + VideoPortWritePortUlong((PULONG)Port, Value) +/** Read an 8-bit value from an I/O port. */ +# define VBVO_PORT_READ_U8(Port) \ + VideoPortReadPortUchar((PUCHAR)Port) +/** Read a 16-bit value from an I/O port. */ +# define VBVO_PORT_READ_U16(Port) \ + VideoPortReadPortUshort((PUSHORT)Port) +/** Read a 32-bit value from an I/O port. */ +# define VBVO_PORT_READ_U32(Port) \ + VideoPortReadPortUlong((PULONG)Port) + +#else /** @todo make these explicit */ + +/** Write an 8-bit value to an I/O port. */ +# define VBVO_PORT_WRITE_U8(Port, Value) \ + ASMOutU8(Port, Value) +/** Write a 16-bit value to an I/O port. */ +# define VBVO_PORT_WRITE_U16(Port, Value) \ + ASMOutU16(Port, Value) +/** Write a 32-bit value to an I/O port. */ +# define VBVO_PORT_WRITE_U32(Port, Value) \ + ASMOutU32(Port, Value) +/** Read an 8-bit value from an I/O port. */ +# define VBVO_PORT_READ_U8(Port) \ + ASMInU8(Port) +/** Read a 16-bit value from an I/O port. */ +# define VBVO_PORT_READ_U16(Port) \ + ASMInU16(Port) +/** Read a 32-bit value from an I/O port. */ +# define VBVO_PORT_READ_U32(Port) \ + ASMInU32(Port) +#endif + +/** @} */ + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideoIPRT_h */ + diff --git a/include/VBox/Graphics/VBoxVideoVBE.h b/include/VBox/Graphics/VBoxVideoVBE.h new file mode 100644 index 00000000..fb1c6808 --- /dev/null +++ b/include/VBox/Graphics/VBoxVideoVBE.h @@ -0,0 +1,107 @@ +/* $Id: VBoxVideoVBE.h $ */ +/** @file + * VirtualBox graphics card port I/O definitions + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideoVBE_h +#define VBOX_INCLUDED_Graphics_VBoxVideoVBE_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* GUEST <-> HOST Communication API */ + +/** @todo FIXME: Either dynamicly ask host for this or put somewhere high in + * physical memory like 0xE0000000. */ + +#define VBE_DISPI_BANK_ADDRESS 0xA0000 +#define VBE_DISPI_BANK_SIZE_KB 64 + +#define VBE_DISPI_MAX_XRES 16384 +#define VBE_DISPI_MAX_YRES 16384 +#define VBE_DISPI_MAX_BPP 32 + +#define VBE_DISPI_IOPORT_INDEX 0x01CE +#define VBE_DISPI_IOPORT_DATA 0x01CF + +#define VBE_DISPI_IOPORT_DAC_WRITE_INDEX 0x03C8 +#define VBE_DISPI_IOPORT_DAC_DATA 0x03C9 + +/* Cross reference with src/VBox/Devices/Graphics/DevVGA.h */ +#define VBE_DISPI_INDEX_ID 0x0 +#define VBE_DISPI_INDEX_XRES 0x1 +#define VBE_DISPI_INDEX_YRES 0x2 +#define VBE_DISPI_INDEX_BPP 0x3 +#define VBE_DISPI_INDEX_ENABLE 0x4 +#define VBE_DISPI_INDEX_BANK 0x5 +#define VBE_DISPI_INDEX_VIRT_WIDTH 0x6 +#define VBE_DISPI_INDEX_VIRT_HEIGHT 0x7 +#define VBE_DISPI_INDEX_X_OFFSET 0x8 +#define VBE_DISPI_INDEX_Y_OFFSET 0x9 +#define VBE_DISPI_INDEX_VBOX_VIDEO 0xa +#define VBE_DISPI_INDEX_FB_BASE_HI 0xb +#define VBE_DISPI_INDEX_CFG 0xc + +#define VBE_DISPI_ID0 0xB0C0 +#define VBE_DISPI_ID1 0xB0C1 +#define VBE_DISPI_ID2 0xB0C2 +#define VBE_DISPI_ID3 0xB0C3 +#define VBE_DISPI_ID4 0xB0C4 + +#define VBE_DISPI_ID_VBOX_VIDEO 0xBE00 +/* The VBOX interface id. Indicates support for VBVA shared memory interface. */ +#define VBE_DISPI_ID_HGSMI 0xBE01 +#define VBE_DISPI_ID_ANYX 0xBE02 +#define VBE_DISPI_ID_CFG 0xBE03 /* VBE_DISPI_INDEX_CFG is available. */ + +#define VBE_DISPI_DISABLED 0x00 +#define VBE_DISPI_ENABLED 0x01 +#define VBE_DISPI_GETCAPS 0x02 +#define VBE_DISPI_8BIT_DAC 0x20 +/** @note this definition is a BOCHS legacy, used only in the video BIOS + * code and ignored by the emulated hardware. */ +#define VBE_DISPI_LFB_ENABLED 0x40 +#define VBE_DISPI_NOCLEARMEM 0x80 + +/* VBE_DISPI_INDEX_CFG content. */ +#define VBE_DISPI_CFG_MASK_ID 0x0FFF /* Identifier of a configuration value. */ +#define VBE_DISPI_CFG_MASK_SUPPORT 0x1000 /* Query whether the identifier is supported. */ +#define VBE_DISPI_CFG_MASK_RESERVED 0xE000 /* For future extensions. Must be 0. */ + +/* VBE_DISPI_INDEX_CFG values. */ +#define VBE_DISPI_CFG_ID_VERSION 0x0000 /* Version of the configuration interface. */ +#define VBE_DISPI_CFG_ID_VRAM_SIZE 0x0001 /* VRAM size. */ +#define VBE_DISPI_CFG_ID_3D 0x0002 /* 3D support. */ +#define VBE_DISPI_CFG_ID_VMSVGA 0x0003 /* VMSVGA FIFO and ports are available. */ +#define VBE_DISPI_CFG_ID_VMSVGA_DX 0x0004 /* VGPU10 is enabled. */ + +#define VGA_PORT_HGSMI_HOST 0x3b0 +#define VGA_PORT_HGSMI_GUEST 0x3d0 + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideoVBE_h */ + diff --git a/include/VBox/Graphics/VBoxVideoVBEPrivate.h b/include/VBox/Graphics/VBoxVideoVBEPrivate.h new file mode 100644 index 00000000..40f8bfa4 --- /dev/null +++ b/include/VBox/Graphics/VBoxVideoVBEPrivate.h @@ -0,0 +1,245 @@ +/** @file + * VirtualBox graphics card definitions, private interface for firmware + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_Graphics_VBoxVideoVBEPrivate_h +#define VBOX_INCLUDED_Graphics_VBoxVideoVBEPrivate_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifdef VBE +# include +#else +# include +#endif + +/* VBE Mode Numbers */ +#define VBE_MODE_VESA_DEFINED 0x0100 +#define VBE_MODE_REFRESH_RATE_USE_CRTC 0x0800 +#define VBE_MODE_LINEAR_FRAME_BUFFER 0x4000 +#define VBE_MODE_PRESERVE_DISPLAY_MEMORY 0x8000 + +/* VBE GFX Mode Number */ +#define VBE_VESA_MODE_640X400X8 0x100 +#define VBE_VESA_MODE_640X480X8 0x101 +#define VBE_VESA_MODE_800X600X4 0x102 +#define VBE_VESA_MODE_800X600X8 0x103 +#define VBE_VESA_MODE_1024X768X4 0x104 +#define VBE_VESA_MODE_1024X768X8 0x105 +#define VBE_VESA_MODE_1280X1024X4 0x106 +#define VBE_VESA_MODE_1280X1024X8 0x107 +#define VBE_VESA_MODE_320X200X1555 0x10D +#define VBE_VESA_MODE_320X200X565 0x10E +#define VBE_VESA_MODE_320X200X888 0x10F +#define VBE_VESA_MODE_640X480X1555 0x110 +#define VBE_VESA_MODE_640X480X565 0x111 +#define VBE_VESA_MODE_640X480X888 0x112 +#define VBE_VESA_MODE_800X600X1555 0x113 +#define VBE_VESA_MODE_800X600X565 0x114 +#define VBE_VESA_MODE_800X600X888 0x115 +#define VBE_VESA_MODE_1024X768X1555 0x116 +#define VBE_VESA_MODE_1024X768X565 0x117 +#define VBE_VESA_MODE_1024X768X888 0x118 +#define VBE_VESA_MODE_1280X1024X1555 0x119 +#define VBE_VESA_MODE_1280X1024X565 0x11A +#define VBE_VESA_MODE_1280X1024X888 0x11B +#define VBE_VESA_MODE_1600X1200X8 0x11C +#define VBE_VESA_MODE_1600X1200X1555 0x11D +#define VBE_VESA_MODE_1600X1200X565 0x11E +#define VBE_VESA_MODE_1600X1200X888 0x11F + +/* BOCHS/PLEX86 'own' mode numbers */ +#define VBE_OWN_MODE_320X200X8888 0x140 +#define VBE_OWN_MODE_640X400X8888 0x141 +#define VBE_OWN_MODE_640X480X8888 0x142 +#define VBE_OWN_MODE_800X600X8888 0x143 +#define VBE_OWN_MODE_1024X768X8888 0x144 +#define VBE_OWN_MODE_1280X1024X8888 0x145 +#define VBE_OWN_MODE_320X200X8 0x146 +#define VBE_OWN_MODE_1600X1200X8888 0x147 +#define VBE_OWN_MODE_1152X864X8 0x148 +#define VBE_OWN_MODE_1152X864X1555 0x149 +#define VBE_OWN_MODE_1152X864X565 0x14a +#define VBE_OWN_MODE_1152X864X888 0x14b +#define VBE_OWN_MODE_1152X864X8888 0x14c + +/* VirtualBox 'own' mode numbers */ +#define VBE_VBOX_MODE_CUSTOM1 0x160 +#define VBE_VBOX_MODE_CUSTOM2 0x161 +#define VBE_VBOX_MODE_CUSTOM3 0x162 +#define VBE_VBOX_MODE_CUSTOM4 0x163 +#define VBE_VBOX_MODE_CUSTOM5 0x164 +#define VBE_VBOX_MODE_CUSTOM6 0x165 +#define VBE_VBOX_MODE_CUSTOM7 0x166 +#define VBE_VBOX_MODE_CUSTOM8 0x167 +#define VBE_VBOX_MODE_CUSTOM9 0x168 +#define VBE_VBOX_MODE_CUSTOM10 0x169 +#define VBE_VBOX_MODE_CUSTOM11 0x16a +#define VBE_VBOX_MODE_CUSTOM12 0x16b +#define VBE_VBOX_MODE_CUSTOM13 0x16c +#define VBE_VBOX_MODE_CUSTOM14 0x16d +#define VBE_VBOX_MODE_CUSTOM15 0x16e +#define VBE_VBOX_MODE_CUSTOM16 0x16f + +#define VBE_VESA_MODE_END_OF_LIST 0xFFFF + +/* Capabilities */ +#define VBE_CAPABILITY_8BIT_DAC 0x0001 +#define VBE_CAPABILITY_NOT_VGA_COMPATIBLE 0x0002 +#define VBE_CAPABILITY_RAMDAC_USE_BLANK_BIT 0x0004 +#define VBE_CAPABILITY_STEREOSCOPIC_SUPPORT 0x0008 +#define VBE_CAPABILITY_STEREO_VIA_VESA_EVC 0x0010 + +/* Mode Attributes */ +#define VBE_MODE_ATTRIBUTE_SUPPORTED 0x0001 +#define VBE_MODE_ATTRIBUTE_EXTENDED_INFORMATION_AVAILABLE 0x0002 +#define VBE_MODE_ATTRIBUTE_TTY_BIOS_SUPPORT 0x0004 +#define VBE_MODE_ATTRIBUTE_COLOR_MODE 0x0008 +#define VBE_MODE_ATTRIBUTE_GRAPHICS_MODE 0x0010 +#define VBE_MODE_ATTRIBUTE_NOT_VGA_COMPATIBLE 0x0020 +#define VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW 0x0040 +#define VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE 0x0080 +#define VBE_MODE_ATTRIBUTE_DOUBLE_SCAN_MODE 0x0100 +#define VBE_MODE_ATTRIBUTE_INTERLACE_MODE 0x0200 +#define VBE_MODE_ATTRIBUTE_HARDWARE_TRIPLE_BUFFER 0x0400 +#define VBE_MODE_ATTRIBUTE_HARDWARE_STEREOSCOPIC_DISPLAY 0x0800 +#define VBE_MODE_ATTRIBUTE_DUAL_DISPLAY_START_ADDRESS 0x1000 + +#define VBE_MODE_ATTTRIBUTE_LFB_ONLY ( VBE_MODE_ATTRIBUTE_NO_VGA_COMPATIBLE_WINDOW | VBE_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER_MODE ) + +/* Window attributes */ +#define VBE_WINDOW_ATTRIBUTE_RELOCATABLE 0x01 +#define VBE_WINDOW_ATTRIBUTE_READABLE 0x02 +#define VBE_WINDOW_ATTRIBUTE_WRITEABLE 0x04 + +/* Memory model */ +#define VBE_MEMORYMODEL_TEXT_MODE 0x00 +#define VBE_MEMORYMODEL_CGA_GRAPHICS 0x01 +#define VBE_MEMORYMODEL_HERCULES_GRAPHICS 0x02 +#define VBE_MEMORYMODEL_PLANAR 0x03 +#define VBE_MEMORYMODEL_PACKED_PIXEL 0x04 +#define VBE_MEMORYMODEL_NON_CHAIN_4_256 0x05 +#define VBE_MEMORYMODEL_DIRECT_COLOR 0x06 +#define VBE_MEMORYMODEL_YUV 0x07 + +/* DirectColorModeInfo */ +#define VBE_DIRECTCOLOR_COLOR_RAMP_PROGRAMMABLE 0x01 +#define VBE_DIRECTCOLOR_RESERVED_BITS_AVAILABLE 0x02 + +/* Video memory */ +#define VGAMEM_GRAPH 0xA000 + +/** + * VBE Bios Extra Data structure. + */ +typedef struct VBEHeader +{ + /** Signature (VBEHEADER_MAGIC). */ + uint16_t u16Signature; + /** Data size. */ + uint16_t cbData; +} VBEHeader; + +/** The value of the VBEHeader::u16Signature field. */ +#define VBEHEADER_MAGIC 0x77CC + +/** The extra port which is used to read the mode list. */ +#define VBE_EXTRA_PORT 0x3b6 + +/** The extra port which is used for debug printf. */ +#define VBE_PRINTF_PORT 0x3b7 + +/** + * This one is for compactly storing a list of mode info blocks + */ +#pragma pack(1) /* pack(1) is important! (you'll get a byte extra for each of the u8 fields elsewise...) + * bird: Load of non-sense. You'll get two extra bytes before MaxPixelClock if you don't pack it. */ +typedef struct ModeInfoBlockCompact +{ + /* Mandatory information for all VBE revisions */ + uint16_t ModeAttributes; + uint8_t WinAAttributes; + uint8_t WinBAttributes; + uint16_t WinGranularity; + uint16_t WinSize; + uint16_t WinASegment; + uint16_t WinBSegment; + uint32_t WinFuncPtr; + uint16_t BytesPerScanLine; + /* Mandatory information for VBE 1.2 and above */ + uint16_t XResolution; + uint16_t YResolution; + uint8_t XCharSize; + uint8_t YCharSize; + uint8_t NumberOfPlanes; + uint8_t BitsPerPixel; + uint8_t NumberOfBanks; + uint8_t MemoryModel; + uint8_t BankSize; + uint8_t NumberOfImagePages; + uint8_t Reserved_page; + /* Direct Color fields (required for direct/6 and YUV/7 memory models) */ + uint8_t RedMaskSize; + uint8_t RedFieldPosition; + uint8_t GreenMaskSize; + uint8_t GreenFieldPosition; + uint8_t BlueMaskSize; + uint8_t BlueFieldPosition; + uint8_t RsvdMaskSize; + uint8_t RsvdFieldPosition; + uint8_t DirectColorModeInfo; + /* Mandatory information for VBE 2.0 and above */ + uint32_t PhysBasePtr; + uint32_t OffScreenMemOffset; + uint16_t OffScreenMemSize; + /* Mandatory information for VBE 3.0 and above */ + uint16_t LinBytesPerScanLine; + uint8_t BnkNumberOfPages; + uint8_t LinNumberOfPages; + uint8_t LinRedMaskSize; + uint8_t LinRedFieldPosition; + uint8_t LinGreenMaskSize; + uint8_t LinGreenFieldPosition; + uint8_t LinBlueMaskSize; + uint8_t LinBlueFieldPosition; + uint8_t LinRsvdMaskSize; + uint8_t LinRsvdFieldPosition; + uint32_t MaxPixelClock; +} ModeInfoBlockCompact; +#pragma pack() + +typedef struct ModeInfoListItem +{ + uint16_t mode; + ModeInfoBlockCompact info; +} ModeInfoListItem; + + +#endif /* !VBOX_INCLUDED_Graphics_VBoxVideoVBEPrivate_h */ + diff --git a/include/VBox/GuestHost/DragAndDrop.h b/include/VBox/GuestHost/DragAndDrop.h new file mode 100644 index 00000000..a9722c59 --- /dev/null +++ b/include/VBox/GuestHost/DragAndDrop.h @@ -0,0 +1,350 @@ +/* $Id: DragAndDrop.h $ */ +/** @file + * DnD - Shared functions between host and guest. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_DragAndDrop_h +#define VBOX_INCLUDED_GuestHost_DragAndDrop_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +#include + +/** DnDURIDroppedFiles flags. */ +typedef uint32_t DNDURIDROPPEDFILEFLAGS; + +/** No flags specified. */ +#define DNDURIDROPPEDFILE_FLAGS_NONE 0 + +/** + * Structure for keeping a DnD dropped files entry. + */ +typedef struct DNDDROPPEDFILESENTRY +{ + RTLISTNODE Node; + char *pszPath; +} DNDDROPPEDFILESENTRY; +/** Pointer to a DnD dropped files entry. */ +typedef DNDDROPPEDFILESENTRY *PDNDDROPPEDFILESENTRY; + +/** + * Structure for maintaining a "dropped files" directory + * on the host or guest. This will contain all received files & directories + * for a single drag and drop operation. + * + * In case of a failed drag and drop operation this can also + * perform a gentle rollback if required. + */ +typedef struct DNDDROPPEDFILES +{ + /** Open flags. */ + uint32_t m_fOpen; + /** Directory handle for drop directory. */ + RTDIR m_hDir; + /** Absolute path to drop directory. */ + char *pszPathAbs; + /** List for holding created directories in the case of a rollback. */ + RTLISTANCHOR m_lstDirs; + /** List for holding created files in the case of a rollback. */ + RTLISTANCHOR m_lstFiles; +} DNDDROPPEDFILES; +/** Pointer to a DnD dropped files directory. */ +typedef DNDDROPPEDFILES *PDNDDROPPEDFILES; + +int DnDDroppedFilesInit(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesInitEx(PDNDDROPPEDFILES pDF, const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags); +void DnDDroppedFilesDestroy(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesAddFile(PDNDDROPPEDFILES pDF, const char *pszFile); +int DnDDroppedFilesAddDir(PDNDDROPPEDFILES pDF, const char *pszDir); +int DnDDroppedFilesClose(PDNDDROPPEDFILES pDF); +bool DnDDroppedFilesIsOpen(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesOpenEx(PDNDDROPPEDFILES pDF, const char *pszPath, DNDURIDROPPEDFILEFLAGS fFlags); +int DnDDroppedFilesOpenTemp(PDNDDROPPEDFILES pDF, DNDURIDROPPEDFILEFLAGS fFlags); +const char *DnDDroppedFilesGetDirAbs(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesReopen(PDNDDROPPEDFILES pDF); +int DnDDroppedFilesReset(PDNDDROPPEDFILES pDF, bool fDelete); +int DnDDroppedFilesRollback(PDNDDROPPEDFILES pDF); + +const char *DnDHostMsgToStr(uint32_t uMsg); +const char *DnDGuestMsgToStr(uint32_t uMsg); +const char *DnDActionToStr(VBOXDNDACTION uAction); + char *DnDActionListToStrA(VBOXDNDACTIONLIST fActionList); +const char *DnDStateToStr(VBOXDNDSTATE enmState); + +bool DnDMIMEHasFileURLs(const char *pcszFormat, size_t cchFormatMax); +bool DnDMIMENeedsDropDir(const char *pcszFormat, size_t cchFormatMax); + +int DnDPathValidate(const char *pcszPath, bool fMustExist); + +/** DnD path conversion flags. */ +typedef uint32_t DNDPATHCONVERTFLAGS; + +/** No flags specified. + * This will convert the path to the universal tansport style. */ +#define DNDPATHCONVERT_FLAGS_TRANSPORT 0 +/** Converts the path to a OS-dependent path. */ +#define DNDPATHCONVERT_FLAGS_TO_DOS RT_BIT(0) + +/** Mask of all valid DnD path conversion flags. */ +#define DNDPATHCONVERT_FLAGS_VALID_MASK UINT32_C(0x1) + +int DnDPathConvert(char *pszPath, size_t cbPath, DNDPATHCONVERTFLAGS fFlags); +int DnDPathSanitizeFileName(char *pszPath, size_t cbPath); +int DnDPathRebase(const char *pcszPathAbs, const char *pcszBaseOld, const char *pcszBaseNew, char **ppszPath); + +/** DnDTransferObject flags. */ +typedef uint32_t DNDTRANSFEROBJECTFLAGS; + +/** No flags specified. */ +#define DNDTRANSFEROBJECT_FLAGS_NONE 0 + +/** Mask of all valid DnD transfer object flags. */ +#define DNDTRANSFEROBJECT_FLAGS_VALID_MASK UINT32_C(0x0) + +/** + * Enumeration for specifying a transfer object type. + */ +typedef enum DNDTRANSFEROBJTYPE +{ + /** Unknown type, do not use. */ + DNDTRANSFEROBJTYPE_UNKNOWN = 0, + /** Object is a file. */ + DNDTRANSFEROBJTYPE_FILE, + /** Object is a directory. */ + DNDTRANSFEROBJTYPE_DIRECTORY, + /** The usual 32-bit hack. */ + DNDTRANSFEROBJTYPE_32BIT_HACK = 0x7fffffff +} DNDTRANSFEROBJTYPE; + +/** + * Enumeration for specifying a path style. + */ +typedef enum DNDTRANSFEROBJPATHSTYLE +{ + /** Transport style (UNIX-y), the default. */ + DNDTRANSFEROBJPATHSTYLE_TRANSPORT = 0, + /** DOS style, containing back slashes. */ + DNDTRANSFEROBJPATHSTYLE_DOS, + /** The usual 32-bit hack. */ + DNDTRANSFEROBJPATHSTYLE_32BIT_HACK = 0x7fffffff +} DNDTRANSFEROBJPATHSTYLE; + +/** + * Structure for keeping a DnD transfer object. + */ +typedef struct DNDTRANSFEROBJECT +{ + RTLISTNODE Node; + /** The object's type. */ + DNDTRANSFEROBJTYPE enmType; + /** Index (in characters, UTF-8) at which the first destination segment starts. */ + uint16_t idxDst; + /** Allocated path. Includdes the absolute source path (if any) + destination segments. + * Transport (IPRT) style. */ + char *pszPath; + + /** Union containing data depending on the object's type. */ + union + { + /** Structure containing members for objects that + * are files. */ + struct + { + /** File handle. */ + RTFILE hFile; + /** File system object information of this file. */ + RTFSOBJINFO objInfo; + /** Bytes to proces for reading/writing. */ + uint64_t cbToProcess; + /** Bytes processed reading/writing. */ + uint64_t cbProcessed; + } File; + struct + { + /** Directory handle. */ + RTDIR hDir; + /** File system object information of this directory. */ + RTFSOBJINFO objInfo; + } Dir; + } u; +} DNDTRANSFEROBJECT; +/** Pointer to a DnD transfer object. */ +typedef DNDTRANSFEROBJECT *PDNDTRANSFEROBJECT; + +int DnDTransferObjectInit(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectInitEx(PDNDTRANSFEROBJECT pObj, DNDTRANSFEROBJTYPE enmType, const char *pcszPathSrcAbs, const char *pcszPathDst); +void DnDTransferObjectDestroy(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectClose(PDNDTRANSFEROBJECT pObj); +void DnDTransferObjectReset(PDNDTRANSFEROBJECT pObj); +const char *DnDTransferObjectGetSourcePath(PDNDTRANSFEROBJECT pObj); +const char *DnDTransferObjectGetDestPath(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectGetDestPathEx(PDNDTRANSFEROBJECT pObj, DNDTRANSFEROBJPATHSTYLE enmStyle, char *pszBuf, size_t cbBuf); +RTFMODE DnDTransferObjectGetMode(PDNDTRANSFEROBJECT pObj); +uint64_t DnDTransferObjectGetProcessed(PDNDTRANSFEROBJECT pObj); +uint64_t DnDTransferObjectGetSize(PDNDTRANSFEROBJECT pObj); +DNDTRANSFEROBJTYPE DnDTransferObjectGetType(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectSetSize(PDNDTRANSFEROBJECT pObj, uint64_t cbSize); +bool DnDTransferObjectIsComplete(PDNDTRANSFEROBJECT pObj); +bool DnDTransferObjectIsOpen(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectOpen(PDNDTRANSFEROBJECT pObj, uint64_t fOpen, RTFMODE fMode, DNDTRANSFEROBJECTFLAGS fFlags); +int DnDTransferObjectQueryInfo(PDNDTRANSFEROBJECT pObj); +int DnDTransferObjectRead(PDNDTRANSFEROBJECT pObj, void *pvBuf, size_t cbBuf, uint32_t *pcbRead); +int DnDTransferObjectWrite(PDNDTRANSFEROBJECT pObj, const void *pvBuf, size_t cbBuf, uint32_t *pcbWritten); + +/** Defines the default chunk size of DnD data transfers. + * Supported on all (older) Guest Additions which also support DnD. */ +#define DND_DEFAULT_CHUNK_SIZE _64K + +/** Separator for a formats list. */ +#define DND_FORMATS_SEPARATOR_STR "\r\n" + +/** Default URI list path separator, if not specified otherwise. + * + * This is there for hysterical raisins, to not break older Guest Additions. + ** @todo Get rid of this. */ +#define DND_PATH_SEPARATOR_STR "\r\n" + +/** DnDTransferList flags. */ +typedef uint32_t DNDTRANSFERLISTFLAGS; + +/** No flags specified. */ +#define DNDTRANSFERLIST_FLAGS_NONE 0 +/** Enables recurisve directory handling. */ +#define DNDTRANSFERLIST_FLAGS_RECURSIVE RT_BIT(0) +/** Resolve all symlinks. Currently not supported and will be ignored. */ +#define DNDTRANSFERLIST_FLAGS_RESOLVE_SYMLINKS RT_BIT(1) +/** Keep the files + directory entries open while + * being in this list. */ +#define DNDTRANSFERLIST_FLAGS_KEEP_OPEN RT_BIT(2) +/** Lazy loading: Only enumerate sub directories when needed. Not implemented yet. + ** @todo Implement lazy loading. */ +#define DNDTRANSFERLIST_FLAGS_LAZY RT_BIT(3) + +/** Mask of all valid DnD transfer list flags. */ +#define DNDTRANSFERLIST_FLAGS_VALID_MASK UINT32_C(0xF) + +/** + * Enumeration for specifying a transfer list format. + */ +typedef enum DNDTRANSFERLISTFMT +{ + /** Unknown format, do not use. */ + DNDTRANSFERLISTFMT_UNKNOWN = 0, + /** Native format. */ + DNDTRANSFERLISTFMT_NATIVE, + /** URI format. */ + DNDTRANSFERLISTFMT_URI, + /** The usual 32-bit hack. */ + DNDTRANSFERLISTFMT_32BIT_HACK = 0x7fffffff +} DNDTRANSFERLISTFMT; + +/** + * Structure for keeping a DnD transfer list root entry. + * + * A root entry always is relative to the parent list maintaining it. + */ +typedef struct DNDTRANSFERLISTROOT +{ + /** List node. */ + RTLISTNODE Node; + /** Pointer to the allocated root path. + * - Relative to the list's root path + * - Always ends with a trailing slash + * - Always stored in transport style (UNIX-y). */ + char *pszPathRoot; +} DNDTRANSFERLISTROOT; +/** Pointer to a DnD list root entry. */ +typedef DNDTRANSFERLISTROOT *PDNDTRANSFERLISTROOT; + +/** + * Struct for keeping a DnD transfer list. + * + * All entries must share a common (absolute) root path. For different root paths another transfer list is needed. + */ +typedef struct DNDTRANSFERLIST +{ + /** Absolute root path of this transfer list, in native path style. + * Always ends with a separator. */ + char *pszPathRootAbs; + /** List of all relative (to \a pszPathRootAbs) top-level file/directory entries, of type DNDTRANSFERLISTROOT. + * Note: All paths are stored internally in transport style (UNIX paths) for + * easier conversion/handling! */ + RTLISTANCHOR lstRoot; + /** Total number of all transfer root entries. */ + uint64_t cRoots; + /** List of all transfer objects added, of type DNDTRANSFEROBJECT. + * + * The order of objects being added is crucial for traversing the tree. + * In other words, sub directories must come first before its contents. */ + RTLISTANCHOR lstObj; + /** Total number of all transfer objects. */ + uint64_t cObj; + /** Total size of all transfer objects, that is, the file + * size of all objects (in bytes). + * Note: Do *not* size_t here, as we also want to support large files + * on 32-bit guests. */ + uint64_t cbObjTotal; +} DNDTRANSFERLIST; +/** Pointer to a DNDTRANSFERLIST struct. */ +typedef DNDTRANSFERLIST *PDNDTRANSFERLIST; + +int DnDTransferListInit(PDNDTRANSFERLIST pList); +int DnDTransferListInitEx(PDNDTRANSFERLIST pList, const char *pcszRootPathAbs, DNDTRANSFERLISTFMT enmFmt); +void DnDTransferListDestroy(PDNDTRANSFERLIST pList); +void DnDTransferListReset(PDNDTRANSFERLIST pList); + +int DnDTransferListAppendPath(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pszPath, DNDTRANSFERLISTFLAGS fFlags); +int DnDTransferListAppendPathsFromBuffer(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pszPaths, size_t cbPaths, const char *pcszSeparator, DNDTRANSFERLISTFLAGS fFlags); +int DnDTransferListAppendPathsFromArray(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char * const *papcszPaths, size_t cPaths, DNDTRANSFERLISTFLAGS fFlags); +int DnDTransferListAppendRootsFromBuffer(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pszPaths, size_t cbPaths, const char *pcszSeparator, DNDTRANSFERLISTFLAGS fFlags); +int DnDTransferListAppendRootsFromArray(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char * const *papcszPaths, size_t cPaths, DNDTRANSFERLISTFLAGS fFlags); + +int DnDTransferListGetRootsEx(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, const char *pcszPathBase, const char *pcszSeparator, char **ppszBuffer, size_t *pcbBuffer); +int DnDTransferListGetRoots(PDNDTRANSFERLIST pList, DNDTRANSFERLISTFMT enmFmt, char **ppszBuffer, size_t *pcbBuffer); +uint64_t DnDTransferListGetRootCount(PDNDTRANSFERLIST pList); +const char *DnDTransferListGetRootPathAbs(PDNDTRANSFERLIST pList); + +PDNDTRANSFEROBJECT DnDTransferListObjGetFirst(PDNDTRANSFERLIST pList); +void DnDTransferListObjRemove(PDNDTRANSFERLIST pList, PDNDTRANSFEROBJECT pObj); +void DnDTransferListObjRemoveFirst(PDNDTRANSFERLIST pList); +uint64_t DnDTransferListObjCount(PDNDTRANSFERLIST pList); +uint64_t DnDTransferListObjTotalBytes(PDNDTRANSFERLIST pList); + +#endif /* !VBOX_INCLUDED_GuestHost_DragAndDrop_h */ + diff --git a/include/VBox/GuestHost/DragAndDropDefs.h b/include/VBox/GuestHost/DragAndDropDefs.h new file mode 100644 index 00000000..0968fa8a --- /dev/null +++ b/include/VBox/GuestHost/DragAndDropDefs.h @@ -0,0 +1,112 @@ +/** @file + * Drag and Drop definitions - Common header for host service and guest clients. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_DragAndDropDefs_h +#define VBOX_INCLUDED_GuestHost_DragAndDropDefs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* + * The mode of operations. + */ +#define VBOX_DRAG_AND_DROP_MODE_OFF 0 +#define VBOX_DRAG_AND_DROP_MODE_HOST_TO_GUEST 1 +#define VBOX_DRAG_AND_DROP_MODE_GUEST_TO_HOST 2 +#define VBOX_DRAG_AND_DROP_MODE_BIDIRECTIONAL 3 + +#define VBOX_DND_ACTION_IGNORE UINT32_C(0) +#define VBOX_DND_ACTION_COPY RT_BIT_32(0) +#define VBOX_DND_ACTION_MOVE RT_BIT_32(1) +#define VBOX_DND_ACTION_LINK RT_BIT_32(2) + +/** A single DnD action. */ +typedef uint32_t VBOXDNDACTION; +/** A list of (OR'ed) DnD actions. */ +typedef uint32_t VBOXDNDACTIONLIST; + +#define hasDnDCopyAction(a) ((a) & VBOX_DND_ACTION_COPY) +#define hasDnDMoveAction(a) ((a) & VBOX_DND_ACTION_MOVE) +#define hasDnDLinkAction(a) ((a) & VBOX_DND_ACTION_LINK) + +#define isDnDIgnoreAction(a) ((a) == VBOX_DND_ACTION_IGNORE) +#define isDnDCopyAction(a) ((a) == VBOX_DND_ACTION_COPY) +#define isDnDMoveAction(a) ((a) == VBOX_DND_ACTION_MOVE) +#define isDnDLinkAction(a) ((a) == VBOX_DND_ACTION_LINK) + +/** @def VBOX_DND_FORMATS_DEFAULT + * Default drag'n drop formats. + * Note: If you add new entries here, make sure you test those + * with all supported guest OSes! + */ +#define VBOX_DND_FORMATS_DEFAULT \ + "text/uri-list", \ + /* Text. */ \ + "text/html", \ + "text/plain;charset=utf-8", \ + "text/plain;charset=utf-16", \ + "text/plain", \ + "text/richtext", \ + "UTF8_STRING", \ + "TEXT", \ + "STRING", \ + /* OpenOffice formats. */ \ + /* See: https://wiki.openoffice.org/wiki/Documentation/DevGuide/OfficeDev/Common_Application_Features#OpenOffice.org_Clipboard_Data_Formats */ \ + "application/x-openoffice-embed-source-xml;windows_formatname=\"Star Embed Source (XML)\"", \ + "application/x-openoffice;windows_formatname=\"Bitmap\"" + +/** + * Enumeration for keeping a DnD state. + */ +typedef enum +{ + VBOXDNDSTATE_UNKNOWN = 0, + VBOXDNDSTATE_ENTERED, + VBOXDNDSTATE_LEFT, + VBOXDNDSTATE_QUERY_FORMATS, + VBOXDNDSTATE_QUERY_STATUS, + VBOXDNDSTATE_DRAGGING, + VBOXDNDSTATE_DROP_STARTED, + VBOXDNDSTATE_DROP_ENDED, + VBOXDNDSTATE_CANCELLED, + VBOXDNDSTATE_ERROR +} VBOXDNDSTATE; +/** Pointer to a DnD state. */ +typedef VBOXDNDSTATE *PVBOXDNDSTATE; + +#endif /* !VBOX_INCLUDED_GuestHost_DragAndDropDefs_h */ + diff --git a/include/VBox/GuestHost/GuestControl.h b/include/VBox/GuestHost/GuestControl.h new file mode 100644 index 00000000..3ecbc0a3 --- /dev/null +++ b/include/VBox/GuestHost/GuestControl.h @@ -0,0 +1,236 @@ +/* $Id: GuestControl.h $ */ +/** @file + * Guest Control - Common Guest and Host Code. + * + * @todo r=bird: Just merge this with GuestControlSvc.h! + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_GuestControl_h +#define VBOX_INCLUDED_GuestHost_GuestControl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* Everything defined in this file lives in this namespace. */ +namespace guestControl { + +/** + * Process status when executed in the guest. + */ +enum eProcessStatus +{ + /** Process is in an undefined state. */ + PROC_STS_UNDEFINED = 0, + /** Process has been started. */ + PROC_STS_STARTED = 1, + /** Process terminated normally. */ + PROC_STS_TEN = 2, + /** Process terminated via signal. */ + PROC_STS_TES = 3, + /** Process terminated abnormally. */ + PROC_STS_TEA = 4, + /** Process timed out and was killed. */ + PROC_STS_TOK = 5, + /** Process timed out and was not killed successfully. */ + PROC_STS_TOA = 6, + /** Service/OS is stopping, process was killed. */ + PROC_STS_DWN = 7, + /** Something went wrong (error code in flags). */ + PROC_STS_ERROR = 8 +}; + +/** + * Input flags, set by the host. This is needed for + * handling flags on the guest side. + * Note: Has to match Main's ProcessInputFlag_* flags! + */ +#define GUEST_PROC_IN_FLAG_NONE 0x0 +#define GUEST_PROC_IN_FLAG_EOF RT_BIT(0) + +/** + * Guest session creation flags. + * Only handled internally at the moment. + */ +#define SESSIONCREATIONFLAG_NONE 0x0 + +/** @name DIRREMOVEREC_FLAG_XXX - Guest directory removement flags. + * Essentially using what IPRT's RTDIRRMREC_F_ + * defines have to offer. + * @{ + */ +/** No remove flags specified. */ +#define DIRREMOVEREC_FLAG_NONE UINT32_C(0x0) +/** Recursively deletes the directory contents. */ +#define DIRREMOVEREC_FLAG_RECURSIVE RT_BIT(0) +/** Delete the content of the directory and the directory itself. */ +#define DIRREMOVEREC_FLAG_CONTENT_AND_DIR RT_BIT(1) +/** Only delete the content of the directory, omit the directory it self. */ +#define DIRREMOVEREC_FLAG_CONTENT_ONLY RT_BIT(2) +/** Mask of valid flags. */ +#define DIRREMOVEREC_FLAG_VALID_MASK UINT32_C(0x00000007) +/** @} */ + +/** @name GUEST_PROC_CREATE_FLAG_XXX - Guest process creation flags. + * @note Has to match Main's ProcessCreateFlag_* flags! + * @{ + */ +#define GUEST_PROC_CREATE_FLAG_NONE UINT32_C(0x0) +#define GUEST_PROC_CREATE_FLAG_WAIT_START RT_BIT(0) +#define GUEST_PROC_CREATE_FLAG_IGNORE_ORPHANED RT_BIT(1) +#define GUEST_PROC_CREATE_FLAG_HIDDEN RT_BIT(2) +#define GUEST_PROC_CREATE_FLAG_PROFILE RT_BIT(3) +#define GUEST_PROC_CREATE_FLAG_WAIT_STDOUT RT_BIT(4) +#define GUEST_PROC_CREATE_FLAG_WAIT_STDERR RT_BIT(5) +#define GUEST_PROC_CREATE_FLAG_EXPAND_ARGUMENTS RT_BIT(6) +#define GUEST_PROC_CREATE_FLAG_UNQUOTED_ARGS RT_BIT(7) +/** @} */ + +/** @name GUEST_PROC_OUT_H_XXX - Pipe handle IDs used internally for referencing + * to a certain pipe buffer. + * @{ + */ +#define GUEST_PROC_OUT_H_STDOUT_DEPRECATED 0 /**< Needed for VBox hosts < 4.1.0. */ +#define GUEST_PROC_OUT_H_STDOUT 1 +#define GUEST_PROC_OUT_H_STDERR 2 +/** @} */ + +/** @name PATHRENAME_FLAG_XXX - Guest path rename flags. + * Essentially using what IPRT's RTPATHRENAME_FLAGS_XXX have to offer. + * @{ + */ +/** Do not replace anything. */ +#define PATHRENAME_FLAG_NO_REPLACE UINT32_C(0) +/** This will replace attempt any target which isn't a directory. */ +#define PATHRENAME_FLAG_REPLACE RT_BIT(0) +/** Don't allow symbolic links as part of the path. */ +#define PATHRENAME_FLAG_NO_SYMLINKS RT_BIT(1) +/** Mask of valid flags. */ +#define PATHRENAME_FLAG_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** @name GUEST_SHUTDOWN_FLAG_XXX - Guest shutdown flags. + * Must match Main's GuestShutdownFlag_ definitions. + * @{ + */ +#define GUEST_SHUTDOWN_FLAG_NONE UINT32_C(0) +#define GUEST_SHUTDOWN_FLAG_POWER_OFF RT_BIT(0) +#define GUEST_SHUTDOWN_FLAG_REBOOT RT_BIT(1) +#define GUEST_SHUTDOWN_FLAG_FORCE RT_BIT(2) +/** @} */ + +/** @name Defines for default (initial) guest process buffer lengths. + * Note: These defaults were the maximum values before; so be careful when raising those in order to + * not break running with older Guest Additions. + * @{ + */ +#define GUEST_PROC_DEF_CMD_LEN _1K +#define GUEST_PROC_DEF_ARGS_LEN _1K +#define GUEST_PROC_DEF_ENV_LEN _1K +#define GUEST_PROC_DEF_USER_LEN 128 +#define GUEST_PROC_DEF_PASSWORD_LEN 128 +#define GUEST_PROC_DEF_DOMAIN_LEN 256 +/** @} */ + +/** @name Defines for maximum guest process buffer lengths. + * @{ + */ +#define GUEST_PROC_MAX_CMD_LEN _1M +#define GUEST_PROC_MAX_ARGS_LEN _2M +#define GUEST_PROC_MAX_ENV_LEN _4M +#define GUEST_PROC_MAX_USER_LEN _64K +#define GUEST_PROC_MAX_PASSWORD_LEN _64K +#define GUEST_PROC_MAX_DOMAIN_LEN _64K +/** @} */ + +/** @name Internal tools built into VBoxService which are used in order + * to accomplish tasks host<->guest. + * @{ + */ +#define VBOXSERVICE_TOOL_CAT "vbox_cat" +#define VBOXSERVICE_TOOL_LS "vbox_ls" +#define VBOXSERVICE_TOOL_RM "vbox_rm" +#define VBOXSERVICE_TOOL_MKDIR "vbox_mkdir" +#define VBOXSERVICE_TOOL_MKTEMP "vbox_mktemp" +#define VBOXSERVICE_TOOL_STAT "vbox_stat" +/** @} */ + +/** Special process exit codes for "vbox_cat". */ +typedef enum VBOXSERVICETOOLBOX_CAT_EXITCODE +{ + VBOXSERVICETOOLBOX_CAT_EXITCODE_ACCESS_DENIED = RTEXITCODE_END, + VBOXSERVICETOOLBOX_CAT_EXITCODE_FILE_NOT_FOUND, + VBOXSERVICETOOLBOX_CAT_EXITCODE_PATH_NOT_FOUND, + VBOXSERVICETOOLBOX_CAT_EXITCODE_SHARING_VIOLATION, + VBOXSERVICETOOLBOX_CAT_EXITCODE_IS_A_DIRECTORY, + /** The usual 32-bit type hack. */ + VBOXSERVICETOOLBOX_CAT_32BIT_HACK = 0x7fffffff +} VBOXSERVICETOOLBOX_CAT_EXITCODE; + +/** Special process exit codes for "vbox_stat". */ +typedef enum VBOXSERVICETOOLBOX_STAT_EXITCODE +{ + VBOXSERVICETOOLBOX_STAT_EXITCODE_ACCESS_DENIED = RTEXITCODE_END, + VBOXSERVICETOOLBOX_STAT_EXITCODE_FILE_NOT_FOUND, + VBOXSERVICETOOLBOX_STAT_EXITCODE_PATH_NOT_FOUND, + VBOXSERVICETOOLBOX_STAT_EXITCODE_NET_PATH_NOT_FOUND, + VBOXSERVICETOOLBOX_STAT_EXITCODE_INVALID_NAME, + /** The usual 32-bit type hack. */ + VBOXSERVICETOOLBOX_STAT_32BIT_HACK = 0x7fffffff +} VBOXSERVICETOOLBOX_STAT_EXITCODE; + +/** + * Input status, reported by the client. + */ +enum eInputStatus +{ + /** Input is in an undefined state. */ + INPUT_STS_UNDEFINED = 0, + /** Input was written (partially, see cbProcessed). */ + INPUT_STS_WRITTEN = 1, + /** Input failed with an error (see flags for rc). */ + INPUT_STS_ERROR = 20, + /** Process has abandoned / terminated input handling. */ + INPUT_STS_TERMINATED = 21, + /** Too much input data. */ + INPUT_STS_OVERFLOW = 30 +}; + + + +} /* namespace guestControl */ + +#endif /* !VBOX_INCLUDED_GuestHost_GuestControl_h */ + diff --git a/include/VBox/GuestHost/HGCMMock.h b/include/VBox/GuestHost/HGCMMock.h new file mode 100644 index 00000000..3aabed57 --- /dev/null +++ b/include/VBox/GuestHost/HGCMMock.h @@ -0,0 +1,804 @@ +/* $Id: HGCMMock.h $ */ +/** @file + * HGCMMock.h: Mocking framework for testing HGCM-based host services + + * Vbgl code on the host side. + * + * Goal is to run host service + Vbgl code as unmodified as + * possible as part of testcases to gain test coverage which + * otherwise wouldn't possible for heavily user-centric features + * like Shared Clipboard or drag'n drop (DnD). + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_HGCMMock_h +#define VBOX_INCLUDED_GuestHost_HGCMMock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + + +/********************************************************************************************************************************* +* Definitions. * +*********************************************************************************************************************************/ + +#if defined(IN_RING3) /* Only R3 parts implemented so far. */ + +RT_C_DECLS_BEGIN + +DECLCALLBACK(DECLEXPORT(int)) VBoxHGCMSvcLoad(VBOXHGCMSVCFNTABLE *ptable); + +RT_C_DECLS_END + +# define VBGLR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL + +/** Simple call handle structure for the guest call completion callback. */ +typedef struct VBOXHGCMCALLHANDLE_TYPEDEF +{ + /** Where to store the result code on call completion. */ + int32_t rc; +} VBOXHGCMCALLHANDLE_TYPEDEF; + +/** + * Enumeration for a HGCM mock function type. + */ +typedef enum TSTHGCMMOCKFNTYPE +{ + TSTHGCMMOCKFNTYPE_NONE = 0, + TSTHGCMMOCKFNTYPE_CONNECT, + TSTHGCMMOCKFNTYPE_DISCONNECT, + TSTHGCMMOCKFNTYPE_CALL, + TSTHGCMMOCKFNTYPE_HOST_CALL +} TSTHGCMMOCKFNTYPE; + +/** Pointer to a mock HGCM service. */ +typedef struct TSTHGCMMOCKSVC *PTSTHGCMMOCKSVC; + +/** + * Structure for mocking a server-side HGCM client. + */ +typedef struct TSTHGCMMOCKCLIENT +{ + /** Pointer to to mock service instance this client belongs to. */ + PTSTHGCMMOCKSVC pSvc; + /** Assigned HGCM client ID. */ + uint32_t idClient; + /** Opaque pointer to service-specific client data. + * Can be NULL if not being used. */ + void *pvClient; + /** Size (in bytes) of \a pvClient. */ + size_t cbClient; + /** The client's current HGCM call handle. */ + VBOXHGCMCALLHANDLE_TYPEDEF hCall; + /** Whether the current client call has an asynchronous + * call pending or not. */ + bool fAsyncExec; + /** Event semaphore to signal call completion. */ + RTSEMEVENT hEvent; +} TSTHGCMMOCKCLIENT; +/** Pointer to a mock HGCM client. */ +typedef TSTHGCMMOCKCLIENT *PTSTHGCMMOCKCLIENT; + +/** + * Structure for keeping HGCM mock function parameters. + */ +typedef struct TSTHGCMMOCKFN +{ + /** List node for storing this struct into a queue. */ + RTLISTNODE Node; + /** Function type. */ + TSTHGCMMOCKFNTYPE enmType; + /** Pointer to associated client. */ + PTSTHGCMMOCKCLIENT pClient; + /** Union keeping function-specific parameters, + * depending on \a enmType. */ + union + { + struct + { + int32_t iFunc; + uint32_t cParms; + PVBOXHGCMSVCPARM pParms; + VBOXHGCMCALLHANDLE hCall; + } Call; + struct + { + int32_t iFunc; + uint32_t cParms; + PVBOXHGCMSVCPARM pParms; + } HostCall; + } u; +} TSTHGCMMOCKFN; +/** Pointer to a HGCM mock function parameters structure. */ +typedef TSTHGCMMOCKFN *PTSTHGCMMOCKFN; + +/** + * Structure for keeping a HGCM mock service instance. + */ +typedef struct TSTHGCMMOCKSVC +{ + /** HGCM helper table to use. */ + VBOXHGCMSVCHELPERS fnHelpers; + /** HGCM service function table to use. */ + VBOXHGCMSVCFNTABLE fnTable; + /** Next HGCM client ID to assign. + * 0 is considered as being invalid. */ + HGCMCLIENTID uNextClientId; + /** Size (in bytes) of opaque pvClient area to reserve + * for a connected client. */ + size_t cbClient; + /** Array of connected HGCM mock clients. + * Currently limited to 4 clients maximum. */ + TSTHGCMMOCKCLIENT aHgcmClient[4]; + /** Thread handle for the service's main loop. */ + RTTHREAD hThread; + /** Event semaphore for signalling a message + * queue change. */ + RTSEMEVENT hEventQueue; + /** Event semaphore for clients connecting to the server. */ + RTSEMEVENT hEventConnect; + /** Number of current host calls being served. + * Currently limited to one call at a time. */ + uint8_t cHostCallers; + /** Result code of last returned host call. */ + int rcHostCall; + /** Event semaphore for host calls. */ + RTSEMEVENT hEventHostCall; + /** List (queue) of function calls to process. */ + RTLISTANCHOR lstCall; + /** Shutdown indicator flag. */ + volatile bool fShutdown; +} TSTHGCMMOCKSVC; + +/** Static HGCM service to mock. */ +static TSTHGCMMOCKSVC s_tstHgcmSvc; + +/********************************************************************************************************************************* +* Prototypes. * +*********************************************************************************************************************************/ +PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void); +PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout); +PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc); +int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient); +int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc); +int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc); +int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc); + +int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]); + +VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient); +VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient); +VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo); + + + +/********************************************************************************************************************************* +* Internal functions * +*********************************************************************************************************************************/ + +/** + * Initializes a HGCM mock client. + * + * @return VBox status code. + * @param pClient Client instance to initialize. + * @param idClient HGCM client ID to assign. + * @param cbClient Size (in bytes) of service-specific (opaque) client data to allocate. + */ +static int tstHgcmMockClientInit(PTSTHGCMMOCKCLIENT pClient, uint32_t idClient, size_t cbClient) +{ + RT_BZERO(pClient, sizeof(TSTHGCMMOCKCLIENT)); + + pClient->idClient = idClient; + if (cbClient) + { + pClient->pvClient = RTMemAllocZ(cbClient); + AssertPtrReturn(pClient->pvClient, VERR_NO_MEMORY); + pClient->cbClient = cbClient; + } + + return RTSemEventCreate(&pClient->hEvent); +} + +/** + * Destroys a HGCM mock client. + * + * @return VBox status code. + * @param pClient Client instance to destroy. + */ +static int tstHgcmMockClientDestroy(PTSTHGCMMOCKCLIENT pClient) +{ + int rc = RTSemEventDestroy(pClient->hEvent); + if (RT_SUCCESS(rc)) + { + if (pClient->pvClient) + { + Assert(pClient->cbClient); + RTMemFree(pClient->pvClient); + pClient->pvClient = NULL; + pClient->cbClient = 0; + } + + pClient->hEvent = NIL_RTSEMEVENT; + } + + return rc; +} + +/* @copydoc VBOXHGCMSVCFNTABLE::pfnConnect */ +static DECLCALLBACK(int) tstHgcmMockSvcConnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t *pidClient) +{ + RT_NOREF(pvService); + + PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN)); + AssertPtrReturn(pFn, VERR_NO_MEMORY); + + PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[pSvc->uNextClientId]; + + int rc = tstHgcmMockClientInit(pClient, pSvc->uNextClientId, pSvc->cbClient); + if (RT_FAILURE(rc)) + return rc; + + pFn->enmType = TSTHGCMMOCKFNTYPE_CONNECT; + pFn->pClient = pClient; + + RTListAppend(&pSvc->lstCall, &pFn->Node); + pFn = NULL; /* Thread takes ownership now. */ + + int rc2 = RTSemEventSignal(pSvc->hEventQueue); + AssertRCReturn(rc2, rc2); + rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC); + AssertRCReturn(rc2, rc2); + + ASMAtomicIncU32(&pSvc->uNextClientId); + + rc2 = RTSemEventSignal(pSvc->hEventConnect); + AssertRCReturn(rc2, rc2); + + *pidClient = pClient->idClient; + + return VINF_SUCCESS; +} + +/* @copydoc VBOXHGCMSVCFNTABLE::pfnDisconnect */ +static DECLCALLBACK(int) tstHgcmMockSvcDisconnect(PTSTHGCMMOCKSVC pSvc, void *pvService, uint32_t idClient) +{ + RT_NOREF(pvService); + + PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient]; + + PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN)); + AssertPtrReturn(pFn, VERR_NO_MEMORY); + + pFn->enmType = TSTHGCMMOCKFNTYPE_DISCONNECT; + pFn->pClient = pClient; + + RTListAppend(&pSvc->lstCall, &pFn->Node); + pFn = NULL; /* Thread takes ownership now. */ + + int rc2 = RTSemEventSignal(pSvc->hEventQueue); + AssertRCReturn(rc2, rc2); + + rc2 = RTSemEventWait(pClient->hEvent, RT_MS_30SEC); + AssertRCReturn(rc2, rc2); + + return tstHgcmMockClientDestroy(pClient); +} + +/* @copydoc VBOXHGCMSVCFNTABLE::pfnCall */ +static DECLCALLBACK(int) tstHgcmMockSvcCall(PTSTHGCMMOCKSVC pSvc, void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient, + int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) +{ + RT_NOREF(pvService, pvClient); + + PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[idClient]; + + PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN)); + AssertPtrReturn(pFn, VERR_NO_MEMORY); + + const size_t cbParms = cParms * sizeof(VBOXHGCMSVCPARM); + + pFn->enmType = TSTHGCMMOCKFNTYPE_CALL; + pFn->pClient = pClient; + + pFn->u.Call.hCall = callHandle; + pFn->u.Call.iFunc = function; + pFn->u.Call.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cbParms); + AssertPtrReturn(pFn->u.Call.pParms, VERR_NO_MEMORY); + pFn->u.Call.cParms = cParms; + + RTListAppend(&pSvc->lstCall, &pFn->Node); + + int rc2 = RTSemEventSignal(pSvc->hEventQueue); + AssertRCReturn(rc2, rc2); + + rc2 = RTSemEventWait(pClient->hEvent, RT_INDEFINITE_WAIT); + AssertRCReturn(rc2, rc2); + + memcpy(paParms, pFn->u.Call.pParms, cbParms); + + return VINF_SUCCESS; /** @todo Return host call rc */ +} + +/* @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall */ +/** Note: Public for also being able to test host calls via testcases. */ +int TstHgcmMockSvcHostCall(PTSTHGCMMOCKSVC pSvc, void *pvService, int32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) +{ + RT_NOREF(pvService); + AssertReturn(pSvc->cHostCallers == 0, VERR_WRONG_ORDER); /* Only one host call at a time. */ + + pSvc->cHostCallers++; + + PTSTHGCMMOCKFN pFn = (PTSTHGCMMOCKFN)RTMemAllocZ(sizeof(TSTHGCMMOCKFN)); + AssertPtrReturn(pFn, VERR_INVALID_POINTER); + + pFn->enmType = TSTHGCMMOCKFNTYPE_HOST_CALL; + pFn->u.HostCall.iFunc = function; + if (cParms) + { + pFn->u.HostCall.pParms = (PVBOXHGCMSVCPARM)RTMemDup(paParms, cParms * sizeof(VBOXHGCMSVCPARM)); + AssertPtrReturn(pFn->u.HostCall.pParms, VERR_NO_MEMORY); + pFn->u.HostCall.cParms = cParms; + } + + RTListAppend(&pSvc->lstCall, &pFn->Node); + pFn = NULL; /* Thread takes ownership now. */ + + int rc2 = RTSemEventSignal(pSvc->hEventQueue); + AssertRC(rc2); + + rc2 = RTSemEventWait(pSvc->hEventHostCall, RT_INDEFINITE_WAIT); + AssertRCReturn(rc2, rc2); + + Assert(pSvc->cHostCallers); + pSvc->cHostCallers--; + + return pSvc->rcHostCall; +} + +/** + * Call completion callback for guest calls. + * + * @return VBox status code. + * @param callHandle Call handle to complete. + * @param rc Return code to return to the caller. + */ +static DECLCALLBACK(int) tstHgcmMockSvcCallComplete(VBOXHGCMCALLHANDLE callHandle, int32_t rc) +{ + PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); + + size_t i = 0; + for (; RT_ELEMENTS(pSvc->aHgcmClient); i++) + { + PTSTHGCMMOCKCLIENT pClient = &pSvc->aHgcmClient[i]; + if (&pClient->hCall == callHandle) /* Slow, but works for now. */ + { + if (rc == VINF_HGCM_ASYNC_EXECUTE) + { + Assert(pClient->fAsyncExec == false); + } + else /* Complete call + notify client. */ + { + callHandle->rc = rc; + + int rc2 = RTSemEventSignal(pClient->hEvent); + AssertRCReturn(rc2, rc2); + } + + return VINF_SUCCESS; + } + } + + return VERR_NOT_FOUND; +} + +/** + * Main thread of HGCM mock service. + * + * @return VBox status code. + * @param hThread Thread handle. + * @param pvUser User-supplied data of type PTSTHGCMMOCKSVC. + */ +static DECLCALLBACK(int) tstHgcmMockSvcThread(RTTHREAD hThread, void *pvUser) +{ + RT_NOREF(hThread); + PTSTHGCMMOCKSVC pSvc = (PTSTHGCMMOCKSVC)pvUser; + + pSvc->uNextClientId = 0; + + pSvc->fnTable.cbSize = sizeof(pSvc->fnTable); + pSvc->fnTable.u32Version = VBOX_HGCM_SVC_VERSION; + + RT_ZERO(pSvc->fnHelpers); + pSvc->fnHelpers.pfnCallComplete = tstHgcmMockSvcCallComplete; + pSvc->fnTable.pHelpers = &pSvc->fnHelpers; + + int rc = VBoxHGCMSvcLoad(&pSvc->fnTable); + if (RT_SUCCESS(rc)) + { + RTThreadUserSignal(hThread); + + for (;;) + { + rc = RTSemEventWait(pSvc->hEventQueue, 10 /* ms */); + if (ASMAtomicReadBool(&pSvc->fShutdown)) + { + rc = VINF_SUCCESS; + break; + } + if (rc == VERR_TIMEOUT) + continue; + + PTSTHGCMMOCKFN pFn = RTListGetFirst(&pSvc->lstCall, TSTHGCMMOCKFN, Node); + if (pFn) + { + switch (pFn->enmType) + { + case TSTHGCMMOCKFNTYPE_CONNECT: + { + rc = pSvc->fnTable.pfnConnect(pSvc->fnTable.pvService, + pFn->pClient->idClient, pFn->pClient->pvClient, + VMMDEV_REQUESTOR_USR_NOT_GIVEN /* fRequestor */, false /* fRestoring */); + + int rc2 = RTSemEventSignal(pFn->pClient->hEvent); + AssertRC(rc2); + break; + } + + case TSTHGCMMOCKFNTYPE_DISCONNECT: + { + rc = pSvc->fnTable.pfnDisconnect(pSvc->fnTable.pvService, + pFn->pClient->idClient, pFn->pClient->pvClient); + + int rc2 = RTSemEventSignal(pFn->pClient->hEvent); + AssertRC(rc2); + break; + } + + case TSTHGCMMOCKFNTYPE_CALL: + { + pSvc->fnTable.pfnCall(NULL, pFn->u.Call.hCall, pFn->pClient->idClient, pFn->pClient->pvClient, + pFn->u.Call.iFunc, pFn->u.Call.cParms, pFn->u.Call.pParms, RTTimeMilliTS()); + + /* Note: Call will be completed in the call completion callback. */ + break; + } + + case TSTHGCMMOCKFNTYPE_HOST_CALL: + { + pSvc->rcHostCall = pSvc->fnTable.pfnHostCall(NULL, pFn->u.HostCall.iFunc, pFn->u.HostCall.cParms, pFn->u.HostCall.pParms); + + int rc2 = RTSemEventSignal(pSvc->hEventHostCall); + AssertRC(rc2); + break; + } + + default: + AssertFailed(); + break; + } + RTListNodeRemove(&pFn->Node); + RTMemFree(pFn); + } + } + } + + return rc; +} + + +/********************************************************************************************************************************* +* Public functions * +*********************************************************************************************************************************/ + +/** + * Returns the pointer to the HGCM mock service instance. + * + * @return Pointer to HGCM mock service instance. + */ +PTSTHGCMMOCKSVC TstHgcmMockSvcInst(void) +{ + return &s_tstHgcmSvc; +} + +/** + * Waits for a HGCM mock client to connect, extended version. + * + * @return Pointer to connected client, or NULL if ran into timeout. + * @param pSvc HGCM mock service instance. + * @param msTimeout Timeout (in ms) to wait for connection. + */ +PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnectEx(PTSTHGCMMOCKSVC pSvc, RTMSINTERVAL msTimeout) +{ + int rc = RTSemEventWait(pSvc->hEventConnect, msTimeout); + if (RT_SUCCESS(rc)) + { + Assert(pSvc->uNextClientId); + return &pSvc->aHgcmClient[pSvc->uNextClientId - 1]; + } + return NULL; +} + +/** + * Waits for a HGCM mock client to connect. + * + * @return Pointer to connected client, or NULL if waiting for connection was aborted. + * @param pSvc HGCM mock service instance. + */ +PTSTHGCMMOCKCLIENT TstHgcmMockSvcWaitForConnect(PTSTHGCMMOCKSVC pSvc) +{ + return TstHgcmMockSvcWaitForConnectEx(pSvc, RT_MS_30SEC); +} + +/** + * Creates a HGCM mock service instance. + * + * @return VBox status code. + * @param pSvc HGCM mock service instance to create. + * @param cbClient Size (in bytes) of service-specific client data to + * allocate for a HGCM mock client. + */ +int TstHgcmMockSvcCreate(PTSTHGCMMOCKSVC pSvc, size_t cbClient) +{ + AssertReturn(cbClient, VERR_INVALID_PARAMETER); + + RT_ZERO(pSvc->aHgcmClient); + pSvc->fShutdown = false; + int rc = RTSemEventCreate(&pSvc->hEventQueue); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventCreate(&pSvc->hEventHostCall); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventCreate(&pSvc->hEventConnect); + if (RT_SUCCESS(rc)) + { + RTListInit(&pSvc->lstCall); + + pSvc->cbClient = cbClient; + } + } + } + + return rc; +} + +/** + * Destroys a HGCM mock service instance. + * + * @return VBox status code. + * @param pSvc HGCM mock service instance to destroy. + */ +int TstHgcmMockSvcDestroy(PTSTHGCMMOCKSVC pSvc) +{ + int rc = RTSemEventDestroy(pSvc->hEventQueue); + if (RT_SUCCESS(rc)) + { + rc = RTSemEventDestroy(pSvc->hEventHostCall); + if (RT_SUCCESS(rc)) + RTSemEventDestroy(pSvc->hEventConnect); + } + return rc; +} + +/** + * Starts a HGCM mock service instance. + * + * @return VBox status code. + * @param pSvc HGCM mock service instance to start. + */ +int TstHgcmMockSvcStart(PTSTHGCMMOCKSVC pSvc) +{ + int rc = RTThreadCreate(&pSvc->hThread, tstHgcmMockSvcThread, pSvc, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, + "MockSvc"); + if (RT_SUCCESS(rc)) + rc = RTThreadUserWait(pSvc->hThread, RT_MS_30SEC); + + return rc; +} + +/** + * Stops a HGCM mock service instance. + * + * @return VBox status code. + * @param pSvc HGCM mock service instance to stop. + */ +int TstHgcmMockSvcStop(PTSTHGCMMOCKSVC pSvc) +{ + ASMAtomicWriteBool(&pSvc->fShutdown, true); + + int rcThread; + int rc = RTThreadWait(pSvc->hThread, RT_MS_30SEC, &rcThread); + if (RT_SUCCESS(rc)) + rc = rcThread; + if (RT_SUCCESS(rc)) + { + pSvc->hThread = NIL_RTTHREAD; + } + + return rc; +} + + +/********************************************************************************************************************************* +* VbglR3 stubs * +*********************************************************************************************************************************/ + +/** + * Connects to an HGCM mock service. + * + * @returns VBox status code + * @param pszServiceName Name of the host service. + * @param pidClient Where to put the client ID on success. The client ID + * must be passed to all the other calls to the service. + */ +VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient) +{ + RT_NOREF(pszServiceName); + + PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); + + return tstHgcmMockSvcConnect(pSvc, pSvc->fnTable.pvService, pidClient); +} + +/** + * Disconnect from an HGCM mock service. + * + * @returns VBox status code. + * @param idClient The client id returned by VbglR3HGCMConnect(). + */ +VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient) +{ + PTSTHGCMMOCKSVC pSvc = TstHgcmMockSvcInst(); + + return tstHgcmMockSvcDisconnect(pSvc, pSvc->fnTable.pvService, idClient); +} + +/** + * Makes a fully prepared HGCM call to an HGCM mock service. + * + * @returns VBox status code. + * @param pInfo Fully prepared HGCM call info. + * @param cbInfo Size of the info. This may sometimes be larger than + * what the parameter count indicates because of + * parameter changes between versions and such. + */ +VBGLR3DECL(int) VbglR3HGCMCall(PVBGLIOCHGCMCALL pInfo, size_t cbInfo) +{ + RT_NOREF(cbInfo); + + AssertMsg(pInfo->Hdr.cbIn == cbInfo, ("cbIn=%#x cbInfo=%#zx\n", pInfo->Hdr.cbIn, cbInfo)); + AssertMsg(pInfo->Hdr.cbOut == cbInfo, ("cbOut=%#x cbInfo=%#zx\n", pInfo->Hdr.cbOut, cbInfo)); + Assert(sizeof(*pInfo) + pInfo->cParms * sizeof(HGCMFunctionParameter) <= cbInfo); + + HGCMFunctionParameter *offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo); + PVBOXHGCMSVCPARM paDstParms = (PVBOXHGCMSVCPARM)RTMemAlloc(pInfo->cParms * sizeof(VBOXHGCMSVCPARM)); + + uint16_t i = 0; + for (; i < pInfo->cParms; i++) + { + switch (offSrcParms->type) + { + case VMMDevHGCMParmType_32bit: + { + paDstParms[i].type = VBOX_HGCM_SVC_PARM_32BIT; + paDstParms[i].u.uint32 = offSrcParms->u.value32; + break; + } + + case VMMDevHGCMParmType_64bit: + { + paDstParms[i].type = VBOX_HGCM_SVC_PARM_64BIT; + paDstParms[i].u.uint64 = offSrcParms->u.value64; + break; + } + + case VMMDevHGCMParmType_LinAddr: + { + paDstParms[i].type = VBOX_HGCM_SVC_PARM_PTR; + paDstParms[i].u.pointer.addr = (void *)offSrcParms->u.LinAddr.uAddr; + paDstParms[i].u.pointer.size = offSrcParms->u.LinAddr.cb; + break; + } + + default: + AssertFailed(); + break; + } + + offSrcParms++; + } + + PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst(); + + int rc2 = tstHgcmMockSvcCall(pSvc, pSvc->fnTable.pvService, &pSvc->aHgcmClient[pInfo->u32ClientID].hCall, + pInfo->u32ClientID, pSvc->aHgcmClient[pInfo->u32ClientID].pvClient, + pInfo->u32Function, pInfo->cParms, paDstParms); + if (RT_SUCCESS(rc2)) + { + offSrcParms = VBGL_HGCM_GET_CALL_PARMS(pInfo); + + for (i = 0; i < pInfo->cParms; i++) + { + paDstParms[i].type = offSrcParms->type; + switch (paDstParms[i].type) + { + case VMMDevHGCMParmType_32bit: + offSrcParms->u.value32 = paDstParms[i].u.uint32; + break; + + case VMMDevHGCMParmType_64bit: + offSrcParms->u.value64 = paDstParms[i].u.uint64; + break; + + case VMMDevHGCMParmType_LinAddr: + { + offSrcParms->u.LinAddr.cb = paDstParms[i].u.pointer.size; + break; + } + + default: + AssertFailed(); + break; + } + + offSrcParms++; + } + } + + RTMemFree(paDstParms); + + if (RT_SUCCESS(rc2)) + rc2 = pSvc->aHgcmClient[pInfo->u32ClientID].hCall.rc; + + return rc2; +} + +#endif /* IN_RING3 */ + +#endif /* !VBOX_INCLUDED_GuestHost_HGCMMock_h */ diff --git a/include/VBox/GuestHost/HGCMMockUtils.h b/include/VBox/GuestHost/HGCMMockUtils.h new file mode 100644 index 00000000..8eb9f943 --- /dev/null +++ b/include/VBox/GuestHost/HGCMMockUtils.h @@ -0,0 +1,428 @@ +/* $Id */ +/** @file + * HGCMMockUtils.h: Utility functions for the HGCM Mocking framework. + * + * The utility functions are optional to the actual HGCM Mocking framework and + * can support testcases which require a more advanced setup. + * + * With this one can setup host and guest side threads, which in turn can simulate + * specific host (i.e. HGCM service) + guest (i.e. like in the Guest Addditions + * via VbglR3) scenarios. + * + * Glossary: + * + * Host thread: + * - The host thread is used as part of the actual HGCM service being tested and + * provides callbacks (@see TSTHGCMUTILSHOSTCALLBACKS) for the unit test. + * Guest thread: + * - The guest thread is used as part of the guest side and mimics + * VBoxClient / VBoxTray / VBoxService parts. (i.e. for VbglR3 calls). + * Task: + * - A task is the simplest unit of test execution and used between the guest + * and host mocking threads. + * + ** @todo Add TstHGCMSimpleHost / TstHGCMSimpleGuest wrappers along those lines: + * Callback.pfnOnClientConnected = tstOnHostClientConnected() + * TstHGCMSimpleHostInitAndStart(&Callback) + * Callback.pfnOnConnected = tstOnGuestConnected() + * TstHGCMSimpleClientInitAndStart(&Callback) + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_HGCMMockUtils_h +#define VBOX_INCLUDED_GuestHost_HGCMMockUtils_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +#include +#include + + +#if defined(IN_RING3) /* Only R3 parts implemented so far. */ + +/** Pointer to a HGCM Mock utils context. */ +typedef struct TSTHGCMUTILSCTX *PTSTHGCMUTILSCTX; + +/** + * Structure for keeping a HGCM Mock utils host service callback table. + */ +typedef struct TSTHGCMUTILSHOSTCALLBACKS +{ + DECLCALLBACKMEMBER(int, pfnOnClientConnected,(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKCLIENT pClient, void *pvUser)); +} TSTHGCMUTILSHOSTCALLBACKS; +/** Pointer to a HGCM Mock utils host callbacks table. */ +typedef TSTHGCMUTILSHOSTCALLBACKS *PTSTHGCMUTILSHOSTCALLBACKS; + +/** + * Structure for keeping a generic HGCM Mock utils task. + * + * A task is a single test unit / entity. + */ +typedef struct TSTHGCMUTILSTASK +{ + /** Completion event. */ + RTSEMEVENT hEvent; + /** Completion rc. + * Set to VERR_IPE_UNINITIALIZED_STATUS if not completed yet. */ + int rcCompleted; + /** Expected completion rc. */ + int rcExpected; + /** Pointer to opaque (testcase-specific) task parameters. + * Might be NULL if not needed / used. */ + void *pvUser; +} TSTHGCMUTILSTASK; +/** Pointer to a HGCM Mock utils task. */ +typedef TSTHGCMUTILSTASK *PTSTHGCMUTILSTASK; + +/** Callback function for HGCM Mock utils threads. */ +typedef DECLCALLBACKTYPE(int, FNTSTHGCMUTILSTHREAD,(PTSTHGCMUTILSCTX pCtx, void *pvUser)); +/** Pointer to a HGCM Mock utils guest thread callback. */ +typedef FNTSTHGCMUTILSTHREAD *PFNTSTHGCMUTILSTHREAD; + +/** + * Structure for keeping a HGCM Mock utils context. + */ +typedef struct TSTHGCMUTILSCTX +{ + /** Pointer to the HGCM Mock service instance to use. */ + PTSTHGCMMOCKSVC pSvc; + /** Currently we only support one task at a time. */ + TSTHGCMUTILSTASK Task; + struct + { + RTTHREAD hThread; + volatile bool fShutdown; + PFNTSTHGCMUTILSTHREAD pfnThread; + void *pvUser; + } Guest; + struct + { + RTTHREAD hThread; + volatile bool fShutdown; + TSTHGCMUTILSHOSTCALLBACKS Callbacks; + void *pvUser; + } Host; +} TSTHGCMUTILSCTX; + + +/********************************************************************************************************************************* +* Prototypes. * +*********************************************************************************************************************************/ +/** @name Context handling. + * @{ */ +void TstHGCMUtilsCtxInit(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKSVC pSvc); +/** @} */ + +/** @name Task handling. + * @{ */ +PTSTHGCMUTILSTASK TstHGCMUtilsTaskGetCurrent(PTSTHGCMUTILSCTX pCtx); +int TstHGCMUtilsTaskInit(PTSTHGCMUTILSTASK pTask); +void TstHGCMUtilsTaskDestroy(PTSTHGCMUTILSTASK pTask); +int TstHGCMUtilsTaskWait(PTSTHGCMUTILSTASK pTask, RTMSINTERVAL msTimeout); +bool TstHGCMUtilsTaskOk(PTSTHGCMUTILSTASK pTask); +bool TstHGCMUtilsTaskCompleted(PTSTHGCMUTILSTASK pTask); +void TstHGCMUtilsTaskSignal(PTSTHGCMUTILSTASK pTask, int rc); +/** @} */ + +/** @name Threading. + * @{ */ +int TstHGCMUtilsGuestThreadStart(PTSTHGCMUTILSCTX pCtx, PFNTSTHGCMUTILSTHREAD pFnThread, void *pvUser); +int TstHGCMUtilsGuestThreadStop(PTSTHGCMUTILSCTX pCtx); +int TstHGCMUtilsHostThreadStart(PTSTHGCMUTILSCTX pCtx, PTSTHGCMUTILSHOSTCALLBACKS pCallbacks, void *pvUser); +int TstHGCMUtilsHostThreadStop(PTSTHGCMUTILSCTX pCtx); +/** @} */ + + +/********************************************************************************************************************************* + * Context * + ********************************************************************************************************************************/ +/** + * Initializes a HGCM Mock utils context. + * + * @param pCtx Context to intiialize. + * @param pSvc HGCM Mock service instance to use. + */ +void TstHGCMUtilsCtxInit(PTSTHGCMUTILSCTX pCtx, PTSTHGCMMOCKSVC pSvc) +{ + RT_BZERO(pCtx, sizeof(TSTHGCMUTILSCTX)); + + pCtx->pSvc = pSvc; +} + + +/********************************************************************************************************************************* + * Tasks * + ********************************************************************************************************************************/ +/** + * Returns the current task of a HGCM Mock utils context. + * + * @returns Current task of a HGCM Mock utils context. NULL if no current task found. + * @param pCtx HGCM Mock utils context. + */ +PTSTHGCMUTILSTASK TstHGCMUtilsTaskGetCurrent(PTSTHGCMUTILSCTX pCtx) +{ + /* Currently we only support one task at a time. */ + return &pCtx->Task; +} + +/** + * Initializes a HGCM Mock utils task. + * + * @returns VBox status code. + * @param pTask Task to initialize. + */ +int TstHGCMUtilsTaskInit(PTSTHGCMUTILSTASK pTask) +{ + pTask->pvUser = NULL; + pTask->rcCompleted = pTask->rcExpected = VERR_IPE_UNINITIALIZED_STATUS; + return RTSemEventCreate(&pTask->hEvent); +} + +/** + * Destroys a HGCM Mock utils task. + * + * @returns VBox status code. + * @param pTask Task to destroy. + */ +void TstHGCMUtilsTaskDestroy(PTSTHGCMUTILSTASK pTask) +{ + RTSemEventDestroy(pTask->hEvent); +} + +/** + * Waits for a HGCM Mock utils task to complete. + * + * @returns VBox status code. + * @param pTask Task to wait for. + * @param msTimeout Timeout (in ms) to wait. + */ +int TstHGCMUtilsTaskWait(PTSTHGCMUTILSTASK pTask, RTMSINTERVAL msTimeout) +{ + return RTSemEventWait(pTask->hEvent, msTimeout); +} + +/** + * Returns if the HGCM Mock utils task has been completed successfully. + * + * @returns \c true if successful, \c false if not. + * @param pTask Task to check. + */ +bool TstHGCMUtilsTaskOk(PTSTHGCMUTILSTASK pTask) +{ + return pTask->rcCompleted == pTask->rcExpected; +} + +/** + * Returns if the HGCM Mock utils task has been completed (failed or succeeded). + * + * @returns \c true if completed, \c false if (still) running. + * @param pTask Task to check. + */ +bool TstHGCMUtilsTaskCompleted(PTSTHGCMUTILSTASK pTask) +{ + return pTask->rcCompleted != VERR_IPE_UNINITIALIZED_STATUS; +} + +/** + * Signals a HGCM Mock utils task to complete its operation. + * + * @param pTask Task to complete. + * @param rc Task result to set for completion. + */ +void TstHGCMUtilsTaskSignal(PTSTHGCMUTILSTASK pTask, int rc) +{ + AssertMsg(pTask->rcCompleted == VERR_IPE_UNINITIALIZED_STATUS, ("Task already completed\n")); + pTask->rcCompleted = rc; + int rc2 = RTSemEventSignal(pTask->hEvent); + AssertRC(rc2); +} + + +/********************************************************************************************************************************* + * Threading * + ********************************************************************************************************************************/ + +/** + * Thread worker for the guest side thread. + * + * @returns VBox status code. + * @param hThread Thread handle. + * @param pvUser Pointer of type PTSTHGCMUTILSCTX. + * + * @note Runs in the guest thread. + */ +static DECLCALLBACK(int) tstHGCMUtilsGuestThread(RTTHREAD hThread, void *pvUser) +{ + RT_NOREF(hThread); + PTSTHGCMUTILSCTX pCtx = (PTSTHGCMUTILSCTX)pvUser; + AssertPtr(pCtx); + + RTThreadUserSignal(hThread); + + if (pCtx->Guest.pfnThread) + return pCtx->Guest.pfnThread(pCtx, pCtx->Guest.pvUser); + + return VINF_SUCCESS; +} + +/** + * Starts the guest side thread. + * + * @returns VBox status code. + * @param pCtx HGCM Mock utils context to start guest thread for. + * @param pFnThread Pointer to custom thread worker function to call within the guest side thread. + * @param pvUser User-supplied pointer to guest thread context data. Optional and can be NULL. + */ +int TstHGCMUtilsGuestThreadStart(PTSTHGCMUTILSCTX pCtx, PFNTSTHGCMUTILSTHREAD pFnThread, void *pvUser) +{ + pCtx->Guest.pfnThread = pFnThread; + pCtx->Guest.pvUser = pvUser; + + int rc = RTThreadCreate(&pCtx->Guest.hThread, tstHGCMUtilsGuestThread, pCtx, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, + "tstShClGst"); + if (RT_SUCCESS(rc)) + rc = RTThreadUserWait(pCtx->Guest.hThread, RT_MS_30SEC); + + return rc; +} + +/** + * Stops the guest side thread. + * + * @returns VBox status code. + * @param pCtx HGCM Mock utils context to stop guest thread for. + */ +int TstHGCMUtilsGuestThreadStop(PTSTHGCMUTILSCTX pCtx) +{ + ASMAtomicWriteBool(&pCtx->Guest.fShutdown, true); + + int rcThread; + int rc = RTThreadWait(pCtx->Guest.hThread, RT_MS_30SEC, &rcThread); + if (RT_SUCCESS(rc)) + rc = rcThread; + if (RT_SUCCESS(rc)) + pCtx->Guest.hThread = NIL_RTTHREAD; + + return rc; +} + +/** + * Thread worker function for the host side HGCM service. + * + * @returns VBox status code. + * @param hThread Thread handle. + * @param pvUser Pointer of type PTSTHGCMUTILSCTX. + * + * @note Runs in the host service thread. + */ +static DECLCALLBACK(int) tstHGCMUtilsHostThreadWorker(RTTHREAD hThread, void *pvUser) +{ + RT_NOREF(hThread); + PTSTHGCMUTILSCTX pCtx = (PTSTHGCMUTILSCTX)pvUser; + AssertPtr(pCtx); + + int rc = VINF_SUCCESS; + + RTThreadUserSignal(hThread); + + PTSTHGCMMOCKSVC const pSvc = TstHgcmMockSvcInst(); + + for (;;) + { + if (ASMAtomicReadBool(&pCtx->Host.fShutdown)) + break; + + /* Wait for a new (mock) HGCM client to connect. */ + PTSTHGCMMOCKCLIENT pMockClient = TstHgcmMockSvcWaitForConnectEx(pSvc, 100 /* ms */); + if (pMockClient) /* Might be NULL when timed out. */ + { + if (pCtx->Host.Callbacks.pfnOnClientConnected) + /* ignore rc */ pCtx->Host.Callbacks.pfnOnClientConnected(pCtx, pMockClient, pCtx->Host.pvUser); + } + } + + return rc; +} + +/** + * Starts the host side thread. + * + * @returns VBox status code. + * @param pCtx HGCM Mock utils context to start host thread for. + * @param pCallbacks Pointer to host callback table to use. + * @param pvUser User-supplied pointer to reach into the host thread callbacks. + */ +int TstHGCMUtilsHostThreadStart(PTSTHGCMUTILSCTX pCtx, PTSTHGCMUTILSHOSTCALLBACKS pCallbacks, void *pvUser) +{ + memcpy(&pCtx->Host.Callbacks, pCallbacks, sizeof(TSTHGCMUTILSHOSTCALLBACKS)); + pCtx->Host.pvUser = pvUser; + + int rc = RTThreadCreate(&pCtx->Host.hThread, tstHGCMUtilsHostThreadWorker, pCtx, 0, RTTHREADTYPE_DEFAULT, RTTHREADFLAGS_WAITABLE, + "tstShClHst"); + if (RT_SUCCESS(rc)) + rc = RTThreadUserWait(pCtx->Host.hThread, RT_MS_30SEC); + + return rc; +} + +/** + * Stops the host side thread. + * + * @returns VBox status code. + * @param pCtx HGCM Mock utils context to stop host thread for. + */ +int TstHGCMUtilsHostThreadStop(PTSTHGCMUTILSCTX pCtx) +{ + ASMAtomicWriteBool(&pCtx->Host.fShutdown, true); + + int rcThread; + int rc = RTThreadWait(pCtx->Host.hThread, RT_MS_30SEC, &rcThread); + if (RT_SUCCESS(rc)) + rc = rcThread; + if (RT_SUCCESS(rc)) + pCtx->Host.hThread = NIL_RTTHREAD; + + return rc; +} + +#endif /* IN_RING3 */ + +#endif /* !VBOX_INCLUDED_GuestHost_HGCMMockUtils_h */ + diff --git a/include/VBox/GuestHost/Makefile.kup b/include/VBox/GuestHost/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/VBox/GuestHost/SharedClipboard-transfers.h b/include/VBox/GuestHost/SharedClipboard-transfers.h new file mode 100644 index 00000000..32e5b814 --- /dev/null +++ b/include/VBox/GuestHost/SharedClipboard-transfers.h @@ -0,0 +1,993 @@ +/* $Id: SharedClipboard-transfers.h $ */ +/** @file + * Shared Clipboard - Shared transfer functions between host and guest. + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_transfers_h +#define VBOX_INCLUDED_GuestHost_SharedClipboard_transfers_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#include +#include +#include +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP +# include +#endif +#include + +#include +#include + +#include +#include + + +struct SHCLTRANSFER; +/** Pointer to a single shared clipboard transfer */ +typedef struct SHCLTRANSFER *PSHCLTRANSFER; + + +/** @name Shared Clipboard transfer definitions. + * @{ + */ + +/** Defines the maximum length (in chars) a Shared Clipboard transfer path can have. */ +#define SHCL_TRANSFER_PATH_MAX RTPATH_MAX + +/** + * Defines the transfer status codes. + */ +typedef enum +{ + /** No status set. */ + SHCLTRANSFERSTATUS_NONE = 0, + /** The transfer has been initialized but is not running yet. */ + SHCLTRANSFERSTATUS_INITIALIZED, + /** The transfer is active and running. */ + SHCLTRANSFERSTATUS_STARTED, + /** The transfer has been stopped. */ + SHCLTRANSFERSTATUS_STOPPED, + /** The transfer has been canceled. */ + SHCLTRANSFERSTATUS_CANCELED, + /** The transfer has been killed. */ + SHCLTRANSFERSTATUS_KILLED, + /** The transfer ran into an unrecoverable error. */ + SHCLTRANSFERSTATUS_ERROR, + /** The usual 32-bit hack. */ + SHCLTRANSFERSTATUS_32BIT_SIZE_HACK = 0x7fffffff +} SHCLTRANSFERSTATUSENUM; + +/** Defines a transfer status. */ +typedef uint32_t SHCLTRANSFERSTATUS; + +/** @} */ + +/** @name Shared Clipboard handles. + * @{ + */ + +/** A Shared Clipboard list handle. */ +typedef uint64_t SHCLLISTHANDLE; +/** Pointer to a Shared Clipboard list handle. */ +typedef SHCLLISTHANDLE *PSHCLLISTHANDLE; +/** Specifies an invalid Shared Clipboard list handle. + * @todo r=bird: The convention is NIL_SHCLLISTHANDLE. */ +#define SHCLLISTHANDLE_INVALID ((SHCLLISTHANDLE)UINT64_MAX) + +/** A Shared Clipboard object handle. */ +typedef uint64_t SHCLOBJHANDLE; +/** Pointer to a Shared Clipboard object handle. */ +typedef SHCLOBJHANDLE *PSHCLOBJHANDLE; +/** Specifies an invalid Shared Clipboard object handle. + * @todo r=bird: The convention is NIL_SHCLOBJHANDLE. */ +#define SHCLOBJHANDLE_INVALID ((SHCLOBJHANDLE)UINT64_MAX) + +/** @} */ + +/** @name Shared Clipboard open/create flags. + * @{ + */ +/** No flags. Initialization value. */ +#define SHCL_OBJ_CF_NONE UINT32_C(0x00000000) + +#if 0 /* These probably won't be needed either */ +/** Lookup only the object, do not return a handle. All other flags are ignored. */ +#define SHCL_OBJ_CF_LOOKUP UINT32_C(0x00000001) +/** Create/open a directory. */ +#define SHCL_OBJ_CF_DIRECTORY UINT32_C(0x00000004) +#endif + +/** Read/write requested access for the object. */ +#define SHCL_OBJ_CF_ACCESS_MASK_RW UINT32_C(0x00001000) +/** No access requested. */ +#define SHCL_OBJ_CF_ACCESS_NONE UINT32_C(0x00000000) +/** Read access requested. */ +#define SHCL_OBJ_CF_ACCESS_READ UINT32_C(0x00001000) + +/** Requested share access for the object. */ +#define SHCL_OBJ_CF_ACCESS_MASK_DENY UINT32_C(0x00008000) +/** Allow any access. */ +#define SHCL_OBJ_CF_ACCESS_DENYNONE UINT32_C(0x00000000) +/** Do not allow write. */ +#define SHCL_OBJ_CF_ACCESS_DENYWRITE UINT32_C(0x00008000) + +/** Requested access to attributes of the object. */ +#define SHCL_OBJ_CF_ACCESS_MASK_ATTR UINT32_C(0x00010000) +/** No access requested. */ +#define SHCL_OBJ_CF_ACCESS_ATTR_NONE UINT32_C(0x00000000) +/** Read access requested. */ +#define SHCL_OBJ_CF_ACCESS_ATTR_READ UINT32_C(0x00010000) + +/** Valid bits. */ +#define SHCL_OBJ_CF_VALID_MASK UINT32_C(0x00019000) +/** @} */ + +/** + * The available additional information in a SHCLFSOBJATTR object. + * @sa RTFSOBJATTRADD + */ +typedef enum _SHCLFSOBJATTRADD +{ + /** No additional information is available / requested. */ + SHCLFSOBJATTRADD_NOTHING = 1, + /** The additional unix attributes (SHCLFSOBJATTR::u::Unix) are + * available / requested. */ + SHCLFSOBJATTRADD_UNIX, + /** The additional extended attribute size (SHCLFSOBJATTR::u::EASize) is + * available / requested. */ + SHCLFSOBJATTRADD_EASIZE, + /** The last valid item (inclusive). + * The valid range is SHCLFSOBJATTRADD_NOTHING thru + * SHCLFSOBJATTRADD_LAST. */ + SHCLFSOBJATTRADD_LAST = SHCLFSOBJATTRADD_EASIZE, + /** The usual 32-bit hack. */ + SHCLFSOBJATTRADD_32BIT_SIZE_HACK = 0x7fffffff +} SHCLFSOBJATTRADD; + + +/* Assert sizes of the IRPT types we're using below. */ +AssertCompileSize(RTFMODE, 4); +AssertCompileSize(RTFOFF, 8); +AssertCompileSize(RTINODE, 8); +AssertCompileSize(RTTIMESPEC, 8); +AssertCompileSize(RTDEV, 4); +AssertCompileSize(RTUID, 4); + +/** + * Shared Clipboard filesystem object attributes. + * + * @sa RTFSOBJATTR + */ +typedef struct _SHCLFSOBJATTR +{ + /** Mode flags (st_mode). RTFS_UNIX_*, RTFS_TYPE_*, and RTFS_DOS_*. + * @remarks We depend on a number of RTFS_ defines to remain unchanged. + * Fortuntately, these are depending on windows, dos and unix + * standard values, so this shouldn't be much of a pain. */ + RTFMODE fMode; + + /** The additional attributes available. */ + SHCLFSOBJATTRADD enmAdditional; + + /** + * Additional attributes. + * + * Unless explicitly specified to an API, the API can provide additional + * data as it is provided by the underlying OS. + */ + union SHCLFSOBJATTRUNION + { + /** Additional Unix Attributes + * These are available when SHCLFSOBJATTRADD is set in fUnix. + */ + struct SHCLFSOBJATTRUNIX + { + /** The user owning the filesystem object (st_uid). + * This field is ~0U if not supported. */ + RTUID uid; + + /** The group the filesystem object is assigned (st_gid). + * This field is ~0U if not supported. */ + RTGID gid; + + /** Number of hard links to this filesystem object (st_nlink). + * This field is 1 if the filesystem doesn't support hardlinking or + * the information isn't available. + */ + uint32_t cHardlinks; + + /** The device number of the device which this filesystem object resides on (st_dev). + * This field is 0 if this information is not available. */ + RTDEV INodeIdDevice; + + /** The unique identifier (within the filesystem) of this filesystem object (st_ino). + * Together with INodeIdDevice, this field can be used as a OS wide unique id + * when both their values are not 0. + * This field is 0 if the information is not available. */ + RTINODE INodeId; + + /** User flags (st_flags). + * This field is 0 if this information is not available. */ + uint32_t fFlags; + + /** The current generation number (st_gen). + * This field is 0 if this information is not available. */ + uint32_t GenerationId; + + /** The device number of a character or block device type object (st_rdev). + * This field is 0 if the file isn't of a character or block device type and + * when the OS doesn't subscribe to the major+minor device idenfication scheme. */ + RTDEV Device; + } Unix; + + /** + * Extended attribute size. + */ + struct SHCLFSOBJATTREASIZE + { + /** Size of EAs. */ + RTFOFF cb; + } EASize; + + /** Padding the structure to a multiple of 8 bytes. */ + uint64_t au64Padding[5]; + } u; +} SHCLFSOBJATTR; +AssertCompileSize(SHCLFSOBJATTR, 48); +/** Pointer to a Shared Clipboard filesystem object attributes structure. */ +typedef SHCLFSOBJATTR *PSHCLFSOBJATTR; +/** Pointer to a const Shared Clipboard filesystem object attributes structure. */ +typedef const SHCLFSOBJATTR *PCSHCLFSOBJATTR; + +/** + * Shared Clipboard file system object information structure. + * + * @sa RTFSOBJINFO + */ +typedef struct _SHCLFSOBJINFO +{ + /** Logical size (st_size). + * For normal files this is the size of the file. + * For symbolic links, this is the length of the path name contained + * in the symbolic link. + * For other objects this fields needs to be specified. + */ + RTFOFF cbObject; + + /** Disk allocation size (st_blocks * DEV_BSIZE). */ + RTFOFF cbAllocated; + + /** Time of last access (st_atime). + * @remarks Here (and other places) we depend on the IPRT timespec to + * remain unchanged. */ + RTTIMESPEC AccessTime; + + /** Time of last data modification (st_mtime). */ + RTTIMESPEC ModificationTime; + + /** Time of last status change (st_ctime). + * If not available this is set to ModificationTime. + */ + RTTIMESPEC ChangeTime; + + /** Time of file birth (st_birthtime). + * If not available this is set to ChangeTime. + */ + RTTIMESPEC BirthTime; + + /** Attributes. */ + SHCLFSOBJATTR Attr; + +} SHCLFSOBJINFO; +AssertCompileSize(SHCLFSOBJINFO, 96); +/** Pointer to a Shared Clipboard filesystem object information structure. */ +typedef SHCLFSOBJINFO *PSHCLFSOBJINFO; +/** Pointer to a const Shared Clipboard filesystem object information + * structure. */ +typedef const SHCLFSOBJINFO *PCSHCLFSOBJINFO; + +/** + * Structure for keeping object open/create parameters. + */ +typedef struct _SHCLOBJOPENCREATEPARMS +{ + /** Path to object to open / create. */ + char *pszPath; + /** Size (in bytes) of path to to object. */ + uint32_t cbPath; + /** SHCL_OBJ_CF_* */ + uint32_t fCreate; + /** + * Attributes of object to open/create and + * returned actual attributes of opened/created object. + */ + SHCLFSOBJINFO ObjInfo; +} SHCLOBJOPENCREATEPARMS, *PSHCLOBJOPENCREATEPARMS; + +/** + * Structure for keeping a reply message. + */ +typedef struct _SHCLREPLY +{ + /** Message type of type VBOX_SHCL_REPLYMSGTYPE_XXX. */ + uint32_t uType; + /** IPRT result of overall operation. Note: int vs. uint32! */ + uint32_t rc; + union + { + struct + { + SHCLTRANSFERSTATUS uStatus; + } TransferStatus; + struct + { + SHCLLISTHANDLE uHandle; + } ListOpen; + struct + { + SHCLLISTHANDLE uHandle; + } ListClose; + struct + { + SHCLOBJHANDLE uHandle; + } ObjOpen; + struct + { + SHCLOBJHANDLE uHandle; + } ObjClose; + } u; + /** Pointer to optional payload. */ + void *pvPayload; + /** Payload size (in bytes). */ + uint32_t cbPayload; +} SHCLREPLY, *PSHCLREPLY; + +struct _SHCLLISTENTRY; +typedef _SHCLLISTENTRY SHCLLISTENTRY; + +/** Defines a single root list entry. Currently the same as a regular list entry. */ +typedef SHCLLISTENTRY SHCLROOTLISTENTRY; +/** Defines a pointer to a single root list entry. Currently the same as a regular list entry pointer. */ +typedef SHCLROOTLISTENTRY *PSHCLROOTLISTENTRY; + +/** + * Structure for keeping Shared Clipboard root list headers. + */ +typedef struct _SHCLROOTLISTHDR +{ + /** Roots listing flags; unused at the moment. */ + uint32_t fRoots; + /** Number of root list entries. */ + uint32_t cRoots; +} SHCLROOTLISTHDR, *PSHCLROOTLISTHDR; + +/** + * Structure for maintaining a Shared Clipboard root list. + */ +typedef struct _SHCLROOTLIST +{ + /** Root list header. */ + SHCLROOTLISTHDR Hdr; + /** Root list entries. */ + SHCLROOTLISTENTRY *paEntries; +} SHCLROOTLIST, *PSHCLROOTLIST; + +/** + * Structure for maintaining Shared Clipboard list open paramters. + */ +typedef struct _SHCLLISTOPENPARMS +{ + /** Listing flags (see VBOX_SHCL_LIST_FLAG_XXX). */ + uint32_t fList; + /** Size (in bytes) of the filter string. */ + uint32_t cbFilter; + /** Filter string. DOS wilcard-style. */ + char *pszFilter; + /** Size (in bytes) of the listing path. */ + uint32_t cbPath; + /** Listing path (absolute). If empty or NULL the listing's root path will be opened. */ + char *pszPath; +} SHCLLISTOPENPARMS, *PSHCLLISTOPENPARMS; + +/** + * Structure for keeping a Shared Clipboard list header. + */ +typedef struct _SHCLLISTHDR +{ + /** Feature flag(s). Not being used atm. */ + uint32_t fFeatures; + /** Total objects returned. */ + uint64_t cTotalObjects; + /** Total size (in bytes) returned. */ + uint64_t cbTotalSize; +} SHCLLISTHDR, *PSHCLLISTHDR; + +/** + * Structure for a Shared Clipboard list entry. + */ +typedef struct _SHCLLISTENTRY +{ + /** Entry name. */ + char *pszName; + /** Size (in bytes) of entry name. */ + uint32_t cbName; + /** Information flag(s). */ + uint32_t fInfo; + /** Size (in bytes) of the actual list entry. */ + uint32_t cbInfo; + /** Data of the actual list entry. */ + void *pvInfo; +} SHCLLISTENTRY, *PSHCLLISTENTRY; + +/** Maximum length (in UTF-8 characters) of a list entry name. */ +#define SHCLLISTENTRY_MAX_NAME RTPATH_MAX /** @todo Improve this to be more dynamic. */ + +/** + * Structure for maintaining a Shared Clipboard list. + */ +typedef struct _SHCLLIST +{ + /** List header. */ + SHCLLISTHDR Hdr; + /** List entries. */ + SHCLROOTLISTENTRY *paEntries; +} SHCLLIST, *PSHCLLIST; + +/** + * Structure for keeping a Shared Clipboard object data chunk. + */ +typedef struct _SHCLOBJDATACHUNK +{ + /** Handle of object this data chunk is related to. */ + uint64_t uHandle; + /** Pointer to actual data chunk. */ + void *pvData; + /** Size (in bytes) of data chunk. */ + uint32_t cbData; +} SHCLOBJDATACHUNK, *PSHCLOBJDATACHUNK; + +/** + * Structure for handling a single transfer object context. + */ +typedef struct _SHCLCLIENTTRANSFEROBJCTX +{ + SHCLTRANSFER *pTransfer; + SHCLOBJHANDLE uHandle; +} SHCLCLIENTTRANSFEROBJCTX, *PSHCLCLIENTTRANSFEROBJCTX; + +typedef struct _SHCLTRANSFEROBJSTATE +{ + /** How many bytes were processed (read / write) so far. */ + uint64_t cbProcessed; +} SHCLTRANSFEROBJSTATE, *PSHCLTRANSFEROBJSTATE; + +typedef struct _SHCLTRANSFEROBJ +{ + SHCLOBJHANDLE uHandle; + char *pszPathAbs; + SHCLFSOBJINFO objInfo; + SHCLSOURCE enmSource; + SHCLTRANSFEROBJSTATE State; +} SHCLTRANSFEROBJ, *PSHCLTRANSFEROBJ; + +/** + * Enumeration for specifying a Shared Clipboard object type. + */ +typedef enum _SHCLOBJTYPE +{ + /** Invalid object type. */ + SHCLOBJTYPE_INVALID = 0, + /** Object is a directory. */ + SHCLOBJTYPE_DIRECTORY, + /** Object is a file. */ + SHCLOBJTYPE_FILE, + /** Object is a symbolic link. */ + SHCLOBJTYPE_SYMLINK, + /** The usual 32-bit hack. */ + SHCLOBJTYPE_32BIT_SIZE_HACK = 0x7fffffff +} SHCLOBJTYPE; + +/** + * Structure for keeping transfer list handle information. + * This is using to map own (local) handles to the underlying file system. + */ +typedef struct _SHCLLISTHANDLEINFO +{ + /** The list node. */ + RTLISTNODE Node; + /** The list's handle. */ + SHCLLISTHANDLE hList; + /** Type of list handle. */ + SHCLOBJTYPE enmType; + /** Absolute local path of the list object. */ + char *pszPathLocalAbs; + union + { + /** Local data, based on enmType. */ + struct + { + union + { + RTDIR hDir; + RTFILE hFile; + }; + } Local; + } u; +} SHCLLISTHANDLEINFO, *PSHCLLISTHANDLEINFO; + +/** + * Structure for keeping transfer object handle information. + * This is using to map own (local) handles to the underlying file system. + */ +typedef struct _SHCLOBJHANDLEINFO +{ + /** The list node. */ + RTLISTNODE Node; + /** The object's handle. */ + SHCLOBJHANDLE hObj; + /** Type of object handle. */ + SHCLOBJTYPE enmType; + /** Absolute local path of the object. */ + char *pszPathLocalAbs; + union + { + /** Local data, based on enmType. */ + struct + { + union + { + RTDIR hDir; + RTFILE hFile; + }; + } Local; + } u; +} SHCLOBJHANDLEINFO, *PSHCLOBJHANDLEINFO; + +/** + * Structure for keeping a single root list entry. + */ +typedef struct _SHCLLISTROOT +{ + /** The list node. */ + RTLISTNODE Node; + /** Absolute path of entry. */ + char *pszPathAbs; +} SHCLLISTROOT, *PSHCLLISTROOT; + +/** + * Structure for maintaining an Shared Clipboard transfer state. + * Everything in here will be part of a saved state (later). + */ +typedef struct _SHCLTRANSFERSTATE +{ + /** The transfer's (local) ID. */ + SHCLTRANSFERID uID; + /** The transfer's current status. */ + SHCLTRANSFERSTATUS enmStatus; + /** The transfer's direction, seen from the perspective who created the transfer. */ + SHCLTRANSFERDIR enmDir; + /** The transfer's source, seen from the perspective who created the transfer. */ + SHCLSOURCE enmSource; +} SHCLTRANSFERSTATE, *PSHCLTRANSFERSTATE; + +/** + * Structure maintaining clipboard transfer provider context data. + * This is handed in to the provider interface implementations. + */ +typedef struct _SHCLTXPROVIDERCTX +{ + /** Pointer to the related Shared Clipboard transfer. */ + PSHCLTRANSFER pTransfer; + /** User-defined data pointer. Can be NULL if not needed. */ + void *pvUser; + /** Size (in bytes) of data at user pointer. */ + size_t cbUser; +} SHCLTXPROVIDERCTX, *PSHCLTXPROVIDERCTX; + +struct SHCLTRANSFERCTX; +typedef struct SHCLTRANSFERCTX *PSHCLTRANSFERCTX; + +/** + * Shared Clipboard transfer provider interface table. + * + * A transfer provider inteface implementation realizes all low level functions + * needed for making a Shared Clipboard transfer happen. + */ +typedef struct _SHCLTXPROVIDERIFACE +{ + DECLCALLBACKMEMBER(int, pfnRootsGet,(PSHCLTXPROVIDERCTX pCtx, PSHCLROOTLIST *ppRootList)); + DECLCALLBACKMEMBER(int, pfnListOpen,(PSHCLTXPROVIDERCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList)); + DECLCALLBACKMEMBER(int, pfnListClose,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList)); + DECLCALLBACKMEMBER(int, pfnListHdrRead,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)); + DECLCALLBACKMEMBER(int, pfnListHdrWrite,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr)); + DECLCALLBACKMEMBER(int, pfnListEntryRead,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry)); + DECLCALLBACKMEMBER(int, pfnListEntryWrite,(PSHCLTXPROVIDERCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry)); + DECLCALLBACKMEMBER(int, pfnObjOpen,(PSHCLTXPROVIDERCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms, PSHCLOBJHANDLE phObj)); + DECLCALLBACKMEMBER(int, pfnObjClose,(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj)); + DECLCALLBACKMEMBER(int, pfnObjRead,(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData, + uint32_t fFlags, uint32_t *pcbRead)); + DECLCALLBACKMEMBER(int, pfnObjWrite,(PSHCLTXPROVIDERCTX pCtx, SHCLOBJHANDLE hObj, void *pvData, uint32_t cbData, + uint32_t fFlags, uint32_t *pcbWritten)); +} SHCLTXPROVIDERIFACE, *PSHCLTXPROVIDERIFACE; + +/** + * Structure for the Shared Clipboard transfer provider creation context. + */ +typedef struct _SHCLTXPROVIDERCREATIONCTX +{ + /** Specifies what the source of the provider is. */ + SHCLSOURCE enmSource; + /** The provider interface table. */ + SHCLTXPROVIDERIFACE Interface; + /** User-provided callback data. */ + void *pvUser; + /** Size (in bytes) of data at user pointer. */ + size_t cbUser; +} SHCLTXPROVIDERCREATIONCTX, *PSHCLTXPROVIDERCREATIONCTX; + +/** + * Structure maintaining clipboard transfer callback context data. + */ +typedef struct _SHCLTRANSFERCALLBACKCTX +{ + /** Pointer to the related Shared Clipboard transfer. */ + PSHCLTRANSFER pTransfer; + /** User-defined data pointer. Can be NULL if not needed. */ + void *pvUser; + /** Size (in bytes) of data at user pointer. */ + size_t cbUser; +} SHCLTRANSFERCALLBACKCTX, *PSHCLTRANSFERCALLBACKCTX; + +/** + * Shared Clipboard transfer callback table. + * + * All callbacks are optional and can provide additional information / feedback to a frontend. + */ +typedef struct _SHCLTRANSFERCALLBACKTABLE +{ + /** + * Called when the transfer gets initialized. + * + * @param pCbCtx Pointer to callback context to use. + */ + DECLCALLBACKMEMBER(int, pfnOnInitialize,(PSHCLTRANSFERCALLBACKCTX pCbCtx)); + /** + * Called before the transfer will be started. + * + * @param pCbCtx Pointer to callback context to use. + */ + DECLCALLBACKMEMBER(int, pfnOnStart,(PSHCLTRANSFERCALLBACKCTX pCbCtx)); + /** + * Called when the transfer has been complete. + * + * @param pCbCtx Pointer to callback context to use. + * @param rcCompletion Completion result. + * VERR_CANCELED if transfer has been canceled. + */ + DECLCALLBACKMEMBER(void, pfnOnCompleted,(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcCompletion)); + /** + * Called when transfer resulted in an unrecoverable error. + * + * @param pCbCtx Pointer to callback context to use. + * @param rcError Error reason, IPRT-style. + */ + DECLCALLBACKMEMBER(void, pfnOnError,(PSHCLTRANSFERCALLBACKCTX pCbCtx, int rcError)); + /** + * Called when transfer got registered to a transfer context. + * + * @param pCbCtx Pointer to callback context to use. + * @param pTransferCtx Transfer context transfer was registered to. + */ + DECLCALLBACKMEMBER(void, pfnOnRegistered,(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)); + /** + * Called when transfer got unregistered from a transfer context. + * + * @param pCbCtx Pointer to callback context to use. + * @param pTransferCtx Transfer context transfer was unregistered from. + */ + DECLCALLBACKMEMBER(void, pfnOnUnregistered,(PSHCLTRANSFERCALLBACKCTX pCbCtx, PSHCLTRANSFERCTX pTransferCtx)); + + /** User-provided callback data. Can be NULL if not used. */ + void *pvUser; + /** Size (in bytes) of data pointer at \a pvUser. */ + size_t cbUser; +} SHCLTRANSFERCALLBACKTABLE, *PSHCLTRANSFERCALLBACKTABLE; + +/** + * Structure for thread-related members for a single Shared Clipboard transfer. + */ +typedef struct _SHCLTRANSFERTHREAD +{ + /** Thread handle for the reading / writing thread. + * Can be NIL_RTTHREAD if not being used. */ + RTTHREAD hThread; + /** Thread started indicator. */ + volatile bool fStarted; + /** Thread stop flag. */ + volatile bool fStop; + /** Thread cancelled flag / indicator. */ + volatile bool fCancelled; +} SHCLTRANSFERTHREAD, *PSHCLTRANSFERTHREAD; + +/** + * A single Shared Clipboard transfer. + * + ** @todo Not yet thread safe. + */ +typedef struct SHCLTRANSFER +{ + /** The node member for using this struct in a RTList. */ + RTLISTNODE Node; + /** The transfer's state (for SSM, later). */ + SHCLTRANSFERSTATE State; + /** Absolute path to root entries. */ + char *pszPathRootAbs; + /** Timeout (in ms) for waiting of events. Default is 30s. */ + RTMSINTERVAL uTimeoutMs; + /** Maximum data chunk size (in bytes) to transfer. Default is 64K. */ + uint32_t cbMaxChunkSize; + /** The transfer's own event source. */ + SHCLEVENTSOURCE Events; + /** Current number of concurrent list handles. */ + uint32_t cListHandles; + /** Maximum number of concurrent list handles. */ + uint32_t cMaxListHandles; + /** Next upcoming list handle. */ + SHCLLISTHANDLE uListHandleNext; + /** List of all list handles elated to this transfer. */ + RTLISTANCHOR lstList; + /** Number of root entries in list. */ + uint64_t cRoots; + /** List of root entries of this transfer. */ + RTLISTANCHOR lstRoots; + /** Current number of concurrent object handles. */ + uint32_t cObjHandles; + /** Maximum number of concurrent object handles. */ + uint32_t cMaxObjHandles; + /** Next upcoming object handle. */ + SHCLOBJHANDLE uObjHandleNext; + /** Map of all objects handles related to this transfer. */ + RTLISTANCHOR lstObj; + /** The transfer's own provider context. */ + SHCLTXPROVIDERCTX ProviderCtx; + /** The transfer's provider interface. */ + SHCLTXPROVIDERIFACE ProviderIface; + /** The transfer's callback context. */ + SHCLTRANSFERCALLBACKCTX CallbackCtx; + /** The transfer's callback table. */ + SHCLTRANSFERCALLBACKTABLE Callbacks; + /** Opaque pointer to implementation-specific parameters. */ + void *pvUser; + /** Size (in bytes) of implementation-specific parameters. */ + size_t cbUser; + /** Contains thread-related attributes. */ + SHCLTRANSFERTHREAD Thread; + /** Critical section for serializing access. */ + RTCRITSECT CritSect; +} SHCLTRANSFER, *PSHCLTRANSFER; + +/** + * Structure for keeping an Shared Clipboard transfer status report. + */ +typedef struct _SHCLTRANSFERREPORT +{ + /** Actual status to report. */ + SHCLTRANSFERSTATUS uStatus; + /** Result code (rc) to report; might be unused / invalid, based on enmStatus. */ + int rc; + /** Reporting flags. Currently unused and must be 0. */ + uint32_t fFlags; +} SHCLTRANSFERREPORT, *PSHCLTRANSFERREPORT; + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP +typedef struct _SHCLHTTPSERVER +{ + /** Critical section for serializing access. */ + RTCRITSECT CritSect; + /** Handle of the HTTP server instance. */ + RTHTTPSERVER hHTTPServer; + /** Port number the HTTP server is running on. 0 if not running. */ + uint16_t uPort; + /** List of registered HTTP transfers. */ + RTLISTANCHOR lstTransfers; + /** Number of registered HTTP transfers. */ + uint32_t cTransfers; + /** Cached response data. */ + RTHTTPSERVERRESP Resp; +} SHCLHTTPSERVER; +typedef SHCLHTTPSERVER *PSHCLHTTPSERVER; + +typedef struct _SHCLHTTPCONTEXT +{ + /** HTTP server instance data. */ + SHCLHTTPSERVER HttpServer; +} SHCLHTTPCONTEXT; +typedef SHCLHTTPCONTEXT *PSHCLHTTPCONTEXT; + +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */ + +/** + * Structure for keeping Shared Clipboard transfer context around. + */ +struct SHCLTRANSFERCTX +{ + /** Critical section for serializing access. */ + RTCRITSECT CritSect; + /** List of transfers. */ + RTLISTANCHOR List; + /** Transfer ID allocation bitmap; clear bits are free, set bits are busy. */ + uint64_t bmTransferIds[VBOX_SHCL_MAX_TRANSFERS / sizeof(uint64_t) / 8]; + /** Number of running (concurrent) transfers. */ + uint16_t cRunning; + /** Maximum Number of running (concurrent) transfers. */ + uint16_t cMaxRunning; + /** Number of total transfers (in list). */ + uint16_t cTransfers; +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP + /** HTTP server instance for this transfer context. */ + SHCLHTTPSERVER HttpServer; +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */ +}; + +int ShClTransferObjCtxInit(PSHCLCLIENTTRANSFEROBJCTX pObjCtx); +void ShClTransferObjCtxDestroy(PSHCLCLIENTTRANSFEROBJCTX pObjCtx); +bool ShClTransferObjCtxIsValid(PSHCLCLIENTTRANSFEROBJCTX pObjCtx); + +int ShClTransferObjHandleInfoInit(PSHCLOBJHANDLEINFO pInfo); +void ShClTransferObjHandleInfoDestroy(PSHCLOBJHANDLEINFO pInfo); + +int ShClTransferObjOpenParmsInit(PSHCLOBJOPENCREATEPARMS pParms); +int ShClTransferObjOpenParmsCopy(PSHCLOBJOPENCREATEPARMS pParmsDst, PSHCLOBJOPENCREATEPARMS pParmsSrc); +void ShClTransferObjOpenParmsDestroy(PSHCLOBJOPENCREATEPARMS pParms); + +int ShClTransferObjOpen(PSHCLTRANSFER pTransfer, PSHCLOBJOPENCREATEPARMS pOpenCreateParms, PSHCLOBJHANDLE phObj); +int ShClTransferObjClose(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj); +int ShClTransferObjRead(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t fFlags, uint32_t *pcbRead); +int ShClTransferObjWrite(PSHCLTRANSFER pTransfer, SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, uint32_t fFlags, uint32_t *pcbWritten); + +PSHCLOBJDATACHUNK ShClTransferObjDataChunkDup(PSHCLOBJDATACHUNK pDataChunk); +void ShClTransferObjDataChunkDestroy(PSHCLOBJDATACHUNK pDataChunk); +void ShClTransferObjDataChunkFree(PSHCLOBJDATACHUNK pDataChunk); + +int ShClTransferCreate(PSHCLTRANSFER *ppTransfer); +int ShClTransferInit(PSHCLTRANSFER pTransfer, SHCLTRANSFERDIR enmDir, SHCLSOURCE enmSource); +int ShClTransferDestroy(PSHCLTRANSFER pTransfer); + +int ShClTransferListOpen(PSHCLTRANSFER pTransfer, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList); +int ShClTransferListClose(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList); +int ShClTransferListGetHeader(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, PSHCLLISTHDR pHdr); +PSHCLTRANSFEROBJ ShClTransferListGetObj(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, uint64_t uIdx); +int ShClTransferListRead(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry); +int ShClTransferListWrite(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList, PSHCLLISTENTRY pEntry); +bool ShClTransferListHandleIsValid(PSHCLTRANSFER pTransfer, SHCLLISTHANDLE hList); + +int ShClPathSanitizeFilename(char *pszPath, size_t cbPath); +int ShClPathSanitize(char *pszPath, size_t cbPath); + +PSHCLROOTLIST ShClTransferRootListAlloc(void); +void ShClTransferRootListFree(PSHCLROOTLIST pRootList); + +PSHCLROOTLISTHDR ShClTransferRootListHdrDup(PSHCLROOTLISTHDR pRoots); +int ShClTransferRootListHdrInit(PSHCLROOTLISTHDR pRoots); +void ShClTransferRootListHdrDestroy(PSHCLROOTLISTHDR pRoots); + +int ShClTransferRootListEntryCopy(PSHCLROOTLISTENTRY pDst, PSHCLROOTLISTENTRY pSrc); +int ShClTransferRootListEntryInit(PSHCLROOTLISTENTRY pRootListEntry); +void ShClTransferRootListEntryDestroy(PSHCLROOTLISTENTRY pRootListEntry); +PSHCLROOTLISTENTRY ShClTransferRootListEntryDup(PSHCLROOTLISTENTRY pRootListEntry); + +int ShClTransferListHandleInfoInit(PSHCLLISTHANDLEINFO pInfo); +void ShClTransferListHandleInfoDestroy(PSHCLLISTHANDLEINFO pInfo); + +int ShClTransferListHdrAlloc(PSHCLLISTHDR *ppListHdr); +void ShClTransferListHdrFree(PSHCLLISTHDR pListHdr); +PSHCLLISTHDR ShClTransferListHdrDup(PSHCLLISTHDR pListHdr); +int ShClTransferListHdrInit(PSHCLLISTHDR pListHdr); +void ShClTransferListHdrDestroy(PSHCLLISTHDR pListHdr); +void ShClTransferListHdrReset(PSHCLLISTHDR pListHdr); +bool ShClTransferListHdrIsValid(PSHCLLISTHDR pListHdr); + +int ShClTransferListOpenParmsCopy(PSHCLLISTOPENPARMS pDst, PSHCLLISTOPENPARMS pSrc); +PSHCLLISTOPENPARMS ShClTransferListOpenParmsDup(PSHCLLISTOPENPARMS pParms); +int ShClTransferListOpenParmsInit(PSHCLLISTOPENPARMS pParms); +void ShClTransferListOpenParmsDestroy(PSHCLLISTOPENPARMS pParms); + +int ShClTransferListEntryAlloc(PSHCLLISTENTRY *ppListEntry); +void ShClTransferListEntryFree(PSHCLLISTENTRY pListEntry); +int ShClTransferListEntryCopy(PSHCLLISTENTRY pDst, PSHCLLISTENTRY pSrc); +PSHCLLISTENTRY ShClTransferListEntryDup(PSHCLLISTENTRY pListEntry); +int ShClTransferListEntryInit(PSHCLLISTENTRY pListEntry); +void ShClTransferListEntryDestroy(PSHCLLISTENTRY pListEntry); +bool ShClTransferListEntryIsValid(PSHCLLISTENTRY pListEntry); + +void ShClTransferCopyCallbacks(PSHCLTRANSFERCALLBACKTABLE pCallbacksDst, PSHCLTRANSFERCALLBACKTABLE pCallbacksSrc); +void ShClTransferSetCallbacks(PSHCLTRANSFER pTransfer, PSHCLTRANSFERCALLBACKTABLE pCallbacks); +int ShClTransferSetProviderIface(PSHCLTRANSFER pTransfer, PSHCLTXPROVIDERCREATIONCTX pCreationCtx); +int ShClTransferRootsSet(PSHCLTRANSFER pTransfer, const char *pszRoots, size_t cbRoots); +void ShClTransferReset(PSHCLTRANSFER pTransfer); + +uint32_t ShClTransferRootsCount(PSHCLTRANSFER pTransfer); +int ShClTransferRootsEntry(PSHCLTRANSFER pTransfer, uint64_t uIndex, PSHCLROOTLISTENTRY pEntry); +int ShClTransferRootsGet(PSHCLTRANSFER pTransfer, PSHCLROOTLIST *ppRootList); + +SHCLTRANSFERID ShClTransferGetID(PSHCLTRANSFER pTransfer); +SHCLTRANSFERDIR ShClTransferGetDir(PSHCLTRANSFER pTransfer); +SHCLSOURCE ShClTransferGetSource(PSHCLTRANSFER pTransfer); +SHCLTRANSFERSTATUS ShClTransferGetStatus(PSHCLTRANSFER pTransfer); +int ShClTransferRun(PSHCLTRANSFER pTransfer, PFNRTTHREAD pfnThreadFunc, void *pvUser); +int ShClTransferStart(PSHCLTRANSFER pTransfer); + +int ShClTransferCtxInit(PSHCLTRANSFERCTX pTransferCtx); +void ShClTransferCtxDestroy(PSHCLTRANSFERCTX pTransferCtx); +void ShClTransferCtxReset(PSHCLTRANSFERCTX pTransferCtx); +PSHCLTRANSFER ShClTransferCtxGetTransferById(PSHCLTRANSFERCTX pTransferCtx, uint32_t uID); +PSHCLTRANSFER ShClTransferCtxGetTransferByIndex(PSHCLTRANSFERCTX pTransferCtx, uint32_t uIdx); +uint32_t ShClTransferCtxGetRunningTransfers(PSHCLTRANSFERCTX pTransferCtx); +uint32_t ShClTransferCtxGetTotalTransfers(PSHCLTRANSFERCTX pTransferCtx); +void ShClTransferCtxCleanup(PSHCLTRANSFERCTX pTransferCtx); +bool ShClTransferCtxTransfersMaximumReached(PSHCLTRANSFERCTX pTransferCtx); +int ShClTransferCtxTransferRegister(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID *pidTransfer); +int ShClTransferCtxTransferRegisterById(PSHCLTRANSFERCTX pTransferCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERID idTransfer); +int ShClTransferCtxTransferUnregister(PSHCLTRANSFERCTX pTransferCtx, SHCLTRANSFERID idTransfer); + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP +int ShClHttpTransferRegister(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer); +int ShClHttpTransferUnregister(PSHCLHTTPCONTEXT pCtx, PSHCLTRANSFER pTransfer); + +int ShClTransferHttpServerCreate(PSHCLHTTPSERVER pSrv, uint16_t *puPort); +int ShClTransferHttpServerCreateEx(PSHCLHTTPSERVER pSrv, uint16_t uPort); +int ShClTransferHttpServerDestroy(PSHCLHTTPSERVER pSrv); +void ShClTransferHttpServerInit(PSHCLHTTPSERVER pSrv); +int ShClTransferHttpServerRegisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer); +int ShClTransferHttpServerUnregisterTransfer(PSHCLHTTPSERVER pSrv, PSHCLTRANSFER pTransfer); +bool ShClTransferHttpServerHasTransfer(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer); +uint16_t ShClTransferHttpServerGetPort(PSHCLHTTPSERVER pSrv); +uint32_t ShClTransferHttpServerGetTransferCount(PSHCLHTTPSERVER pSrv); +char *ShClTransferHttpServerGetAddressA(PSHCLHTTPSERVER pSrv); +char *ShClTransferHttpServerGetUrlA(PSHCLHTTPSERVER pSrv, SHCLTRANSFERID idTransfer); +bool ShClTransferHttpServerIsRunning(PSHCLHTTPSERVER pSrv); +#endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP */ + +void ShClFsObjFromIPRT(PSHCLFSOBJINFO pDst, PCRTFSOBJINFO pSrc); + +bool ShClMIMEHasFileURLs(const char *pcszFormat, size_t cchFormatMax); +bool ShClMIMENeedsCache(const char *pcszFormat, size_t cchFormatMax); + +const char *ShClTransferStatusToStr(SHCLTRANSFERSTATUS enmStatus); + +#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_transfers_h */ diff --git a/include/VBox/GuestHost/SharedClipboard-win.h b/include/VBox/GuestHost/SharedClipboard-win.h new file mode 100644 index 00000000..0e35b409 --- /dev/null +++ b/include/VBox/GuestHost/SharedClipboard-win.h @@ -0,0 +1,419 @@ +/** @file + * Shared Clipboard - Common Guest and Host Code, for Windows OSes. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_win_h +#define VBOX_INCLUDED_GuestHost_SharedClipboard_win_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +#include + +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +# include + +# include /* For RTCString. */ +# include /* For DROPFILES and friends. */ +# include /* For Utf8Str. */ +# include + +# include + +using namespace com; +# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + +#ifndef WM_CLIPBOARDUPDATE +# define WM_CLIPBOARDUPDATE 0x031D +#endif + +#define SHCL_WIN_WNDCLASS_NAME "VBoxSharedClipboardClass" + +/** See: https://docs.microsoft.com/en-us/windows/desktop/dataxchg/html-clipboard-format + * Do *not* change the name, as this will break compatbility with other (legacy) applications! */ +#define SHCL_WIN_REGFMT_HTML "HTML Format" + +/** Default timeout (in ms) for passing down messages down the clipboard chain. */ +#define SHCL_WIN_CBCHAIN_TIMEOUT_MS 5000 + +/** Reports clipboard formats. */ +#define SHCL_WIN_WM_REPORT_FORMATS WM_USER +/** Reads data from the clipboard and sends it to the destination. */ +#define SHCL_WIN_WM_READ_DATA WM_USER + 1 +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +/** Starts a transfer on the guest. + * This creates the necessary IDataObject in the matching window thread. */ +# define SHCL_WIN_WM_TRANSFER_START WM_USER + 2 +#endif + +/* Dynamically load clipboard functions from User32.dll. */ +typedef BOOL WINAPI FNADDCLIPBOARDFORMATLISTENER(HWND); +typedef FNADDCLIPBOARDFORMATLISTENER *PFNADDCLIPBOARDFORMATLISTENER; + +typedef BOOL WINAPI FNREMOVECLIPBOARDFORMATLISTENER(HWND); +typedef FNREMOVECLIPBOARDFORMATLISTENER *PFNREMOVECLIPBOARDFORMATLISTENER; + +/** + * Structure for keeping function pointers for the new clipboard API. + * If the new API is not available, those function pointer are NULL. + */ +typedef struct _SHCLWINAPINEW +{ + PFNADDCLIPBOARDFORMATLISTENER pfnAddClipboardFormatListener; + PFNREMOVECLIPBOARDFORMATLISTENER pfnRemoveClipboardFormatListener; +} SHCLWINAPINEW, *PSHCLWINAPINEW; + +/** + * Structure for keeping variables which are needed to drive the old clipboard API. + */ +typedef struct _SHCLWINAPIOLD +{ + /** Timer ID for the refresh timer. */ + UINT timerRefresh; + /** Whether "pinging" the clipboard chain currently is in progress or not. */ + bool fCBChainPingInProcess; +} SHCLWINAPIOLD, *PSHCLWINAPIOLD; + +/** + * Structure for maintaining a Shared Clipboard context on Windows platforms. + */ +typedef struct _SHCLWINCTX +{ + /** Critical section to serialize access. */ + RTCRITSECT CritSect; + /** Window handle of our (invisible) clipbaord window. */ + HWND hWnd; + /** Window handle which is next to us in the clipboard chain. */ + HWND hWndNextInChain; + /** Window handle of the clipboard owner *if* we are the owner. + * @todo r=bird: Ignore the misleading statement above. This is only set to + * NULL by the initialization code and then it's set to the clipboard owner + * after we announce data to the clipboard. So, essentially this will be our + * windows handle or NULL. End of story. */ + HWND hWndClipboardOwnerUs; + /** Structure for maintaining the new clipboard API. */ + SHCLWINAPINEW newAPI; + /** Structure for maintaining the old clipboard API. */ + SHCLWINAPIOLD oldAPI; +} SHCLWINCTX, *PSHCLWINCTX; + +int SharedClipboardWinOpen(HWND hWnd); +int SharedClipboardWinClose(void); +int SharedClipboardWinClear(void); + +int SharedClipboardWinCtxInit(PSHCLWINCTX pWinCtx); +void SharedClipboardWinCtxDestroy(PSHCLWINCTX pWinCtx); + +int SharedClipboardWinCheckAndInitNewAPI(PSHCLWINAPINEW pAPI); +bool SharedClipboardWinIsNewAPI(PSHCLWINAPINEW pAPI); + +int SharedClipboardWinDataWrite(UINT cfFormat, void *pvData, uint32_t cbData); + +int SharedClipboardWinChainAdd(PSHCLWINCTX pCtx); +int SharedClipboardWinChainRemove(PSHCLWINCTX pCtx); +VOID CALLBACK SharedClipboardWinChainPingProc(HWND hWnd, UINT uMsg, ULONG_PTR dwData, LRESULT lResult) RT_NOTHROW_DEF; +LRESULT SharedClipboardWinChainPassToNext(PSHCLWINCTX pWinCtx, UINT msg, WPARAM wParam, LPARAM lParam); + +SHCLFORMAT SharedClipboardWinClipboardFormatToVBox(UINT uFormat); +int SharedClipboardWinGetFormats(PSHCLWINCTX pCtx, PSHCLFORMATS pfFormats); + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +int SharedClipboardWinGetRoots(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer); +int SharedClipboardWinDropFilesToStringList(DROPFILES *pDropFiles, char **papszList, uint32_t *pcbList); +#endif + +int SharedClipboardWinGetCFHTMLHeaderValue(const char *pszSrc, const char *pszOption, uint32_t *puValue); +bool SharedClipboardWinIsCFHTML(const char *pszSource); +int SharedClipboardWinConvertCFHTMLToMIME(const char *pszSource, const uint32_t cch, char **ppszOutput, uint32_t *pcbOutput); +int SharedClipboardWinConvertMIMEToCFHTML(const char *pszSource, size_t cb, char **ppszOutput, uint32_t *pcbOutput); + +LRESULT SharedClipboardWinHandleWMChangeCBChain(PSHCLWINCTX pWinCtx, HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); +int SharedClipboardWinHandleWMDestroy(PSHCLWINCTX pWinCtx); +int SharedClipboardWinHandleWMRenderAllFormats(PSHCLWINCTX pWinCtx, HWND hWnd); +int SharedClipboardWinHandleWMTimer(PSHCLWINCTX pWinCtx); + +int SharedClipboardWinClearAndAnnounceFormats(PSHCLWINCTX pWinCtx, SHCLFORMATS fFormats, HWND hWnd); +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +int SharedClipboardWinTransferCreate(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer); +void SharedClipboardWinTransferDestroy(PSHCLWINCTX pWinCtx, PSHCLTRANSFER pTransfer); +#endif + +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +class SharedClipboardTransferList; +# ifndef FILEGROUPDESCRIPTOR +class FILEGROUPDESCRIPTOR; +# endif + +class SharedClipboardWinDataObject : public IDataObject //, public IDataObjectAsyncCapability +{ +public: + + enum Status + { + /** The object is uninitialized (not ready). */ + Uninitialized = 0, + /** The object is initialized and ready to use. */ + Initialized, + /** The operation has been successfully completed. */ + Completed, + /** The operation has been canceled. */ + Canceled, + /** An (unrecoverable) error occurred. */ + Error + }; + +public: + + SharedClipboardWinDataObject(PSHCLTRANSFER pTransfer, + LPFORMATETC pFormatEtc = NULL, LPSTGMEDIUM pStgMed = NULL, ULONG cFormats = 0); + virtual ~SharedClipboardWinDataObject(void); + +public: /* IUnknown methods. */ + + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + +public: /* IDataObject methods. */ + + STDMETHOD(GetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium); + STDMETHOD(GetDataHere)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium); + STDMETHOD(QueryGetData)(LPFORMATETC pFormatEtc); + STDMETHOD(GetCanonicalFormatEtc)(LPFORMATETC pFormatEct, LPFORMATETC pFormatEtcOut); + STDMETHOD(SetData)(LPFORMATETC pFormatEtc, LPSTGMEDIUM pMedium, BOOL fRelease); + STDMETHOD(EnumFormatEtc)(DWORD dwDirection, IEnumFORMATETC **ppEnumFormatEtc); + STDMETHOD(DAdvise)(LPFORMATETC pFormatEtc, DWORD advf, IAdviseSink *pAdvSink, DWORD *pdwConnection); + STDMETHOD(DUnadvise)(DWORD dwConnection); + STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppEnumAdvise); + +#ifdef VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC +public: /* IDataObjectAsyncCapability methods. */ + + STDMETHOD(EndOperation)(HRESULT hResult, IBindCtx* pbcReserved, DWORD dwEffects); + STDMETHOD(GetAsyncMode)(BOOL* pfIsOpAsync); + STDMETHOD(InOperation)(BOOL* pfInAsyncOp); + STDMETHOD(SetAsyncMode)(BOOL fDoOpAsync); + STDMETHOD(StartOperation)(IBindCtx* pbcReserved); +#endif /* VBOX_WITH_SHARED_CLIPBOARD_WIN_ASYNC */ + +public: + + int Init(void); + void OnTransferComplete(int rc = VINF_SUCCESS); + void OnTransferCanceled(); + +public: + + static DECLCALLBACK(int) readThread(RTTHREAD ThreadSelf, void *pvUser); + + static void logFormat(CLIPFORMAT fmt); + +protected: + + static int Thread(RTTHREAD hThread, void *pvUser); + + int readDir(PSHCLTRANSFER pTransfer, const Utf8Str &strPath); + + int copyToHGlobal(const void *pvData, size_t cbData, UINT fFlags, HGLOBAL *phGlobal); + int createFileGroupDescriptorFromTransfer(PSHCLTRANSFER pTransfer, + bool fUnicode, HGLOBAL *phGlobal); + + bool lookupFormatEtc(LPFORMATETC pFormatEtc, ULONG *puIndex); + void registerFormat(LPFORMATETC pFormatEtc, CLIPFORMAT clipFormat, TYMED tyMed = TYMED_HGLOBAL, + LONG lindex = -1, DWORD dwAspect = DVASPECT_CONTENT, DVTARGETDEVICE *pTargetDevice = NULL); +protected: + + /** + * Structure for keeping a single file system object entry. + */ + struct FSOBJENTRY + { + /** Relative path of the object. */ + Utf8Str strPath; + /** Related (cached) object information. */ + SHCLFSOBJINFO objInfo; + }; + + /** Vector containing file system objects with its (cached) objection information. */ + typedef std::vector FsObjEntryList; + + /** The object's current status. */ + Status m_enmStatus; + /** The object's current reference count. */ + LONG m_lRefCount; + /** How many formats have been registered. */ + ULONG m_cFormats; + LPFORMATETC m_pFormatEtc; + LPSTGMEDIUM m_pStgMedium; + /** Pointer to the associated transfer object being handled. */ + PSHCLTRANSFER m_pTransfer; + /** Current stream object being used. */ + IStream *m_pStream; + /** Current object index being handled by the data object. + * This is needed to create the next IStream object for e.g. the next upcoming file/dir/++ in the transfer. */ + ULONG m_uObjIdx; + /** List of (cached) file system objects. */ + FsObjEntryList m_lstEntries; + /** Whether the transfer thread is running. */ + bool m_fRunning; + /** Event being triggered when reading the transfer list been completed. */ + RTSEMEVENT m_EventListComplete; + /** Event being triggered when the transfer has been completed. */ + RTSEMEVENT m_EventTransferComplete; + /** Registered format for CFSTR_FILEDESCRIPTORA. */ + UINT m_cfFileDescriptorA; + /** Registered format for CFSTR_FILEDESCRIPTORW. */ + UINT m_cfFileDescriptorW; + /** Registered format for CFSTR_FILECONTENTS. */ + UINT m_cfFileContents; + /** Registered format for CFSTR_PERFORMEDDROPEFFECT. */ + UINT m_cfPerformedDropEffect; +}; + +class SharedClipboardWinEnumFormatEtc : public IEnumFORMATETC +{ +public: + + SharedClipboardWinEnumFormatEtc(LPFORMATETC pFormatEtc, ULONG cFormats); + virtual ~SharedClipboardWinEnumFormatEtc(void); + +public: /* IUnknown methods. */ + + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + +public: /* IEnumFORMATETC methods. */ + + STDMETHOD(Next)(ULONG cFormats, LPFORMATETC pFormatEtc, ULONG *pcFetched); + STDMETHOD(Skip)(ULONG cFormats); + STDMETHOD(Reset)(void); + STDMETHOD(Clone)(IEnumFORMATETC **ppEnumFormatEtc); + +public: + + static void CopyFormat(LPFORMATETC pFormatDest, LPFORMATETC pFormatSource); + static HRESULT CreateEnumFormatEtc(UINT cFormats, LPFORMATETC pFormatEtc, IEnumFORMATETC **ppEnumFormatEtc); + +private: + + LONG m_lRefCount; + ULONG m_nIndex; + ULONG m_nNumFormats; + LPFORMATETC m_pFormatEtc; +}; + +/** + * Own IStream implementation to implement file-based clipboard operations + * through HGCM. Needed on Windows hosts and guests. + */ +class SharedClipboardWinStreamImpl : public IStream +{ +public: + + SharedClipboardWinStreamImpl(SharedClipboardWinDataObject *pParent, PSHCLTRANSFER pTransfer, + const Utf8Str &strPath, PSHCLFSOBJINFO pObjInfo); + virtual ~SharedClipboardWinStreamImpl(void); + +public: /* IUnknown methods. */ + + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject); + STDMETHOD_(ULONG, AddRef)(void); + STDMETHOD_(ULONG, Release)(void); + +public: /* IStream methods. */ + + STDMETHOD(Clone)(IStream** ppStream); + STDMETHOD(Commit)(DWORD dwFrags); + STDMETHOD(CopyTo)(IStream* pDestStream, ULARGE_INTEGER nBytesToCopy, ULARGE_INTEGER* nBytesRead, ULARGE_INTEGER* nBytesWritten); + STDMETHOD(LockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes,DWORD dwFlags); + STDMETHOD(Read)(void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead); + STDMETHOD(Revert)(void); + STDMETHOD(Seek)(LARGE_INTEGER nMove, DWORD dwOrigin, ULARGE_INTEGER* nNewPos); + STDMETHOD(SetSize)(ULARGE_INTEGER nNewSize); + STDMETHOD(Stat)(STATSTG* statstg, DWORD dwFlags); + STDMETHOD(UnlockRegion)(ULARGE_INTEGER nStart, ULARGE_INTEGER nBytes, DWORD dwFlags); + STDMETHOD(Write)(const void* pvBuffer, ULONG nBytesToRead, ULONG* nBytesRead); + +public: /* Own methods. */ + + static HRESULT Create(SharedClipboardWinDataObject *pParent, PSHCLTRANSFER pTransfer, const Utf8Str &strPath, + PSHCLFSOBJINFO pObjInfo, IStream **ppStream); +private: + + /** Pointer to the parent data object. */ + SharedClipboardWinDataObject *m_pParent; + /** The stream object's current reference count. */ + LONG m_lRefCount; + /** Pointer to the associated Shared Clipboard transfer. */ + PSHCLTRANSFER m_pTransfer; + /** The object handle to use. */ + SHCLOBJHANDLE m_hObj; + /** Object path. */ + Utf8Str m_strPath; + /** (Cached) object information. */ + SHCLFSOBJINFO m_objInfo; + /** Number of bytes already processed. */ + uint64_t m_cbProcessed; + /** Whether this object already is in completed state or not. */ + bool m_fIsComplete; +}; + +/** + * Class for Windows-specifics for maintaining a single Shared Clipboard transfer. + * Set as pvUser / cbUser in SHCLTRANSFERCTX. + */ +class SharedClipboardWinTransferCtx +{ +public: + SharedClipboardWinTransferCtx() + : pDataObj(NULL) { } + + virtual ~SharedClipboardWinTransferCtx() + { + if (pDataObj) + delete pDataObj; + } + + /** Pointer to data object to use for this transfer. + * Can be NULL if not being used. */ + SharedClipboardWinDataObject *pDataObj; +}; +# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ +#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_win_h */ + diff --git a/include/VBox/GuestHost/SharedClipboard-x11.h b/include/VBox/GuestHost/SharedClipboard-x11.h new file mode 100644 index 00000000..c06f2dd2 --- /dev/null +++ b/include/VBox/GuestHost/SharedClipboard-x11.h @@ -0,0 +1,187 @@ +/** @file + * Shared Clipboard - Common X11 code. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_x11_h +#define VBOX_INCLUDED_GuestHost_SharedClipboard_x11_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#include + +#include +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +# include +#endif + +/** + * The maximum number of simultaneous connections to shared clipboard service. + * This constant limits amount of GUEST -> HOST connections to shared clipboard host service + * for X11 host only. Once amount of connections reaches this number, all the + * further attempts to CONNECT will be dropped on an early stage. Possibility to connect + * is available again after one of existing connections is closed by DISCONNECT call. + */ +#define VBOX_SHARED_CLIPBOARD_X11_CONNECTIONS_MAX (20) + +/** Enables the Xt busy / update handling. */ +#define VBOX_WITH_SHARED_CLIPBOARD_XT_BUSY 1 + +/** + * Enumeration for all clipboard formats which we support on X11. + */ +typedef enum _SHCLX11FMT +{ + SHCLX11FMT_INVALID = 0, + SHCLX11FMT_TARGETS, + SHCLX11FMT_TEXT, /* Treat this as UTF-8, but it may really be ascii */ + SHCLX11FMT_UTF8, + SHCLX11FMT_BMP, + SHCLX11FMT_HTML +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + , SHCLX11FMT_URI_LIST +#endif +} SHCLX11FMT; + +/** + * The table maps X11 names to data formats + * and to the corresponding VBox clipboard formats. + */ +typedef struct SHCLX11FMTTABLE +{ + /** The X11 atom name of the format (several names can match one format). */ + const char *pcszAtom; + /** The format corresponding to the name. */ + SHCLX11FMT enmFmtX11; + /** The corresponding VBox clipboard format. */ + SHCLFORMAT uFmtVBox; +} SHCLX11FMTTABLE; + +#define NIL_CLIPX11FORMAT 0 + +/** Defines an index of the X11 clipboad format table. */ +typedef unsigned SHCLX11FMTIDX; + +/** + * Structure for maintaining a Shared Clipboard context on X11 platforms. + */ +typedef struct _SHCLX11CTX +{ + /** Opaque data structure describing the front-end. */ + PSHCLCONTEXT pFrontend; + /** Our callback table to use. */ + SHCLCALLBACKS Callbacks; + /** Is an X server actually available? */ + bool fHaveX11; + /** The X Toolkit application context structure. */ + XtAppContext pAppContext; + /** We have a separate thread to wait for window and clipboard events. */ + RTTHREAD Thread; + /** Flag indicating that the thread is in a started state. */ + bool fThreadStarted; + /** The X Toolkit widget which we use as our clipboard client. It is never made visible. */ + Widget pWidget; + /** Should we try to grab the clipboard on startup? */ + bool fGrabClipboardOnStart; + /** The best text format X11 has to offer, as an index into the formats table. */ + SHCLX11FMTIDX idxFmtText; + /** The best bitmap format X11 has to offer, as an index into the formats table. */ + SHCLX11FMTIDX idxFmtBmp; + /** The best HTML format X11 has to offer, as an index into the formats table. */ + SHCLX11FMTIDX idxFmtHTML; +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + /** The best HTML format X11 has to offer, as an index into the formats table. */ + SHCLX11FMTIDX idxFmtURI; +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS_HTTP + /** HTTP transfer context data. */ + SHCLHTTPCONTEXT HttpCtx; +# endif +#endif + /** What kind of formats does VBox have to offer? */ + SHCLFORMATS vboxFormats; + /** Cache of the last unicode data that we received. */ + void *pvUnicodeCache; + /** Size of the unicode data in the cache. */ + uint32_t cbUnicodeCache; + /** When we wish the clipboard to exit, we have to wake up the event + * loop. We do this by writing into a pipe. This end of the pipe is + * the end that another thread can write to. */ + int wakeupPipeWrite; + /** The reader end of the pipe. */ + int wakeupPipeRead; + /** A pointer to the XFixesSelectSelectionInput function. */ + void (*fixesSelectInput)(Display *, Window, Atom, unsigned long); + /** The first XFixes event number. */ + int fixesEventBase; +#ifdef VBOX_WITH_SHARED_CLIPBOARD_XT_BUSY + /** XtGetSelectionValue on some versions of libXt isn't re-entrant + * so block overlapping requests on this flag. */ + bool fXtBusy; + /** If a request is blocked on the previous flag, set this flag to request + * an update later - the first callback should check and clear this flag + * before processing the callback event. */ + bool fXtNeedsUpdate; +#endif +} SHCLX11CTX, *PSHCLX11CTX; + +/** + * Structure for keeping a X11 read data request. + */ +typedef struct _SHCLX11READDATAREQ +{ + /** Actual read request to handle. */ + CLIPREADCBREQ *pReq; + /** Result code of the operation on completion. */ + int rcCompletion; +} SHCLX11READDATAREQ; +/** Pointer to a send data request. */ +typedef SHCLX11READDATAREQ *PSHCLX11READDATAREQ; + +/** @name Shared Clipboard APIs for X11. + * @{ + */ +int ShClX11Init(PSHCLX11CTX pCtx, PSHCLCALLBACKS pCallbacks, PSHCLCONTEXT pParent, bool fHeadless); +void ShClX11Destroy(PSHCLX11CTX pCtx); +int ShClX11ThreadStart(PSHCLX11CTX pCtx, bool grab); +int ShClX11ThreadStartEx(PSHCLX11CTX pCtx, const char *pszName, bool fGrab); +int ShClX11ThreadStop(PSHCLX11CTX pCtx); +int ShClX11ReportFormatsToX11(PSHCLX11CTX pCtx, SHCLFORMATS vboxFormats); +int ShClX11ReadDataFromX11(PSHCLX11CTX pCtx, SHCLFORMATS vboxFormat, CLIPREADCBREQ *pReq); +void ShClX11SetCallbacks(PSHCLX11CTX pCtx, PSHCLCALLBACKS pCallbacks); +/** @} */ + +#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_x11_h */ + diff --git a/include/VBox/GuestHost/SharedClipboard.h b/include/VBox/GuestHost/SharedClipboard.h new file mode 100644 index 00000000..ef61bc6c --- /dev/null +++ b/include/VBox/GuestHost/SharedClipboard.h @@ -0,0 +1,354 @@ +/** @file + * Shared Clipboard - Common guest and host Code. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_SharedClipboard_h +#define VBOX_INCLUDED_GuestHost_SharedClipboard_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +/** @name VBOX_SHCL_FMT_XXX - Data formats (flags) for Shared Clipboard. + * @{ + */ +/** No format set. */ +#define VBOX_SHCL_FMT_NONE 0 +/** Shared Clipboard format is an Unicode text. */ +#define VBOX_SHCL_FMT_UNICODETEXT RT_BIT(0) +/** Shared Clipboard format is bitmap (BMP / DIB). */ +#define VBOX_SHCL_FMT_BITMAP RT_BIT(1) +/** Shared Clipboard format is HTML. */ +#define VBOX_SHCL_FMT_HTML RT_BIT(2) +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +/** Shared Clipboard format is a transfer list. */ +# define VBOX_SHCL_FMT_URI_LIST RT_BIT(3) +#endif +/** @} */ + + +/** A single Shared Clipboard format (VBOX_SHCL_FMT_XXX). */ +typedef uint32_t SHCLFORMAT; +/** Pointer to a single Shared Clipboard format (VBOX_SHCL_FMT_XXX). */ +typedef SHCLFORMAT *PSHCLFORMAT; + +/** Bit map (flags) of Shared Clipboard formats (VBOX_SHCL_FMT_XXX). */ +typedef uint32_t SHCLFORMATS; +/** Pointer to a bit map of Shared Clipboard formats (VBOX_SHCL_FMT_XXX). */ +typedef SHCLFORMATS *PSHCLFORMATS; + + +/** + * Shared Clipboard transfer direction. + */ +typedef enum SHCLTRANSFERDIR +{ + /** Unknown transfer directory. */ + SHCLTRANSFERDIR_UNKNOWN = 0, + /** Read transfer (from source). */ + SHCLTRANSFERDIR_FROM_REMOTE, + /** Write transfer (to target). */ + SHCLTRANSFERDIR_TO_REMOTE, + /** The usual 32-bit hack. */ + SHCLTRANSFERDIR_32BIT_HACK = 0x7fffffff +} SHCLTRANSFERDIR; +/** Pointer to a shared clipboard transfer direction. */ +typedef SHCLTRANSFERDIR *PSHCLTRANSFERDIR; + + +/** + * Shared Clipboard data read request. + */ +typedef struct SHCLDATAREQ +{ + /** In which format the data needs to be sent. */ + SHCLFORMAT uFmt; + /** Read flags; currently unused. */ + uint32_t fFlags; + /** Maximum data (in byte) can be sent. */ + uint32_t cbSize; +} SHCLDATAREQ; +/** Pointer to a shared clipboard data request. */ +typedef SHCLDATAREQ *PSHCLDATAREQ; + +/** + * Shared Clipboard event payload (optional). + */ +typedef struct SHCLEVENTPAYLOAD +{ + /** Payload ID; currently unused. */ + uint32_t uID; + /** Size (in bytes) of actual payload data. */ + uint32_t cbData; + /** Pointer to actual payload data. */ + void *pvData; +} SHCLEVENTPAYLOAD; +/** Pointer to a shared clipboard event payload. */ +typedef SHCLEVENTPAYLOAD *PSHCLEVENTPAYLOAD; + +/** A shared clipboard event source ID. */ +typedef uint16_t SHCLEVENTSOURCEID; +/** Pointer to a shared clipboard event source ID. */ +typedef SHCLEVENTSOURCEID *PSHCLEVENTSOURCEID; + +/** A shared clipboard session ID. */ +typedef uint16_t SHCLSESSIONID; +/** Pointer to a shared clipboard session ID. */ +typedef SHCLSESSIONID *PSHCLSESSIONID; +/** NIL shared clipboard session ID. */ +#define NIL_SHCLSESSIONID UINT16_MAX + +/** A shared clipboard transfer ID. */ +typedef uint16_t SHCLTRANSFERID; +/** Pointer to a shared clipboard transfer ID. */ +typedef SHCLTRANSFERID *PSHCLTRANSFERID; +/** NIL shared clipboardtransfer ID. */ +#define NIL_SHCLTRANSFERID UINT16_MAX + +/** A shared clipboard event ID. */ +typedef uint32_t SHCLEVENTID; +/** Pointer to a shared clipboard event source ID. */ +typedef SHCLEVENTID *PSHCLEVENTID; +/** NIL shared clipboard event ID. */ +#define NIL_SHCLEVENTID UINT32_MAX + +/** Pointer to a shared clipboard event source. + * Forward declaration, needed for SHCLEVENT. */ +typedef struct SHCLEVENTSOURCE *PSHCLEVENTSOURCE; + +/** + * Shared Clipboard event. + */ +typedef struct SHCLEVENT +{ + /** List node. */ + RTLISTNODE Node; + /** Parent (source) this event belongs to. */ + PSHCLEVENTSOURCE pParent; + /** The event's ID, for self-reference. */ + SHCLEVENTID idEvent; + /** Reference count to this event. */ + uint32_t cRefs; + /** Event semaphore for signalling the event. */ + RTSEMEVENTMULTI hEvtMulSem; + /** Payload to this event, optional (NULL). */ + PSHCLEVENTPAYLOAD pPayload; +} SHCLEVENT; +/** Pointer to a shared clipboard event. */ +typedef SHCLEVENT *PSHCLEVENT; + +/** + * Shared Clipboard event source. + * + * Each event source maintains an own counter for events, so that it can be used + * in different contexts. + */ +typedef struct SHCLEVENTSOURCE +{ + /** The event source ID. */ + SHCLEVENTSOURCEID uID; + /** Critical section for serializing access. */ + RTCRITSECT CritSect; + /** Next upcoming event ID. */ + SHCLEVENTID idNextEvent; + /** List of events (PSHCLEVENT). */ + RTLISTANCHOR lstEvents; +} SHCLEVENTSOURCE; + +/** @name Shared Clipboard data payload functions. + * @{ + */ +int ShClPayloadAlloc(uint32_t uID, const void *pvData, uint32_t cbData, PSHCLEVENTPAYLOAD *ppPayload); +void ShClPayloadFree(PSHCLEVENTPAYLOAD pPayload); +/** @} */ + +/** @name Shared Clipboard event source functions. + * @{ + */ +int ShClEventSourceCreate(PSHCLEVENTSOURCE pSource, SHCLEVENTSOURCEID idEvtSrc); +int ShClEventSourceDestroy(PSHCLEVENTSOURCE pSource); +void ShClEventSourceReset(PSHCLEVENTSOURCE pSource); +int ShClEventSourceGenerateAndRegisterEvent(PSHCLEVENTSOURCE pSource, PSHCLEVENT *ppEvent); +PSHCLEVENT ShClEventSourceGetFromId(PSHCLEVENTSOURCE pSource, SHCLEVENTID idEvent); +PSHCLEVENT ShClEventSourceGetLast(PSHCLEVENTSOURCE pSource); +/** @} */ + +/** @name Shared Clipboard event functions. + * @{ + */ +uint32_t ShClEventGetRefs(PSHCLEVENT pEvent); +uint32_t ShClEventRetain(PSHCLEVENT pEvent); +uint32_t ShClEventRelease(PSHCLEVENT pEvent); +int ShClEventSignal(PSHCLEVENT pEvent, PSHCLEVENTPAYLOAD pPayload); +int ShClEventWait(PSHCLEVENT pEvent, RTMSINTERVAL uTimeoutMs, PSHCLEVENTPAYLOAD *ppPayload); +/** @} */ + +/** + * Shared Clipboard transfer source type. + * @note Part of saved state! + */ +typedef enum SHCLSOURCE +{ + /** Invalid source type. */ + SHCLSOURCE_INVALID = 0, + /** Source is local. */ + SHCLSOURCE_LOCAL, + /** Source is remote. */ + SHCLSOURCE_REMOTE, + /** The usual 32-bit hack. */ + SHCLSOURCE_32BIT_HACK = 0x7fffffff +} SHCLSOURCE; + +/** Opaque data structure for the X11/VBox frontend/glue code. + * @{ */ +struct SHCLCONTEXT; +typedef struct SHCLCONTEXT SHCLCONTEXT; +/** @} */ +/** Pointer to opaque data structure the X11/VBox frontend/glue code. */ +typedef SHCLCONTEXT *PSHCLCONTEXT; + +/** + * @name Shared Clipboard callback table. + * + * This table gets used by + * - the backends on the host (where required) + * - guest side implementations (e.g. VBoxClient) + * - by the underlying core code (e.g. X11 backend -> X11 common code -> callback) + * + * Some clipboard mechanisms (e.g. X11) require asynchronous and/or event-driven handling + * of clipboard data, making it hard to control our program flow when testing stuff. + * + * So overriding required callbacks on runtime for testing purposes makes this approach much + * more flexible without implementing separate code paths for production code and test units. + * + * @{ + */ +typedef struct _SHCLCALLBACKS +{ + /** + * Callback for reporting supported clipoard formats of current clipboard data. + * + * @note On X11: + * Runs in Xt event thread for the X11 code. + * + * @returns VBox status code. + * @param pCtx Opaque context pointer for the glue code. + * @param fFormats The formats available. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnReportFormats, (PSHCLCONTEXT pCtx, SHCLFORMATS fFormats, void *pvUser)); + + /** + * Callback for reading data from the clipboard. + * Optional and can be NULL. + * + * @note Used for testing X11 clipboard code. + * + * @returns VBox status code. + * @param pCtx Opaque context pointer for the glue code. + * @param uFmt The format in which the data should be read + * (VBOX_SHCL_FMT_XXX). + * @param ppv Returns an allocated buffer with data from on success. + * Needs to be free'd with RTMemFree() by the caller. + * @param pcb Returns the amount of data read (in bytes) on success. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnOnClipboardRead, (PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, size_t *pcb, void *pvUser)); + + /** + * Callback for writing data to the clipboard. + * Optional and can be NULL. + * + * @note Used for testing X11 clipboard code. + * + * @returns VBox status code. + * @param pCtx Opaque context pointer for the glue code. + * @param uFmt The format in which the data should be written as + * (VBOX_SHCL_FMT_XXX). + * @param pv The clipboard data to write. + * @param cb The size of the data in @a pv. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NULL. + */ + DECLCALLBACKMEMBER(int, pfnOnClipboardWrite, (PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void *pv, size_t cb, void *pvUser)); + + /** + * Callback for requesting clipboard data from the source. + * + * @note On X11: + * The function will be invoked for every single target the clipboard requests. + * Runs in Xt event thread for the X11 code. + * + * @returns VBox status code. VERR_NO_DATA if no data available. + * @param pCtx Opaque context pointer for the glue code. + * @param uFmt The format in which the data should be transferred + * (VBOX_SHCL_FMT_XXX). + * @param ppv Returns an allocated buffer with data read from the guest on success. + * Needs to be free'd with RTMemFree() by the caller. + * @param pcb Returns the amount of data read (in bytes) on success. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NULL. + * On X11: Of type PSHCLX11READDATAREQ; We RTMemFree() this in this function. + */ + DECLCALLBACKMEMBER(int, pfnOnRequestDataFromSource, (PSHCLCONTEXT pCtx, SHCLFORMAT uFmt, void **ppv, uint32_t *pcb, void *pvUser)); + + /** + * Callback for sending clipboard data to the destination. + * + * @returns VBox status code. + * @param pCtx Opaque context pointer for the glue code. + * @param pv The clipboard data returned if the request succeeded. + * @param cb The size of the data in @a pv. + * @param pvUser Implementation-dependent pointer to data for fullfilling the request. + * Optional and can be NUL + * On X11: Of type PSHCLX11READDATAREQ. + */ + DECLCALLBACKMEMBER(int, pfnOnSendDataToDest, (PSHCLCONTEXT pCtx, void *pv, uint32_t cb, void *pvUser)); +} SHCLCALLBACKS; +typedef SHCLCALLBACKS *PSHCLCALLBACKS; +/** @} */ + +/** Opaque request structure for X11 clipboard data. + * @{ */ +struct CLIPREADCBREQ; +typedef struct CLIPREADCBREQ CLIPREADCBREQ; +/** @} */ + +#endif /* !VBOX_INCLUDED_GuestHost_SharedClipboard_h */ + diff --git a/include/VBox/GuestHost/clipboard-helper.h b/include/VBox/GuestHost/clipboard-helper.h new file mode 100644 index 00000000..e1c4ad9d --- /dev/null +++ b/include/VBox/GuestHost/clipboard-helper.h @@ -0,0 +1,250 @@ +/* $Id: clipboard-helper.h $ */ +/** @file + * Shared Clipboard - Some helper function for converting between the various EOLs. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_GuestHost_clipboard_helper_h +#define VBOX_INCLUDED_GuestHost_clipboard_helper_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#include + +/** Constants needed for string conversions done by the Linux/Mac clipboard code. */ +enum +{ + /** In Linux, lines end with a linefeed character. */ + VBOX_SHCL_LINEFEED = 0xa, + /** In Windows, lines end with a carriage return and a linefeed character. */ + VBOX_SHCL_CARRIAGERETURN = 0xd, + /** Little endian "real" UTF-16 strings start with this marker. */ + VBOX_SHCL_UTF16LEMARKER = 0xfeff, + /** Big endian "real" UTF-16 strings start with this marker. */ + VBOX_SHCL_UTF16BEMARKER = 0xfffe +}; + +/** + * Returns the length (in UTF-8 characters) of an UTF-16 string with LF EOL. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to return size for. + * @param cwcSrc Length of the string in RTUTF16 units. + * @param pchLen Where to return the length (in UTF-8 characters). + * Does not include terminator. + */ +int ShClUtf16LFLenUtf8(PCRTUTF16 pcwszSrc, size_t cwcSrc, size_t *pchLen); + +/** + * Returns the length (in UTF-8 characters) of an UTF-16 string with CRLF EOL. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to return size for. + * @param cwcSrc Length of the source string in RTUTF16 units. + * @param pchLen Where to return the length (in UTF-8 characters). + * Does not include terminator. + */ +int ShClUtf16CRLFLenUtf8(PCRTUTF16 pcwszSrc, size_t cwcSrc, size_t *pchLen); + +/** + * Returns the length (in characters) of an UTF-16 string, including terminator. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to return size for. + * @param cwcSrc Length of the source string in RTUTF16 units. + * @param pchLen Where to return the length (in UTF-8 characters). + * Does not include terminator. + */ +int ShClUtf16LenUtf8(PCRTUTF16 pcwszSrc, size_t cwcSrc, size_t *pchLen); + +/** + * Converts an UTF-16 string with LF EOL to an UTF-16 string with CRLF EOL. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to convert. + * @param cwcSrc Size of the string int RTUTF16 units. + * @param pwszDst Buffer to store the converted string to. + * @param cwcDst The size of \a pwszDst in RTUTF16 units. + */ +int ShClConvUtf16LFToCRLF(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 pwszDst, size_t cwcDst); + +/** + * Converts an UTF-16 string with LF EOL to an UTF-16 string with CRLF EOL. + * + * Convenience function which returns the allocated + converted string on success. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to convert. + * @param cwcSrc Size of the string int RTUTF16 units. + * @param ppwszDst Where to return the allocated converted string. Must be free'd by the caller. + * @param pcwDst Where to return the size of the converted string in RTUTF16 units. + * Does not include the terminator. + */ +int ShClConvUtf16LFToCRLFA(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 *ppwszDst, size_t *pcwDst); + +/** + * Converts an UTF-16 string with CRLF EOL to an UTF-16 string with LF EOL. + * + * @returns VBox status code. + * @param pcwszSrc UTF-16 string to convert. + * @param cwcSrc Size of the string in RTUTF16 units. + * @param pwszDst Where to store the converted string to. + * @param cwcDst The size of \a pwszDst in RTUTF16 units. + */ +int ShClConvUtf16CRLFToLF(PCRTUTF16 pcwszSrc, size_t cwcSrc, PRTUTF16 pwszDst, size_t cwcDst); + +/** + * Converts an UTF-16 string with CRLF EOL to UTF-8 LF. + * + * @returns VBox status code. Will return VERR_NO_DATA if no data was converted. + * @param pcwszSrc UTF-16 string to convert. + * @param cbSrc Length of @a pwszSrc (in bytes). + * @param pszBuf Where to write the converted string. + * @param cbBuf The size of the buffer pointed to by @a pszBuf. + * @param pcbLen Where to store the size (in bytes) of the converted string. + * Does not include terminator. + */ +int ShClConvUtf16CRLFToUtf8LF(PCRTUTF16 pcwszSrc, size_t cbSrc, char *pszBuf, size_t cbBuf, size_t *pcbLen); + +/** +* Converts an HTML string from UTF-16 into UTF-8. +* +* @returns VBox status code. +* @param pcwszSrc UTF-16 string to convert. +* @param cwcSrc Length (in RTUTF16 units) of the source text. +* @param ppszDst Where to store the converted result on success. +* @param pcbDst Where to store the number of bytes written. +*/ +int ShClConvUtf16ToUtf8HTML(PCRTUTF16 pcwszSrc, size_t cwcSrc, char **ppszDst, size_t *pcbDst); + +/** + * Converts an UTF-8 string with LF EOL into UTF-16 CRLF. + * + * @returns VBox status code. + * @param pcszSrc UTF-8 string to convert. + * @param cbSrc Size of UTF-8 string to convert (in bytes), not counting the terminating zero. + * @param ppwszDst Where to return the allocated buffer on success. + * @param pcwDst Where to return the size (in RTUTF16 units) of the allocated buffer on success. + * Does not include terminator. + */ +int ShClConvUtf8LFToUtf16CRLF(const char *pcszSrc, size_t cbSrc, PRTUTF16 *ppwszDst, size_t *pcwDst); + +/** + * Converts a Latin-1 string with LF EOL into UTF-16 CRLF. + * + * @returns VBox status code. + * @param pcszSrc UTF-8 string to convert. + * @param cbSrc Size of string (in bytes), not counting the terminating zero. + * @param ppwszDst Where to return the allocated buffer on success. + * @param pcwDst Where to return the size (in RTUTF16 units) of the allocated buffer on success. + * Does not include terminator. + */ +int ShClConvLatin1LFToUtf16CRLF(const char *pcszSrc, size_t cbSrc, PRTUTF16 *ppwszDst, size_t *pcwDst); + +/** + * Convert CF_DIB data to full BMP data by prepending the BM header. + * Allocates with RTMemAlloc. + * + * @returns VBox status code. + * @param pvSrc DIB data to convert + * @param cbSrc Size of the DIB data to convert in bytes + * @param ppvDst Where to store the pointer to the buffer for the + * destination data + * @param pcbDst Pointer to the size of the buffer for the destination + * data in bytes. + */ +int ShClDibToBmp(const void *pvSrc, size_t cbSrc, void **ppvDst, size_t *pcbDst); + +/** + * Get the address and size of CF_DIB data in a full BMP data in the input buffer. + * Does not do any allocation. + * + * @returns VBox status code. + * @param pvSrc BMP data to convert + * @param cbSrc Size of the BMP data to convert in bytes + * @param ppvDst Where to store the pointer to the destination data + * @param pcbDst Pointer to the size of the destination data in bytes + */ +int ShClBmpGetDib(const void *pvSrc, size_t cbSrc, const void **ppvDst, size_t *pcbDst); + +#ifdef LOG_ENABLED +/** + * Dumps HTML data to the debug log. + * + * @returns VBox status code. + * @param pszSrc HTML data to dump. + * @param cbSrc Size (in bytes) of HTML data to dump. + */ +int ShClDbgDumpHtml(const char *pszSrc, size_t cbSrc); + +/** + * Dumps data using a specified clipboard format. + * + * @param pv Pointer to data to dump. + * @param cb Size (in bytes) of data to dump. + * @param u32Format Clipboard format to use for dumping. + */ +void ShClDbgDumpData(const void *pv, size_t cb, SHCLFORMAT u32Format); +#endif /* LOG_ENABLED */ + +/** + * Translates a Shared Clipboard host function number to a string. + * + * @returns Function ID string name. + * @param uFn The function to translate. + */ +const char *ShClHostFunctionToStr(uint32_t uFn); + +/** + * Translates a Shared Clipboard host message enum to a string. + * + * @returns Message ID string name. + * @param uMsg The message to translate. + */ +const char *ShClHostMsgToStr(uint32_t uMsg); + +/** + * Translates a Shared Clipboard guest message enum to a string. + * + * @returns Message ID string name. + * @param uMsg The message to translate. + */ +const char *ShClGuestMsgToStr(uint32_t uMsg); + +char *ShClFormatsToStrA(SHCLFORMATS fFormats); + +#endif /* !VBOX_INCLUDED_GuestHost_clipboard_helper_h */ + diff --git a/include/VBox/HostServices/DragAndDropSvc.h b/include/VBox/HostServices/DragAndDropSvc.h new file mode 100644 index 00000000..ba42cdef --- /dev/null +++ b/include/VBox/HostServices/DragAndDropSvc.h @@ -0,0 +1,1198 @@ +/* $Id: DragAndDropSvc.h $ */ +/** @file + * Drag and Drop service - Common header for host service and guest clients. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/** + * Protocol handling and notes: + * All client/server components should be backwards compatible. + * + ****************************************************************************** + * + * Protocol changelog: + * + * Protocol v1 (VBox < 5.0, deprecated): + * | Initial implementation which only implemented host to guest transfers. + * | For file transfers all file information such as the file name and file size were + * transferred with every file data chunk being sent. + * + * Protocol v2 (VBox 5.0 - VBox 5.0.8, deprecated): + * + Added support for guest to host transfers. + * + Added protocol version support through VBOXDNDCONNECTMSG. The host takes the installed + * Guest Additions version as indicator which protocol to use for communicating with the guest. + * The guest itself uses VBOXDNDCONNECTMSG to report its supported protocol version to the DnD service. + * + * Protocol v3 (VBox 5.0.10 and up, deprecated): + * + Added VBOXDNDDISCONNECTMSG for being able to track client disconnects on host side (Main). + * + Added context IDs for every HGCM message. Not used yet and must be 0. + * + Added VBOXDNDSNDDATAHDR and VBOXDNDCBSNDDATAHDRDATA to support (simple) accounting of objects + * being transferred, along with supplying separate meta data size (which is part of the total size being sent). + * + Added new HOST_DND_FN_HG_SND_DATA_HDR + GUEST_DND_FN_GH_SND_DATA_HDR commands which now allow specifying an optional + * compression type and defining a checksum for the overall data transfer. + * + Enhannced VBOXDNDGHSENDDATAMSG to support (rolling) checksums for the supplied data block. + * + VBOXDNDHGSENDDATAMSG and VBOXDNDGHSENDDATAMSG can now contain an optional checksum for the current data block. + * | VBOXDNDHGSENDFILEDATAMSG and VBOXDNDGHSENDFILEDATAMSG are now sharing the same HGCM mesasge. + * - Removed unused HOST_DND_FN_GH_RECV_DIR, HOST_DND_FN_GH_RECV_FILE_DATA and HOST_DND_FN_GH_RECV_FILE_HDR commands. + * + * VBox 6.1.x and up, current: + * + Added GUEST_DND_FN_QUERY_FEATURES + GUEST_DND_FN_REPORT_FEATURES. + * - Protocol versioning support in VBOXDNDCONNECTMSG is now marked as being deprecated. + * + ** @todo: + * - Split up messages which use VBOXDNDHGACTIONMSG into own functions and remove parameters which + * are not actually needed / used by a function. Why does HOST_DND_FN_HG_EVT_MOVE need all the format stuff, for example? + */ + +#ifndef VBOX_INCLUDED_HostServices_DragAndDropSvc_h +#define VBOX_INCLUDED_HostServices_DragAndDropSvc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +#include + +namespace DragAndDropSvc { + +/****************************************************************************** +* Typedefs, constants and inlines * +******************************************************************************/ + +/** + * The service functions which are callable by host. + * Note: When adding new functions to this table, make sure that the actual ID + * does *not* overlap with the eGuestFn enumeration below! + */ +enum eHostFn +{ + /** The host sets a new DnD mode. */ + HOST_DND_FN_SET_MODE = 100, + /** The host requests to cancel the current DnD operation on + * the guest side. This can happen on user request on the host's + * UI side or due to some host error which has happened. + * + * Note: This is a fire-and-forget message, as the host should + * not rely on an answer from the guest side in order to + * properly cancel the operation. */ + HOST_DND_FN_CANCEL = 204, + + /* + * Host -> Guest messages + */ + + /** The host enters the VM window for starting an actual + * DnD operation. */ + HOST_DND_FN_HG_EVT_ENTER = 200, + /** The host's DnD cursor moves within the VM window. */ + HOST_DND_FN_HG_EVT_MOVE = 201, + /** The host leaves the guest VM window. */ + HOST_DND_FN_HG_EVT_LEAVE = 202, + /** The host issues a "drop" event, meaning that the host is + * ready to transfer data over to the guest. */ + HOST_DND_FN_HG_EVT_DROPPED = 203, + /** The host sends the data header at the beginning of a (new) + * data transfer. */ + HOST_DND_FN_HG_SND_DATA_HDR = 210, + /** + * The host sends the actual meta data, based on + * the format(s) specified by HOST_DND_FN_HG_EVT_ENTER. + * + * Protocol v1/v2: If the guest supplied buffer too small to send + * the actual data, the host will send a HOST_DND_FN_HG_SND_MORE_DATA + * message as follow-up. + * Protocol v3+: The incoming meta data size is specified upfront in the + * HOST_DND_FN_HG_SND_DATA_HDR message and must be handled accordingly. + */ + HOST_DND_FN_HG_SND_DATA = 205, + /** The host sends more data in case the data did not entirely fit in + * the HOST_DND_FN_HG_SND_DATA message. */ + /** @todo Deprecated function; do not use anymore. */ + HOST_DND_FN_HG_SND_MORE_DATA = 206, + /** The host sends a directory entry to the guest. */ + HOST_DND_FN_HG_SND_DIR = 207, + /** The host sends a file data chunk to the guest. */ + HOST_DND_FN_HG_SND_FILE_DATA = 208, + /** The host sends a file header to the guest. + * Note: Only for protocol version 2 and up (>= VBox 5.0). */ + HOST_DND_FN_HG_SND_FILE_HDR = 209, + + /* + * Guest -> Host messages + */ + + /** The host asks the guest whether a DnD operation + * is in progress when the mouse leaves the guest window. */ + HOST_DND_FN_GH_REQ_PENDING = 600, + /** The host informs the guest that a DnD drop operation + * has been started and that the host wants the data in + * a specific MIME type. */ + HOST_DND_FN_GH_EVT_DROPPED = 601, + /** Blow the type up to 32-bit. */ + HOST_DND_FN_32BIT_HACK = 0x7fffffff +}; + +/** + * The service functions which are called by guest. + * Note: When adding new functions to this table, make sure that the actual ID + * does *not* overlap with the eHostFn enumeration above! + */ +enum eGuestFn +{ + /** + * The guest sends a connection request to the HGCM service, + * along with some additional information like supported + * protocol version and flags. + * Note: New since protocol version 2. */ + GUEST_DND_FN_CONNECT = 10, + + /** The guest client disconnects from the HGCM service. */ + GUEST_DND_FN_DISCONNECT = 11, + + /** Report guest side feature flags and retrieve the host ones. + * + * Two 64-bit parameters are passed in from the guest with the guest features + * (VBOX_DND_GF_XXX), the host replies by replacing the parameter values with + * the host ones (VBOX_DND_HF_XXX). + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ + GUEST_DND_FN_REPORT_FEATURES = 12, + + /** Query the host ones feature masks. + * + * That way the guest (client) can get hold of the features from the host. + * Again, it is prudent to set the 127 bit and observe it being cleared on + * success, as older hosts might return success without doing anything. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ + GUEST_DND_FN_QUERY_FEATURES = 13, + + /** + * The guest waits for a new message the host wants to process + * on the guest side. This can be a blocking call. + */ + GUEST_DND_FN_GET_NEXT_HOST_MSG = 300, + + /** Reports back an error to the host. + * + * Note: Don't change the ID to also support older hosts + * (was GUEST_DND_FN_GH_EVT_ERROR before < 7.0, only for G->H transfers). + * + * This was changed to GUEST_DND_FN_EVT_ERROR to be a generic event + * that also can be used for H->G transfers. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 7.0.x + */ + GUEST_DND_FN_EVT_ERROR = 502, + + /* + * Host -> Guest operation messages. + */ + + /** The guest acknowledges that a pending DnD operation from the host + * can be dropped on the currently selected area on the guest. */ + GUEST_DND_FN_HG_ACK_OP = 400, + /** The guest requests the actual DnD data to be sent from the host. */ + GUEST_DND_FN_HG_REQ_DATA = 401, + /** The guest reports back its progress back to the host. */ + GUEST_DND_FN_HG_EVT_PROGRESS = 402, + + /* + * Guest -> Host operation messages. + */ + + /** + * The guests acknowledges that it currently has a drag'n drop + * operation in progress on the guest, which eventually could be + * dragged over to the host. + */ + GUEST_DND_FN_GH_ACK_PENDING = 500, + /** The guest sends the data header at the beginning of a (new) + * data transfer. */ + GUEST_DND_FN_GH_SND_DATA_HDR = 503, + /** + * The guest sends data of the requested format to the host. There can + * be more than one message if the actual data does not fit + * into one. + */ + GUEST_DND_FN_GH_SND_DATA = 501, + /** The guest sends a directory entry to the host. */ + GUEST_DND_FN_GH_SND_DIR = 700, + /** The guest sends file data to the host. + * Note: On protocol version 1 this also contains the file name + * and other attributes. */ + GUEST_DND_FN_GH_SND_FILE_DATA = 701, + /** The guest sends a file header to the host, marking the + * beginning of a (new) file transfer. + * Note: Available since protocol version 2 (VBox 5.0). */ + GUEST_DND_FN_GH_SND_FILE_HDR = 702, + /** Blow the type up to 32-bit. */ + GUEST_DND_FN_32BIT_HACK = 0x7fffffff +}; + +/** @name VBOX_DND_GF_XXX - Guest features. + * @sa GUEST_DND_FN_REPORT_FEATURES + * @{ */ +/** No flags set. */ +#define VBOX_DND_GF_NONE 0 +/** Bit that must be set in the 2nd parameter, will be cleared if the host reponds + * correctly (old hosts might not). */ +#define VBOX_DND_GF_1_MUST_BE_ONE RT_BIT_64(63) +/** @} */ + +/** @name VBOX_DND_HF_XXX - Host features. + * @sa DND_GUEST_REPORT_FEATURES + * @{ */ +/** No flags set. */ +#define VBOX_DND_HF_NONE 0 +/** @} */ + +/** + * DnD operation progress states. + */ +typedef enum DNDPROGRESS +{ + DND_PROGRESS_UNKNOWN = 0, + DND_PROGRESS_RUNNING = 1, + DND_PROGRESS_COMPLETE, + DND_PROGRESS_CANCELLED, + DND_PROGRESS_ERROR, + /** Blow the type up to 32-bit. */ + DND_PROGRESS_32BIT_HACK = 0x7fffffff +} DNDPROGRESS, *PDNDPROGRESS; + +#pragma pack (1) + +/* + * Host events + */ + +/** + * Action message for telling the guest about the currently ongoing + * drag and drop action when entering the guest's area, moving around in it + * and dropping content into it from the host. + * + * Used by: + * HOST_DND_FN_HG_EVT_ENTER + * HOST_DND_FN_HG_EVT_MOVE + * HOST_DND_FN_HG_EVT_DROPPED + */ +typedef struct HGCMMsgHGAction +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter uScreenId; /* OUT uint32_t */ + HGCMFunctionParameter uX; /* OUT uint32_t */ + HGCMFunctionParameter uY; /* OUT uint32_t */ + HGCMFunctionParameter uDefAction; /* OUT uint32_t */ + HGCMFunctionParameter uAllActions; /* OUT uint32_t */ + HGCMFunctionParameter pvFormats; /* OUT ptr */ + HGCMFunctionParameter cbFormats; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. */ + HGCMFunctionParameter uContext; + HGCMFunctionParameter uScreenId; /* OUT uint32_t */ + HGCMFunctionParameter uX; /* OUT uint32_t */ + HGCMFunctionParameter uY; /* OUT uint32_t */ + HGCMFunctionParameter uDefAction; /* OUT uint32_t */ + HGCMFunctionParameter uAllActions; /* OUT uint32_t */ + HGCMFunctionParameter pvFormats; /* OUT ptr */ + HGCMFunctionParameter cbFormats; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGAction; + +/** + * Tells the guest that the host has left its drag and drop area on the guest. + * + * Used by: + * HOST_DND_FN_HG_EVT_LEAVE + */ +typedef struct HGCMMsgHGLeave +{ + VBGLIOCHGCMCALL hdr; + union + { + struct + { + /** Context ID. */ + HGCMFunctionParameter uContext; + } v3; + } u; +} HGCMMsgHGLeave; + +/** + * Tells the guest that the host wants to cancel the current drag and drop operation. + * + * Used by: + * HOST_DND_FN_HG_EVT_CANCEL + */ +typedef struct HGCMMsgHGCancel +{ + VBGLIOCHGCMCALL hdr; + union + { + struct + { + /** Context ID. */ + HGCMFunctionParameter uContext; + } v3; + } u; +} HGCMMsgHGCancel; + +/** + * Sends the header of an incoming (meta) data block. + * + * Used by: + * HOST_DND_FN_HG_SND_DATA_HDR + * GUEST_DND_FN_GH_SND_DATA_HDR + * + * New since protocol v3. + */ +typedef struct HGCMMsgHGSendDataHdr +{ + VBGLIOCHGCMCALL hdr; + + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Data transfer flags. Not yet used and must be 0. */ + HGCMFunctionParameter uFlags; /* OUT uint32_t */ + /** Screen ID where the data originates from. */ + HGCMFunctionParameter uScreenId; /* OUT uint32_t */ + /** Total size (in bytes) to transfer. */ + HGCMFunctionParameter cbTotal; /* OUT uint64_t */ + /** + * Total meta data size (in bytes) to transfer. + * This size also is part of cbTotal already, so: + * + * cbTotal = cbMeta + additional size for files etc. + */ + HGCMFunctionParameter cbMeta; /* OUT uint64_t */ + /** Meta data format. */ + HGCMFunctionParameter pvMetaFmt; /* OUT ptr */ + /** Size (in bytes) of meta data format. */ + HGCMFunctionParameter cbMetaFmt; /* OUT uint32_t */ + /* Number of objects (files/directories) to transfer. */ + HGCMFunctionParameter cObjects; /* OUT uint64_t */ + /** Compression type. */ + HGCMFunctionParameter enmCompression; /* OUT uint32_t */ + /** Checksum type. */ + HGCMFunctionParameter enmChecksumType; /* OUT uint32_t */ + /** Checksum buffer for the entire data to be transferred. */ + HGCMFunctionParameter pvChecksum; /* OUT ptr */ + /** Size (in bytes) of checksum. */ + HGCMFunctionParameter cbChecksum; /* OUT uint32_t */ +} HGCMMsgHGSendDataHdr; + +/** + * Sends a (meta) data block to the guest. + * + * Used by: + * HOST_DND_FN_HG_SND_DATA + */ +typedef struct HGCMMsgHGSendData +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter uScreenId; /* OUT uint32_t */ + HGCMFunctionParameter pvFormat; /* OUT ptr */ + HGCMFunctionParameter cbFormat; /* OUT uint32_t */ + HGCMFunctionParameter pvData; /* OUT ptr */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ + } v1; + /* No changes in v2. */ + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Data block to send. */ + HGCMFunctionParameter pvData; /* OUT ptr */ + /** Size (in bytes) of data block to send. */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ + /** Checksum of data block, based on the checksum + * type in the data header. Optional. */ + HGCMFunctionParameter pvChecksum; /* OUT ptr */ + /** Size (in bytes) of checksum to send. */ + HGCMFunctionParameter cbChecksum; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGSendData; + +/** + * Sends more (meta) data in case the data didn't fit + * into the current XXX_DND_HG_SND_DATA message. + * + ** @todo Deprecated since protocol v3. Don't use! Will be removed. + * + * Used by: + * HOST_DND_FN_HG_SND_MORE_DATA + */ +typedef struct HGCMMsgHGSendMoreData +{ + VBGLIOCHGCMCALL hdr; + + HGCMFunctionParameter pvData; /* OUT ptr */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ +} HGCMMsgHGSendMoreData; + +/** + * Directory entry event. + * + * Used by: + * HOST_DND_FN_HG_SND_DIR + * GUEST_DND_FN_GH_SND_DIR + */ +typedef struct HGCMMsgHGSendDir +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + /** Directory name. */ + HGCMFunctionParameter pvName; /* OUT ptr */ + /** Size (in bytes) of directory name. */ + HGCMFunctionParameter cbName; /* OUT uint32_t */ + /** Directory mode. */ + HGCMFunctionParameter fMode; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Directory name. */ + HGCMFunctionParameter pvName; /* OUT ptr */ + /** Size (in bytes) of directory name. */ + HGCMFunctionParameter cbName; /* OUT uint32_t */ + /** Directory mode. */ + HGCMFunctionParameter fMode; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGSendDir; + +/** + * File header message, marking the start of transferring a new file. + * Note: Only for protocol version 2 and up. + * + * Used by: + * HOST_DND_FN_HG_SND_FILE_HDR + * GUEST_DND_FN_GH_SND_FILE_HDR + */ +typedef struct HGCMMsgHGSendFileHdr +{ + VBGLIOCHGCMCALL hdr; + + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** File path. */ + HGCMFunctionParameter pvName; /* OUT ptr */ + /** Size (in bytes) of file path. */ + HGCMFunctionParameter cbName; /* OUT uint32_t */ + /** Optional flags; unused at the moment. */ + HGCMFunctionParameter uFlags; /* OUT uint32_t */ + /** File creation mode. */ + HGCMFunctionParameter fMode; /* OUT uint32_t */ + /** Total size (in bytes). */ + HGCMFunctionParameter cbTotal; /* OUT uint64_t */ +} HGCMMsgHGSendFileHdr; + +/** + * HG: File data (chunk) event. + * + * Used by: + * HOST_DND_FN_HG_SND_FILE + */ +typedef struct HGCMMsgHGSendFileData +{ + VBGLIOCHGCMCALL hdr; + + union + { + /* Note: Protocol v1 sends the file name + file mode + * every time a file data chunk is being sent. */ + struct + { + /** File name. */ + HGCMFunctionParameter pvName; /* OUT ptr */ + /** Size (in bytes) of file name. */ + HGCMFunctionParameter cbName; /* OUT uint32_t */ + /** Current data chunk. */ + HGCMFunctionParameter pvData; /* OUT ptr */ + /** Size (in bytes) of current data chunk. */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ + /** File mode. */ + HGCMFunctionParameter fMode; /* OUT uint32_t */ + } v1; + struct + { + /** Note: pvName is now part of the VBOXDNDHGSENDFILEHDRMSG message. */ + /** Note: cbName is now part of the VBOXDNDHGSENDFILEHDRMSG message. */ + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Current data chunk. */ + HGCMFunctionParameter pvData; /* OUT ptr */ + /** Size (in bytes) of current data chunk. */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ + /** Note: fMode is now part of the VBOXDNDHGSENDFILEHDRMSG message. */ + } v2; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Current data chunk. */ + HGCMFunctionParameter pvData; /* OUT ptr */ + /** Size (in bytes) of current data chunk. */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ + /** Checksum of data block, based on the checksum + * type in the data header. Optional. */ + HGCMFunctionParameter pvChecksum; /* OUT ptr */ + /** Size (in bytes) of curren data chunk checksum. */ + HGCMFunctionParameter cbChecksum; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGSendFileData; + +/** + * Asks the guest if a guest->host DnD operation is in progress. + * + * Used by: + * HOST_DND_FN_GH_REQ_PENDING + */ +typedef struct HGCMMsgGHReqPending +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + /** Screen ID. */ + HGCMFunctionParameter uScreenId; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Screen ID. */ + HGCMFunctionParameter uScreenId; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgGHReqPending; + +/** + * Tells the guest that the host has dropped the ongoing guest->host + * DnD operation on a valid target on the host. + * + * Used by: + * HOST_DND_FN_GH_EVT_DROPPED + */ +typedef struct HGCMMsgGHDropped +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + /** Requested format for sending the data. */ + HGCMFunctionParameter pvFormat; /* OUT ptr */ + /** Size (in bytes) of requested format. */ + HGCMFunctionParameter cbFormat; /* OUT uint32_t */ + /** Drop action peformed on the host. */ + HGCMFunctionParameter uAction; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Requested format for sending the data. */ + HGCMFunctionParameter pvFormat; /* OUT ptr */ + /** Size (in bytes) of requested format. */ + HGCMFunctionParameter cbFormat; /* OUT uint32_t */ + /** Drop action peformed on the host. */ + HGCMFunctionParameter uAction; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgGHDropped; + +/* + * Guest events + */ + +/** + * Asks the host for the next command to process, along + * with the needed amount of parameters and an optional blocking + * flag. + * + * Used by: + * GUEST_DND_FN_GET_NEXT_HOST_MSG + */ +typedef struct HGCMMsgGetNext +{ + VBGLIOCHGCMCALL hdr; + + /** Message ID. */ + HGCMFunctionParameter uMsg; /* OUT uint32_t */ + /** Number of parameters the message needs. */ + HGCMFunctionParameter cParms; /* OUT uint32_t */ + /** Whether or not to block (wait) for a + * new message to arrive. */ + HGCMFunctionParameter fBlock; /* OUT uint32_t */ +} HGCMMsgGetNext; + +/** + * Guest connection request. Used to tell the DnD protocol + * version to the (host) service. + * + * Used by: + * GUEST_DND_FN_CONNECT + */ +typedef struct HGCMMsgConnect +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + /** Protocol version to use. + * Deprecated since VBox 6.1.x. Do not use / rely on it anymore. */ + HGCMFunctionParameter uProtocol; /* OUT uint32_t */ + /** Connection flags. Optional. */ + HGCMFunctionParameter uFlags; /* OUT uint32_t */ + } v2; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Protocol version to use. + * Deprecated since VBox 6.1.x. Do not use / rely on it anymore. */ + HGCMFunctionParameter uProtocol; /* OUT uint32_t */ + /** Connection flags. Optional. */ + HGCMFunctionParameter uFlags; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgConnect; + +/** + * Acknowledges a host operation along with the allowed + * action(s) on the guest. + * + * Used by: + * GUEST_DND_FN_HG_ACK_OP + */ +typedef struct HGCMMsgHGAck +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter uAction; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + HGCMFunctionParameter uAction; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGAck; + +/** + * Requests data to be sent to the guest. + * + * Used by: + * GUEST_DND_FN_HG_REQ_DATA + */ +typedef struct HGCMMsgHGReqData +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter pvFormat; /* OUT ptr */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + HGCMFunctionParameter pvFormat; /* OUT ptr */ + HGCMFunctionParameter cbFormat; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGReqData; + +typedef struct HGCMMsgHGProgress +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter uStatus; /* OUT uint32_t */ + HGCMFunctionParameter uPercent; /* OUT uint32_t */ + HGCMFunctionParameter rc; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + HGCMFunctionParameter uStatus; /* OUT uint32_t */ + HGCMFunctionParameter uPercent; /* OUT uint32_t */ + HGCMFunctionParameter rc; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgHGProgress; + +/** + * Acknowledges a pending guest drag and drop event to the host. + * + * Used by: + * GUEST_DND_FN_GH_ACK_PENDING + */ +typedef struct HGCMMsgGHAckPending +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter uDefAction; /* OUT uint32_t */ + HGCMFunctionParameter uAllActions; /* OUT uint32_t */ + HGCMFunctionParameter pvFormats; /* OUT ptr */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + HGCMFunctionParameter uDefAction; /* OUT uint32_t */ + HGCMFunctionParameter uAllActions; /* OUT uint32_t */ + HGCMFunctionParameter pvFormats; /* OUT ptr */ + HGCMFunctionParameter cbFormats; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgGHAckPending; + +/** + * Sends the header of an incoming data block + * to the host. + * + * Used by: + * GUEST_DND_FN_GH_SND_DATA_HDR + * + * New since protocol v3. + */ +typedef struct HGCMMsgHGSendDataHdr HGCMMsgGHSendDataHdr; + +/** + * Sends a (meta) data block to the host. + * + * Used by: + * GUEST_DND_FN_GH_SND_DATA + */ +typedef struct HGCMMsgGHSendData +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter pvData; /* OUT ptr */ + /** Total bytes to send. This can be more than + * the data block specified in pvData above, e.g. + * when sending over file objects afterwards. */ + HGCMFunctionParameter cbTotalBytes; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + /** Data block to send. */ + HGCMFunctionParameter pvData; /* OUT ptr */ + /** Size (in bytes) of data block to send. */ + HGCMFunctionParameter cbData; /* OUT uint32_t */ + /** (Rolling) Checksum, based on checksum type in data header. */ + HGCMFunctionParameter pvChecksum; /* OUT ptr */ + /** Size (in bytes) of checksum. */ + HGCMFunctionParameter cbChecksum; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgGHSendData; + +/** + * Sends a directory entry to the host. + * + * Used by: + * GUEST_DND_FN_GH_SND_DIR + */ +typedef struct HGCMMsgHGSendDir HGCMMsgGHSendDir; + +/** + * Sends a file header to the host. + * + * Used by: + * GUEST_DND_FN_GH_SND_FILE_HDR + * + * New since protocol v2. + */ +typedef struct HGCMMsgHGSendFileHdr HGCMMsgGHSendFileHdr; + +/** + * Sends file data to the host. + * + * Used by: + * GUEST_DND_FN_GH_SND_FILE_DATA + */ +typedef struct HGCMMsgHGSendFileData HGCMMsgGHSendFileData; + +/** + * Sends a guest error event to the host. + * + * Used by: + * GUEST_DND_FN_GH_EVT_ERROR + */ +typedef struct HGCMMsgGHError +{ + VBGLIOCHGCMCALL hdr; + + union + { + struct + { + HGCMFunctionParameter rc; /* OUT uint32_t */ + } v1; + struct + { + /** Context ID. Unused at the moment. */ + HGCMFunctionParameter uContext; /* OUT uint32_t */ + HGCMFunctionParameter rc; /* OUT uint32_t */ + } v3; + } u; +} HGCMMsgGHError; + +#pragma pack() + +/** Builds a callback magic out of the function ID and the version + * of the callback data. */ +#define VBOX_DND_CB_MAGIC_MAKE(uFn, uVer) \ + RT_MAKE_U32(uVer, uFn) + +/* + * Callback magics. + */ +enum eDnDCallbackMagics +{ + CB_MAGIC_DND_CONNECT = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_CONNECT, 0), + CB_MAGIC_DND_REPORT_FEATURES = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_REPORT_FEATURES, 0), + CB_MAGIC_DND_EVT_ERROR = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_EVT_ERROR, 0), + CB_MAGIC_DND_HG_GET_NEXT_HOST_MSG = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GET_NEXT_HOST_MSG, 0), + CB_MAGIC_DND_HG_ACK_OP = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_HG_ACK_OP, 0), + CB_MAGIC_DND_HG_REQ_DATA = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_HG_REQ_DATA, 0), + CB_MAGIC_DND_HG_EVT_PROGRESS = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_HG_EVT_PROGRESS, 0), + CB_MAGIC_DND_GH_ACK_PENDING = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GH_ACK_PENDING, 0), + CB_MAGIC_DND_GH_SND_DATA = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GH_SND_DATA, 0), + CB_MAGIC_DND_GH_SND_DATA_HDR = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GH_SND_DATA_HDR, 0), + CB_MAGIC_DND_GH_SND_DIR = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GH_SND_DIR, 0), + CB_MAGIC_DND_GH_SND_FILE_HDR = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GH_SND_FILE_HDR, 0), + CB_MAGIC_DND_GH_SND_FILE_DATA = VBOX_DND_CB_MAGIC_MAKE(GUEST_DND_FN_GH_SND_FILE_DATA, 0) +}; + +typedef struct VBOXDNDCBHEADERDATA +{ + /** Magic number to identify the structure. */ + uint32_t uMagic; + /** Context ID to identify callback data. */ + uint32_t uContextID; +} VBOXDNDCBHEADERDATA, *PVBOXDNDCBHEADERDATA; + +typedef struct VBOXDNDCBCONNECTDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + /** Protocol version to use. + * Deprecated since VBox 6.1.x. Do not use / rely on it anymore. */ + uint32_t uProtocolVersion; + /** Connection flags; currently unused. */ + uint32_t fFlags; +} VBOXDNDCBCONNECTDATA, *PVBOXDNDCBCONNECTDATA; + +typedef struct VBOXDNDCBREPORTFEATURESDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + uint32_t fGuestFeatures0; +} VBOXDNDCBREPORTFEATURESDATA, *PVBOXDNDCBREPORTFEATURESDATA; + +typedef struct VBOXDNDCBDISCONNECTMSGDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; +} VBOXDNDCBDISCONNECTMSGDATA, *PVBOXDNDCBDISCONNECTMSGDATA; + +typedef struct VBOXDNDCBHGGETNEXTHOSTMSG +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + uint32_t uMsg; + uint32_t cParms; +} VBOXDNDCBHGGETNEXTHOSTMSG, *PVBOXDNDCBHGGETNEXTHOSTMSG; + +typedef struct VBOXDNDCBHGGETNEXTHOSTMSGDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + uint32_t uMsg; + uint32_t cParms; + PVBOXHGCMSVCPARM paParms; +} VBOXDNDCBHGGETNEXTHOSTMSGDATA, *PVBOXDNDCBHGGETNEXTHOSTMSGDATA; + +typedef struct VBOXDNDCBHGACKOPDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + uint32_t uAction; +} VBOXDNDCBHGACKOPDATA, *PVBOXDNDCBHGACKOPDATA; + +typedef struct VBOXDNDCBHGREQDATADATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + char *pszFormat; + uint32_t cbFormat; +} VBOXDNDCBHGREQDATADATA, *PVBOXDNDCBHGREQDATADATA; + +typedef struct VBOXDNDCBHGEVTPROGRESSDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + uint32_t uPercentage; + uint32_t uStatus; + uint32_t rc; +} VBOXDNDCBHGEVTPROGRESSDATA, *PVBOXDNDCBHGEVTPROGRESSDATA; + +typedef struct VBOXDNDCBGHACKPENDINGDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + uint32_t uDefAction; + uint32_t uAllActions; + char *pszFormat; + uint32_t cbFormat; +} VBOXDNDCBGHACKPENDINGDATA, *PVBOXDNDCBGHACKPENDINGDATA; + +/** + * Data header. + * New since protocol v3. + */ +typedef struct VBOXDNDDATAHDR +{ + /** Data transfer flags. Not yet used and must be 0. */ + uint32_t uFlags; + /** Screen ID where the data originates from. */ + uint32_t uScreenId; + /** Total size (in bytes) to transfer. */ + uint64_t cbTotal; + /** Meta data size (in bytes) to transfer. + * This size also is part of cbTotal already. */ + uint32_t cbMeta; + /** Meta format buffer. */ + void *pvMetaFmt; + /** Size (in bytes) of meta format buffer. */ + uint32_t cbMetaFmt; + /** Number of objects (files/directories) to transfer. */ + uint64_t cObjects; + /** Compression type. Currently unused, so specify 0. + **@todo Add IPRT compression type enumeration as soon as it's available. */ + uint32_t enmCompression; + /** Checksum type. Currently unused, so specify RTDIGESTTYPE_INVALID. */ + RTDIGESTTYPE enmChecksumType; + /** The actual checksum buffer for the entire data to be transferred, + * based on enmChksumType. If RTDIGESTTYPE_INVALID is specified, + * no checksum is being used and pvChecksum will be NULL. */ + void *pvChecksum; + /** Size (in bytes) of checksum. */ + uint32_t cbChecksum; +} VBOXDNDDATAHDR, *PVBOXDNDSNDDATAHDR; + +/* New since protocol v3. */ +typedef struct VBOXDNDCBSNDDATAHDRDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + /** Actual header data. */ + VBOXDNDDATAHDR data; +} VBOXDNDCBSNDDATAHDRDATA, *PVBOXDNDCBSNDDATAHDRDATA; + +typedef struct VBOXDNDSNDDATA +{ + union + { + struct + { + /** Data block buffer. */ + void *pvData; + /** Size (in bytes) of data block. */ + uint32_t cbData; + /** Total metadata size (in bytes). This is transmitted + * with every message because the size can change. */ + uint32_t cbTotalSize; + } v1; + /* Protocol v2: No changes. */ + struct + { + /** Data block buffer. */ + void *pvData; + /** Size (in bytes) of data block. */ + uint32_t cbData; + /** (Rolling) Checksum. Not yet implemented. */ + void *pvChecksum; + /** Size (in bytes) of checksum. Not yet implemented. */ + uint32_t cbChecksum; + } v3; + } u; +} VBOXDNDSNDDATA, *PVBOXDNDSNDDATA; + +typedef struct VBOXDNDCBSNDDATADATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + /** Actual data. */ + VBOXDNDSNDDATA data; +} VBOXDNDCBSNDDATADATA, *PVBOXDNDCBSNDDATADATA; + +typedef struct VBOXDNDCBSNDDIRDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + /** Directory path. */ + char *pszPath; + /** Size (in bytes) of path. */ + uint32_t cbPath; + /** Directory creation mode. */ + uint32_t fMode; +} VBOXDNDCBSNDDIRDATA, *PVBOXDNDCBSNDDIRDATA; + +/* Note: Only for protocol version 2 and up (>= VBox 5.0). */ +typedef struct VBOXDNDCBSNDFILEHDRDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + /** File path (name). */ + char *pszFilePath; + /** Size (in bytes) of file path. */ + uint32_t cbFilePath; + /** Total size (in bytes) of this file. */ + uint64_t cbSize; + /** File (creation) mode. */ + uint32_t fMode; + /** Additional flags. Not used at the moment. */ + uint32_t fFlags; +} VBOXDNDCBSNDFILEHDRDATA, *PVBOXDNDCBSNDFILEHDRDATA; + +typedef struct VBOXDNDCBSNDFILEDATADATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + /** Current file data chunk. */ + void *pvData; + /** Size (in bytes) of current data chunk. */ + uint32_t cbData; + union + { + struct + { + /** File path (name). */ + char *pszFilePath; + /** Size (in bytes) of file path. */ + uint32_t cbFilePath; + /** File (creation) mode. */ + uint32_t fMode; + } v1; + /* Protocol v2 + v3: Have the file attributes (name, size, mode, ...) + in the VBOXDNDCBSNDFILEHDRDATA structure. */ + struct + { + /** Checksum for current file data chunk. */ + void *pvChecksum; + /** Size (in bytes) of current data chunk. */ + uint32_t cbChecksum; + } v3; + } u; +} VBOXDNDCBSNDFILEDATADATA, *PVBOXDNDCBSNDFILEDATADATA; + +typedef struct VBOXDNDCBEVTERRORDATA +{ + /** Callback data header. */ + VBOXDNDCBHEADERDATA hdr; + int32_t rc; +} VBOXDNDCBEVTERRORDATA, *PVBOXDNDCBEVTERRORDATA; + +} /* namespace DragAndDropSvc */ + +#endif /* !VBOX_INCLUDED_HostServices_DragAndDropSvc_h */ + diff --git a/include/VBox/HostServices/GuestControlSvc.h b/include/VBox/HostServices/GuestControlSvc.h new file mode 100644 index 00000000..8ed0b2ba --- /dev/null +++ b/include/VBox/HostServices/GuestControlSvc.h @@ -0,0 +1,1500 @@ +/* $Id: GuestControlSvc.h $ */ +/** @file + * Guest control service - Common header for host service and guest clients. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_HostServices_GuestControlSvc_h +#define VBOX_INCLUDED_HostServices_GuestControlSvc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + +/* Everything defined in this file lives in this namespace. */ +namespace guestControl { + +/****************************************************************************** +* Typedefs, constants and inlines * +******************************************************************************/ + +#define HGCMSERVICE_NAME "VBoxGuestControlSvc" + +/** Maximum number of concurrent guest sessions a VM can have. */ +#define VBOX_GUESTCTRL_MAX_SESSIONS 32 +/** Maximum number of concurrent guest objects (processes, files, ...) + * a guest session can have. */ +#define VBOX_GUESTCTRL_MAX_OBJECTS _2K +/** Maximum of callback contexts a guest process can have. */ +#define VBOX_GUESTCTRL_MAX_CONTEXTS _64K + +/** Base (start) of guest control session IDs. Session + * ID 0 is reserved for the root process which + * hosts all other guest session processes. */ +#define VBOX_GUESTCTRL_SESSION_ID_BASE 1 + +/** Builds a context ID out of the session ID, object ID and an + * increasing count. */ +#define VBOX_GUESTCTRL_CONTEXTID_MAKE(uSession, uObject, uCount) \ + ( (uint32_t)((uSession) & 0x1f) << 27 \ + | (uint32_t)((uObject) & 0x7ff) << 16 \ + | (uint32_t)((uCount) & 0xffff) \ + ) +/** Creates a context ID out of a session ID. */ +#define VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(uSession) \ + ((uint32_t)((uSession) & 0x1f) << 27) +/** Gets the session ID out of a context ID. */ +#define VBOX_GUESTCTRL_CONTEXTID_GET_SESSION(uContextID) \ + (((uContextID) >> 27) & 0x1f) +/** Gets the process ID out of a context ID. */ +#define VBOX_GUESTCTRL_CONTEXTID_GET_OBJECT(uContextID) \ + (((uContextID) >> 16) & 0x7ff) +/** Gets the context count of a process out of a context ID. */ +#define VBOX_GUESTCTRL_CONTEXTID_GET_COUNT(uContextID) \ + ((uContextID) & 0xffff) +/** Filter context IDs by session. Can be used in conjunction + * with VbglR3GuestCtrlMsgFilterSet(). */ +#define VBOX_GUESTCTRL_FILTER_BY_SESSION(uSession) \ + (VBOX_GUESTCTRL_CONTEXTID_MAKE_SESSION(uSession) | 0xF8000000) + +/** + * Structure keeping the context of a host callback. + */ +typedef struct VBOXGUESTCTRLHOSTCBCTX +{ + /** HGCM message number. */ + uint32_t uMessage; + /** The context ID. */ + uint32_t uContextID; + /** Protocol version of this guest session. Might + * be 0 if not supported. */ + uint32_t uProtocol; +} VBOXGUESTCTRLHOSTCBCTX, *PVBOXGUESTCTRLHOSTCBCTX; + +/** + * Structure for low level HGCM host callback from + * the guest. No deep copy. */ +typedef struct VBOXGUESTCTRLHOSTCALLBACK +{ + /** Number of HGCM parameters. */ + uint32_t mParms; + /** Actual HGCM parameters. */ + PVBOXHGCMSVCPARM mpaParms; +} VBOXGUESTCTRLHOSTCALLBACK, *PVBOXGUESTCTRLHOSTCALLBACK; + +/** @name Host message destination flags. + * + * This is ORed into the context ID parameter Main after extending it to 64-bit. + * + * @internal Host internal. + * @{ */ +#define VBOX_GUESTCTRL_DST_ROOT_SVC RT_BIT_64(63) +#define VBOX_GUESTCTRL_DST_SESSION RT_BIT_64(62) +#define VBOX_GUESTCTRL_DST_BOTH ( VBOX_GUESTCTRL_DST_ROOT_SVC | VBOX_GUESTCTRL_DST_SESSION ) +/** @} */ + + +/** + * The service messages which are callable by host. + */ +enum eHostMsg +{ + /** + * The host asks the client to cancel all pending waits and exit. + */ + HOST_MSG_CANCEL_PENDING_WAITS = 0, + /** + * The host wants to create a guest session. + */ + HOST_MSG_SESSION_CREATE = 20, + /** + * The host wants to close a guest session. + */ + HOST_MSG_SESSION_CLOSE = 21, + /** + * The host wants to execute something in the guest. This can be a command + * line or starting a program. + */ + HOST_MSG_EXEC_CMD = 100, + /** + * Sends input data for stdin to a running process executed by HOST_EXEC_CMD. + */ + HOST_MSG_EXEC_SET_INPUT = 101, + /** + * Gets the current status of a running process, e.g. + * new data on stdout/stderr, process terminated etc. + */ + HOST_MSG_EXEC_GET_OUTPUT = 102, + /** + * Terminates a running guest process. + */ + HOST_MSG_EXEC_TERMINATE = 110, + /** + * Waits for a certain event to happen. This can be an input, output + * or status event. + */ + HOST_MSG_EXEC_WAIT_FOR = 120, + /** + * Opens a guest file. + */ + HOST_MSG_FILE_OPEN = 240, + /** + * Closes a guest file. + */ + HOST_MSG_FILE_CLOSE, + /** + * Reads from an opened guest file. + */ + HOST_MSG_FILE_READ = 250, + /** + * Reads from an opened guest file at a specified offset. + */ + HOST_MSG_FILE_READ_AT, + /** + * Write to an opened guest file. + */ + HOST_MSG_FILE_WRITE = 260, + /** + * Write to an opened guest file at a specified offset. + */ + HOST_MSG_FILE_WRITE_AT, + /** + * Changes the read & write position of an opened guest file. + */ + HOST_MSG_FILE_SEEK = 270, + /** + * Gets the current file position of an opened guest file. + */ + HOST_MSG_FILE_TELL, + /** + * Changes the file size. + */ + HOST_MSG_FILE_SET_SIZE, + /** + * Removes a directory on the guest. + */ + HOST_MSG_DIR_REMOVE = 320, + /** + * Renames a path on the guest. + */ + HOST_MSG_PATH_RENAME = 330, + /** + * Retrieves the user's documents directory. + */ + HOST_MSG_PATH_USER_DOCUMENTS, + /** + * Retrieves the user's home directory. + */ + HOST_MSG_PATH_USER_HOME, + /** + * Issues a shutdown / reboot of the guest OS. + */ + HOST_MSG_SHUTDOWN, + + /** Blow the type up to 32-bits. */ + HOST_MSG_32BIT_HACK = 0x7fffffff +}; + + +/** + * Translates a guest control host message enum to a string. + * + * @returns Enum string name. + * @param enmMsg The message to translate. + */ +DECLINLINE(const char *) GstCtrlHostMsgtoStr(enum eHostMsg enmMsg) +{ + switch (enmMsg) + { + RT_CASE_RET_STR(HOST_MSG_CANCEL_PENDING_WAITS); + RT_CASE_RET_STR(HOST_MSG_SESSION_CREATE); + RT_CASE_RET_STR(HOST_MSG_SESSION_CLOSE); + RT_CASE_RET_STR(HOST_MSG_EXEC_CMD); + RT_CASE_RET_STR(HOST_MSG_EXEC_SET_INPUT); + RT_CASE_RET_STR(HOST_MSG_EXEC_GET_OUTPUT); + RT_CASE_RET_STR(HOST_MSG_EXEC_TERMINATE); + RT_CASE_RET_STR(HOST_MSG_EXEC_WAIT_FOR); + RT_CASE_RET_STR(HOST_MSG_FILE_OPEN); + RT_CASE_RET_STR(HOST_MSG_FILE_CLOSE); + RT_CASE_RET_STR(HOST_MSG_FILE_READ); + RT_CASE_RET_STR(HOST_MSG_FILE_READ_AT); + RT_CASE_RET_STR(HOST_MSG_FILE_WRITE); + RT_CASE_RET_STR(HOST_MSG_FILE_WRITE_AT); + RT_CASE_RET_STR(HOST_MSG_FILE_SEEK); + RT_CASE_RET_STR(HOST_MSG_FILE_TELL); + RT_CASE_RET_STR(HOST_MSG_FILE_SET_SIZE); + RT_CASE_RET_STR(HOST_MSG_DIR_REMOVE); + RT_CASE_RET_STR(HOST_MSG_PATH_RENAME); + RT_CASE_RET_STR(HOST_MSG_PATH_USER_DOCUMENTS); + RT_CASE_RET_STR(HOST_MSG_PATH_USER_HOME); + RT_CASE_RET_STR(HOST_MSG_SHUTDOWN); + RT_CASE_RET_STR(HOST_MSG_32BIT_HACK); + } + return "Unknown"; +} + + +/** + * The service messages which are callable by the guest. + * + * @note The message numbers cannot be changed. Please use the first non-zero + * number that's not in use when adding new messages. + * + * @note Remember to update service.cpp when adding new messages for Main, + * as it validates all incoming messages before passing them on. + */ +enum eGuestMsg +{ + /** Guest waits for a new message the host wants to process on the guest side. + * This is a blocking call and can be deferred. + * + * @note This message is rather odd. The above description isn't really + * correct. Yes, it (1) waits for a new message and will return the + * mesage number and parameter count when one is available. However, it + * is also (2) used to retrieve the message parameters. For some weird + * reasons it was decided that it should always return VERR_TOO_MUCH_DATA + * when used in the first capacity. + * + * @note Has a problem if the guest kernel module cancels the HGCM call, as the + * guest cannot resume waiting till the host issues a message for it and + * the cancelled call returns. The new message may potentially end up in + * /dev/null depending and hang the message conversation between the guest + * and the host (SIGCHLD). + * + * @deprecated Replaced by GUEST_MSG_PEEK_WAIT, GUEST_MSG_GET and + * GUEST_MSG_CANCEL. + */ + GUEST_MSG_WAIT = 1, + /** Cancels pending calls for this client session. + * + * This should be used if a GUEST_MSG_PEEK_WAIT or GUEST_MSG_WAIT call gets + * interrupted on the client end, so as to prevent being rebuffed with + * VERR_RESOURCE_BUSY when restarting the call. + * + * @retval VINF_SUCCESS if cancelled any calls. + * @retval VWRN_NOT_FOUND if no callers. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @since 6.0 + */ + GUEST_MSG_CANCEL = 2, + /** Guest disconnected (terminated normally or due to a crash HGCM + * detected when calling service::clientDisconnect(). + * + * @note This is a host side notification message that has no business in this + * enum. The guest cannot use this message number, host will reject it. + */ + GUEST_MSG_DISCONNECTED = 3, + /** Sets a message filter to only get messages which have a certain + * context ID scheme (that is, a specific session, object etc). + * Since VBox 4.3+. + * @deprecated Replaced by GUEST_SESSION_ACCEPT. + */ + GUEST_MSG_FILTER_SET = 4, + /** Unsets (and resets) a previously set message filter. + * @retval VERR_NOT_IMPLEMENTED since 6.0. + * @deprecated Never needed or used, + */ + GUEST_MSG_FILTER_UNSET = 5, + /** Peeks at the next message, returning immediately. + * + * Returns two 32-bit parameters, first is the message ID and the second the + * parameter count. May optionally return additional 32-bit parameters with the + * sizes of respective message parameters. To distinguish buffer sizes from + * integer parameters, the latter gets their sizes inverted (uint32_t is ~4U, + * uint64_t is ~8U). + * + * Does also support the VM restore checking as in GUEST_MSG_PEEK_WAIT (64-bit + * param \# 0), see documentation there. + * + * @retval VINF_SUCCESS if a message was pending and is being returned. + * @retval VERR_TRY_AGAIN if no message pending. + * @retval VERR_VM_RESTORED if first parameter is a non-zero 64-bit value that + * does not match VbglR3GetSessionId() any more. The new value is + * returned. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.0 + */ + GUEST_MSG_PEEK_NOWAIT = 6, + /** Peeks at the next message, waiting for one to arrive. + * + * Returns two 32-bit parameters, first is the message ID and the second the + * parameter count. May optionally return additional 32-bit parameters with the + * sizes of respective message parameters. To distinguish buffer sizes from + * integer parameters, the latter gets their sizes inverted (uint32_t is ~4U, + * uint64_t is ~8U). + * + * To facilitate VM restore checking, the first parameter can be a 64-bit + * integer holding the VbglR3GetSessionId() value the guest knowns. The + * function will then check this before going to sleep and return + * VERR_VM_RESTORED if it doesn't match, same thing happens when the VM is + * restored. + * + * @retval VINF_SUCCESS if info about an pending message is being returned. + * @retval VINF_TRY_AGAIN and message set to HOST_CANCEL_PENDING_WAITS if + * cancelled by GUEST_MSG_CANCEL. + * @retval VERR_RESOURCE_BUSY if another thread already made a waiting call. + * @retval VERR_VM_RESTORED if first parameter is a non-zero 64-bit value that + * does not match VbglR3GetSessionId() any more. The new value is + * returned. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @note This replaces GUEST_MSG_WAIT. + * @since 6.0 + */ + GUEST_MSG_PEEK_WAIT = 7, + /** Gets the next message, returning immediately. + * + * All parameters are specific to the message being retrieved, however if the + * first one is an integer value it shall be an input parameter holding the + * ID of the message being retrieved. While it would be nice to add a separate + * parameter for this purpose, this is difficult without breaking GUEST_MSG_WAIT + * compatibility. + * + * @retval VINF_SUCCESS if message retrieved and removed from the pending queue. + * @retval VERR_TRY_AGAIN if no message pending. + * @retval VERR_MISMATCH if the incoming message ID does not match the pending. + * @retval VERR_BUFFER_OVERFLOW if a parmeter buffer is too small. The buffer + * size was updated to reflect the required size. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @note This replaces GUEST_MSG_WAIT. + * @since 6.0 + */ + GUEST_MSG_GET = 8, + /** Skip message. + * + * This skips the current message, replying to the main backend as best it can. + * Takes between zero and two parameters. The first parameter is the 32-bit + * VBox status code to pass onto Main when skipping the message, defaults to + * VERR_NOT_SUPPORTED. The second parameter is the 32-bit message ID of the + * message to skip, by default whatever is first in the queue is removed. This + * is also the case if UINT32_MAX is specified. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_FOUND if no message pending. + * @retval VERR_MISMATCH if the specified message ID didn't match. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @since 6.0 + */ + GUEST_MSG_SKIP = 9, + /** + * Skips the current assigned message returned by GUEST_MSG_WAIT. + * Needed for telling the host service to not keep stale + * host messages in the queue. + * @deprecated Replaced by GUEST_MSG_SKIP. + */ + GUEST_MSG_SKIP_OLD = 10, + /** General reply to a host message. + * Only contains basic data along with a simple payload. + * @todo proper docs. + */ + GUEST_MSG_REPLY = 11, + /** General message for updating a pending progress for a long task. + * @todo proper docs. + */ + GUEST_MSG_PROGRESS_UPDATE = 12, + /** Sets the caller as the master. + * + * Called by the root VBoxService to explicitly tell the host that's the master + * service. Required to use main VBoxGuest device node. No parameters. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_ACCESS_DENIED if not using main VBoxGuest device not + * @retval VERR_RESOURCE_BUSY if there is already a master. + * @retval VERR_VERSION_MISMATCH if VBoxGuest didn't supply requestor info. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @since 6.0 + */ + GUEST_MSG_MAKE_ME_MASTER = 13, + /** Prepares the starting of a session. + * + * VBoxService makes this call before spawning a session process (must be + * master). The first parameter is the session ID and the second is a one time + * key for identifying the right session process. First parameter is a 32-bit + * session ID with a value between 1 and 0xfff0. The second parameter is a byte + * buffer containing a key that GUEST_SESSION_ACCEPT checks against, minimum + * length is 64 bytes, maximum 16384 bytes. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_OUT_OF_RESOURCES if too many pending sessions hanging around. + * @retval VERR_OUT_OF_RANGE if the session ID outside the allowed range. + * @retval VERR_BUFFER_OVERFLOW if key too large. + * @retval VERR_BUFFER_UNDERFLOW if key too small. + * @retval VERR_ACCESS_DENIED if not master or in legacy mode. + * @retval VERR_DUPLICATE if the session ID has been prepared already. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.0 + */ + GUEST_MSG_SESSION_PREPARE = 14, + /** Cancels a prepared session. + * + * VBoxService makes this call to clean up after spawning a session process + * failed. One parameter, 32-bit session ID. If UINT32_MAX is passed, all + * prepared sessions are cancelled. + * + * @retval VINF_SUCCESS on success. + * @retval VWRN_NOT_FOUND if no session with the specified ID. + * @retval VERR_ACCESS_DENIED if not master or in legacy mode. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.0 + */ + GUEST_MSG_SESSION_CANCEL_PREPARED = 15, + /** Accepts a prepared session. + * + * The session processes makes this call to accept a prepared session. The + * session ID is then uniquely associated with the HGCM client ID of the caller. + * The parameters must be identical to the matching GUEST_SESSION_PREPARE call. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_NOT_FOUND if the specified session ID wasn't found. + * @retval VERR_OUT_OF_RANGE if the session ID outside the allowed range. + * @retval VERR_BUFFER_OVERFLOW if key too large. + * @retval VERR_BUFFER_UNDERFLOW if key too small. + * @retval VERR_ACCESS_DENIED if we're in legacy mode or is master. + * @retval VERR_RESOURCE_BUSY if the client is already associated with a session. + * @retval VERR_MISMATCH if the key didn't match. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.0 + */ + GUEST_MSG_SESSION_ACCEPT = 16, + /** + * Guest reports back a guest session status. + * @todo proper docs. + */ + GUEST_MSG_SESSION_NOTIFY = 20, + /** + * Guest wants to close a specific guest session. + * @todo proper docs. + */ + GUEST_MSG_SESSION_CLOSE = 21, + + /** Report guest side feature flags and retrieve the host ones. + * + * VBoxService makes this call right after becoming master to indicate to the + * host what features it support in addition. In return the host will return + * features the host supports. Two 64-bit parameters are passed in from the + * guest with the guest features (VBOX_GUESTCTRL_GF_XXX), the host replies by + * replacing the parameter values with the host ones (VBOX_GUESTCTRL_HF_XXX). + * + * @retval VINF_SUCCESS on success. + * @retval VERR_ACCESS_DENIED it not master. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.0.10, 5.2.32 + */ + GUEST_MSG_REPORT_FEATURES, + /** Query the host ones feature masks. + * + * This is for the session sub-process so that it can get hold of the features + * from the host. Again, it is prudent to set the 127 bit and observe it being + * cleared on success, as older hosts might return success without doing + * anything. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.0.10, 5.2.32 + */ + GUEST_MSG_QUERY_FEATURES, + + /** + * Guests sends output from an executed process. + * @todo proper docs. + */ + GUEST_MSG_EXEC_OUTPUT = 100, + /** + * Guest sends a status update of an executed process to the host. + * @todo proper docs. + */ + GUEST_MSG_EXEC_STATUS = 101, + /** + * Guests sends an input status notification to the host. + * @todo proper docs. + */ + GUEST_MSG_EXEC_INPUT_STATUS = 102, + /** + * Guest notifies the host about some I/O event. This can be + * a stdout, stderr or a stdin event. The actual event only tells + * how many data is available / can be sent without actually + * transmitting the data. + * @todo proper docs. + */ + GUEST_MSG_EXEC_IO_NOTIFY = 210, + /** + * Guest notifies the host about some directory event. + * @todo proper docs. + */ + GUEST_MSG_DIR_NOTIFY = 230, + /** + * Guest notifies the host about some file event. + * @todo proper docs. + */ + GUEST_MSG_FILE_NOTIFY = 240 +}; + +/** + * Translates a guest control guest message enum to a string. + * + * @returns Enum string name. + * @param enmMsg The message to translate. + */ +DECLINLINE(const char *) GstCtrlGuestMsgToStr(enum eGuestMsg enmMsg) +{ + switch (enmMsg) + { + RT_CASE_RET_STR(GUEST_MSG_WAIT); + RT_CASE_RET_STR(GUEST_MSG_CANCEL); + RT_CASE_RET_STR(GUEST_MSG_DISCONNECTED); + RT_CASE_RET_STR(GUEST_MSG_FILTER_SET); + RT_CASE_RET_STR(GUEST_MSG_FILTER_UNSET); + RT_CASE_RET_STR(GUEST_MSG_PEEK_NOWAIT); + RT_CASE_RET_STR(GUEST_MSG_PEEK_WAIT); + RT_CASE_RET_STR(GUEST_MSG_GET); + RT_CASE_RET_STR(GUEST_MSG_SKIP_OLD); + RT_CASE_RET_STR(GUEST_MSG_REPLY); + RT_CASE_RET_STR(GUEST_MSG_PROGRESS_UPDATE); + RT_CASE_RET_STR(GUEST_MSG_SKIP); + RT_CASE_RET_STR(GUEST_MSG_MAKE_ME_MASTER); + RT_CASE_RET_STR(GUEST_MSG_SESSION_PREPARE); + RT_CASE_RET_STR(GUEST_MSG_SESSION_CANCEL_PREPARED); + RT_CASE_RET_STR(GUEST_MSG_SESSION_ACCEPT); + RT_CASE_RET_STR(GUEST_MSG_SESSION_NOTIFY); + RT_CASE_RET_STR(GUEST_MSG_SESSION_CLOSE); + RT_CASE_RET_STR(GUEST_MSG_REPORT_FEATURES); + RT_CASE_RET_STR(GUEST_MSG_QUERY_FEATURES); + RT_CASE_RET_STR(GUEST_MSG_EXEC_OUTPUT); + RT_CASE_RET_STR(GUEST_MSG_EXEC_STATUS); + RT_CASE_RET_STR(GUEST_MSG_EXEC_INPUT_STATUS); + RT_CASE_RET_STR(GUEST_MSG_EXEC_IO_NOTIFY); + RT_CASE_RET_STR(GUEST_MSG_DIR_NOTIFY); + RT_CASE_RET_STR(GUEST_MSG_FILE_NOTIFY); + } + return "Unknown"; +} + + +/** + * Guest session notification types. + * @sa HGCMMsgSessionNotify. + */ +enum GUEST_SESSION_NOTIFYTYPE +{ + GUEST_SESSION_NOTIFYTYPE_UNDEFINED = 0, + /** Something went wrong (see rc). */ + GUEST_SESSION_NOTIFYTYPE_ERROR = 1, + /** Guest session has been started. */ + GUEST_SESSION_NOTIFYTYPE_STARTED = 11, + /** Guest session terminated normally. */ + GUEST_SESSION_NOTIFYTYPE_TEN = 20, + /** Guest session terminated via signal. */ + GUEST_SESSION_NOTIFYTYPE_TES = 30, + /** Guest session terminated abnormally. */ + GUEST_SESSION_NOTIFYTYPE_TEA = 40, + /** Guest session timed out and was killed. */ + GUEST_SESSION_NOTIFYTYPE_TOK = 50, + /** Guest session timed out and was not killed successfully. */ + GUEST_SESSION_NOTIFYTYPE_TOA = 60, + /** Service/OS is stopping, process was killed. */ + GUEST_SESSION_NOTIFYTYPE_DWN = 150 +}; + +/** + * Guest directory notification types. + * @sa HGCMMsgDirNotify. + */ +enum GUEST_DIR_NOTIFYTYPE +{ + GUEST_DIR_NOTIFYTYPE_UNKNOWN = 0, + /** Something went wrong (see rc). */ + GUEST_DIR_NOTIFYTYPE_ERROR = 1, + /** Guest directory opened. */ + GUEST_DIR_NOTIFYTYPE_OPEN = 10, + /** Guest directory closed. */ + GUEST_DIR_NOTIFYTYPE_CLOSE = 20, + /** Information about an open guest directory. */ + GUEST_DIR_NOTIFYTYPE_INFO = 40, + /** Guest directory created. */ + GUEST_DIR_NOTIFYTYPE_CREATE = 70, + /** Guest directory deleted. */ + GUEST_DIR_NOTIFYTYPE_REMOVE = 80 +}; + +/** + * Guest file notification types. + * @sa HGCMMsgFileNotify. + */ +enum GUEST_FILE_NOTIFYTYPE +{ + GUEST_FILE_NOTIFYTYPE_UNKNOWN = 0, + GUEST_FILE_NOTIFYTYPE_ERROR = 1, + GUEST_FILE_NOTIFYTYPE_OPEN = 10, + GUEST_FILE_NOTIFYTYPE_CLOSE = 20, + GUEST_FILE_NOTIFYTYPE_READ = 30, + GUEST_FILE_NOTIFYTYPE_READ_OFFSET, /**< @since 6.0.10, 5.2.32 - VBOX_GUESTCTRL_HF_0_NOTIFY_RDWR_OFFSET */ + GUEST_FILE_NOTIFYTYPE_WRITE = 40, + GUEST_FILE_NOTIFYTYPE_WRITE_OFFSET, /**< @since 6.0.10, 5.2.32 - VBOX_GUESTCTRL_HF_0_NOTIFY_RDWR_OFFSET */ + GUEST_FILE_NOTIFYTYPE_SEEK = 50, + GUEST_FILE_NOTIFYTYPE_TELL = 60, + GUEST_FILE_NOTIFYTYPE_SET_SIZE +}; + +/** + * Guest file seeking types. Has to match FileSeekType in Main. + * + * @note This is not compatible with RTFileSeek, which is an unncessary pain. + */ +enum GUEST_FILE_SEEKTYPE +{ + GUEST_FILE_SEEKTYPE_BEGIN = 1, + GUEST_FILE_SEEKTYPE_CURRENT = 4, + GUEST_FILE_SEEKTYPE_END = 8 +}; + +/** @name VBOX_GUESTCTRL_GF_XXX - Guest features. + * @sa GUEST_MSG_REPORT_FEATURES + * @{ */ +/** Supports HOST_MSG_FILE_SET_SIZE. */ +#define VBOX_GUESTCTRL_GF_0_SET_SIZE RT_BIT_64(0) +/** Supports passing process arguments starting at argv[0] rather than argv[1]. + * Guest additions which doesn't support this feature will instead use the + * executable image path as argv[0]. + * @sa VBOX_GUESTCTRL_HF_0_PROCESS_ARGV0 + * @since 6.1.6 */ +#define VBOX_GUESTCTRL_GF_0_PROCESS_ARGV0 RT_BIT_64(1) +/** Supports passing cmd / arguments / environment blocks bigger than + * GUESTPROCESS_DEFAULT_CMD_LEN / GUESTPROCESS_DEFAULT_ARGS_LEN / GUESTPROCESS_DEFAULT_ENV_LEN (bytes, in total). */ +#define VBOX_GUESTCTRL_GF_0_PROCESS_DYNAMIC_SIZES RT_BIT_64(2) +/** Supports shutting down / rebooting the guest. */ +#define VBOX_GUESTCTRL_GF_0_SHUTDOWN RT_BIT_64(3) +/** Bit that must be set in the 2nd parameter, will be cleared if the host reponds + * correctly (old hosts might not). */ +#define VBOX_GUESTCTRL_GF_1_MUST_BE_ONE RT_BIT_64(63) +/** @} */ + +/** @name VBOX_GUESTCTRL_HF_XXX - Host features. + * @sa GUEST_MSG_REPORT_FEATURES + * @{ */ +/** Host supports the GUEST_FILE_NOTIFYTYPE_READ_OFFSET and + * GUEST_FILE_NOTIFYTYPE_WRITE_OFFSET notification types. */ +#define VBOX_GUESTCTRL_HF_0_NOTIFY_RDWR_OFFSET RT_BIT_64(0) +/** Host supports process passing arguments starting at argv[0] rather than + * argv[1], when the guest additions reports VBOX_GUESTCTRL_GF_0_PROCESS_ARGV0. + * @since 6.1.6 */ +#define VBOX_GUESTCTRL_HF_0_PROCESS_ARGV0 RT_BIT_64(1) +/** @} */ + + +/* + * HGCM parameter structures. + */ +#pragma pack (1) + +/** + * Waits for a host message to arrive. The structure then contains the + * actual message type + required number of parameters needed to successfully + * retrieve that host message (in a next round). + */ +typedef struct HGCMMsgWaitFor +{ + VBGLIOCHGCMCALL hdr; + /** The returned message the host wants to run on the guest. */ + HGCMFunctionParameter msg; /* OUT uint32_t */ + /** Number of parameters the message needs. */ + HGCMFunctionParameter num_parms; /* OUT uint32_t */ +} HGCMMsgWaitFor; + +/** + * Asks the guest control host service to set a message + * filter for this client. This filter will then only + * deliver messages to the client which match the + * wanted context ID (ranges). + */ +typedef struct HGCMMsgFilterSet +{ + VBGLIOCHGCMCALL hdr; + /** Value to filter for after filter mask was applied. */ + HGCMFunctionParameter value; /* IN uint32_t */ + /** Mask to add to the current set filter. */ + HGCMFunctionParameter mask_add; /* IN uint32_t */ + /** Mask to remove from the current set filter. */ + HGCMFunctionParameter mask_remove; /* IN uint32_t */ + /** Filter flags; currently unused. */ + HGCMFunctionParameter flags; /* IN uint32_t */ +} HGCMMsgFilterSet; + +/** + * Asks the guest control host service to disable + * a previously set message filter again. + */ +typedef struct HGCMMsgFilterUnset +{ + VBGLIOCHGCMCALL hdr; + /** Unset flags; currently unused. */ + HGCMFunctionParameter flags; /* IN uint32_t */ +} HGCMMsgFilterUnset; + +/** + * Asks the guest control host service to skip the + * currently assigned host message returned by + * VbglR3GuestCtrlMsgWaitFor(). + */ +typedef struct HGCMMsgSkip +{ + VBGLIOCHGCMCALL hdr; + /** Skip flags; currently unused. */ + HGCMFunctionParameter flags; /* IN uint32_t */ +} HGCMMsgSkip; + +/** + * Asks the guest control host service to cancel all pending (outstanding) + * waits which were not processed yet. This is handy for a graceful shutdown. + */ +typedef struct HGCMMsgCancelPendingWaits +{ + VBGLIOCHGCMCALL hdr; +} HGCMMsgCancelPendingWaits; + +typedef struct HGCMMsgReply +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** Message type. */ + HGCMFunctionParameter type; + /** IPRT result of overall operation. */ + HGCMFunctionParameter rc; + /** Optional payload to this reply. */ + HGCMFunctionParameter payload; +} HGCMMsgReply; + +/** + * Creates a guest session. + */ +typedef struct HGCMMsgSessionOpen +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The guest control protocol version this + * session is about to use. */ + HGCMFunctionParameter protocol; + /** The user name to run the guest session under. */ + HGCMFunctionParameter username; + /** The user's password. */ + HGCMFunctionParameter password; + /** The domain to run the guest session under. */ + HGCMFunctionParameter domain; + /** Session creation flags. */ + HGCMFunctionParameter flags; +} HGCMMsgSessionOpen; + +/** + * Terminates (closes) a guest session. + */ +typedef struct HGCMMsgSessionClose +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** Session termination flags. */ + HGCMFunctionParameter flags; +} HGCMMsgSessionClose; + +/** + * Reports back a guest session's status. + */ +typedef struct HGCMMsgSessionNotify +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** Notification type. */ + HGCMFunctionParameter type; + /** Notification result. */ + HGCMFunctionParameter result; +} HGCMMsgSessionNotify; + +typedef struct HGCMMsgPathRename +{ + VBGLIOCHGCMCALL hdr; + /** UInt32: Context ID. */ + HGCMFunctionParameter context; + /** Source to rename. */ + HGCMFunctionParameter source; + /** Destination to rename source to. */ + HGCMFunctionParameter dest; + /** UInt32: Rename flags. */ + HGCMFunctionParameter flags; +} HGCMMsgPathRename; + +typedef struct HGCMMsgPathUserDocuments +{ + VBGLIOCHGCMCALL hdr; + /** UInt32: Context ID. */ + HGCMFunctionParameter context; +} HGCMMsgPathUserDocuments; + +typedef struct HGCMMsgPathUserHome +{ + VBGLIOCHGCMCALL hdr; + /** UInt32: Context ID. */ + HGCMFunctionParameter context; +} HGCMMsgPathUserHome; + +/** + * Shuts down / reboots the guest. + */ +typedef struct HGCMMsgShutdown +{ + VBGLIOCHGCMCALL hdr; + /** UInt32: Context ID. */ + HGCMFunctionParameter context; + /** UInt32: Action flags. */ + HGCMFunctionParameter action; +} HGCMMsgShutdown; + +/** + * Executes a command inside the guest. + */ +typedef struct HGCMMsgProcExec +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The command to execute on the guest. */ + HGCMFunctionParameter cmd; + /** Execution flags (see IGuest::ProcessCreateFlag_*). */ + HGCMFunctionParameter flags; + /** Number of arguments. */ + HGCMFunctionParameter num_args; + /** The actual arguments. */ + HGCMFunctionParameter args; + /** Number of environment value pairs. */ + HGCMFunctionParameter num_env; + /** Size (in bytes) of environment block, including terminating zeros. */ + HGCMFunctionParameter cb_env; + /** The actual environment block. */ + HGCMFunctionParameter env; + union + { + struct + { + /** The user name to run the executed command under. + * Only for VBox < 4.3 hosts. */ + HGCMFunctionParameter username; + /** The user's password. + * Only for VBox < 4.3 hosts. */ + HGCMFunctionParameter password; + /** Timeout (in msec) which either specifies the + * overall lifetime of the process or how long it + * can take to bring the process up and running - + * (depends on the IGuest::ProcessCreateFlag_*). */ + HGCMFunctionParameter timeout; + } v1; + struct + { + /** Timeout (in ms) which either specifies the + * overall lifetime of the process or how long it + * can take to bring the process up and running - + * (depends on the IGuest::ProcessCreateFlag_*). */ + HGCMFunctionParameter timeout; + /** Process priority. */ + HGCMFunctionParameter priority; + /** Number of process affinity blocks. */ + HGCMFunctionParameter num_affinity; + /** Pointer to process affinity blocks (uint64_t). */ + HGCMFunctionParameter affinity; + } v2; + } u; +} HGCMMsgProcExec; + +/** + * Sends input to a guest process via stdin. + */ +typedef struct HGCMMsgProcInput +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The process ID (PID) to send the input to. */ + HGCMFunctionParameter pid; + /** Input flags (see IGuest::ProcessInputFlag_*). */ + HGCMFunctionParameter flags; + /** Data buffer. */ + HGCMFunctionParameter data; + /** Actual size of data (in bytes). */ + HGCMFunctionParameter size; +} HGCMMsgProcInput; + +/** + * Retrieves ouptut from a previously executed process + * from stdout/stderr. + */ +typedef struct HGCMMsgProcOutput +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The process ID (PID). */ + HGCMFunctionParameter pid; + /** The pipe handle ID (stdout/stderr). */ + HGCMFunctionParameter handle; + /** Optional flags. */ + HGCMFunctionParameter flags; + /** Data buffer. */ + HGCMFunctionParameter data; +} HGCMMsgProcOutput; + +/** + * Reports the current status of a guest process. + */ +typedef struct HGCMMsgProcStatus +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The process ID (PID). */ + HGCMFunctionParameter pid; + /** The process status. */ + HGCMFunctionParameter status; + /** Optional flags (based on status). */ + HGCMFunctionParameter flags; + /** Optional data buffer (not used atm). */ + HGCMFunctionParameter data; +} HGCMMsgProcStatus; + +/** + * Reports back the status of data written to a process. + */ +typedef struct HGCMMsgProcStatusInput +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The process ID (PID). */ + HGCMFunctionParameter pid; + /** Status of the operation. */ + HGCMFunctionParameter status; + /** Optional flags. */ + HGCMFunctionParameter flags; + /** Data written. */ + HGCMFunctionParameter written; +} HGCMMsgProcStatusInput; + +/* + * Guest control 2.0 messages. + */ + +/** + * Terminates a guest process. + */ +typedef struct HGCMMsgProcTerminate +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The process ID (PID). */ + HGCMFunctionParameter pid; +} HGCMMsgProcTerminate; + +/** + * Waits for certain events to happen. + */ +typedef struct HGCMMsgProcWaitFor +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** The process ID (PID). */ + HGCMFunctionParameter pid; + /** Wait (event) flags. */ + HGCMFunctionParameter flags; + /** Timeout (in ms). */ + HGCMFunctionParameter timeout; +} HGCMMsgProcWaitFor; + +typedef struct HGCMMsgDirRemove +{ + VBGLIOCHGCMCALL hdr; + /** UInt32: Context ID. */ + HGCMFunctionParameter context; + /** Directory to remove. */ + HGCMFunctionParameter path; + /** UInt32: Removement flags. */ + HGCMFunctionParameter flags; +} HGCMMsgDirRemove; + +/** + * Opens a guest file. + */ +typedef struct HGCMMsgFileOpen +{ + VBGLIOCHGCMCALL hdr; + /** UInt32: Context ID. */ + HGCMFunctionParameter context; + /** File to open. */ + HGCMFunctionParameter filename; + /** Open mode. */ + HGCMFunctionParameter openmode; + /** Disposition mode. */ + HGCMFunctionParameter disposition; + /** Sharing mode. */ + HGCMFunctionParameter sharing; + /** UInt32: Creation mode. */ + HGCMFunctionParameter creationmode; + /** UInt64: Initial offset. */ + HGCMFunctionParameter offset; +} HGCMMsgFileOpen; + +/** + * Closes a guest file. + */ +typedef struct HGCMMsgFileClose +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to close. */ + HGCMFunctionParameter handle; +} HGCMMsgFileClose; + +/** + * Reads from a guest file. + */ +typedef struct HGCMMsgFileRead +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to read from. */ + HGCMFunctionParameter handle; + /** Size (in bytes) to read. */ + HGCMFunctionParameter size; +} HGCMMsgFileRead; + +/** + * Reads at a specified offset from a guest file. + */ +typedef struct HGCMMsgFileReadAt +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to read from. */ + HGCMFunctionParameter handle; + /** Offset where to start reading from. */ + HGCMFunctionParameter offset; + /** Actual size of data (in bytes). */ + HGCMFunctionParameter size; +} HGCMMsgFileReadAt; + +/** + * Writes to a guest file. + */ +typedef struct HGCMMsgFileWrite +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to write to. */ + HGCMFunctionParameter handle; + /** Actual size of data (in bytes). */ + HGCMFunctionParameter size; + /** Data buffer to write to the file. */ + HGCMFunctionParameter data; +} HGCMMsgFileWrite; + +/** + * Writes at a specified offset to a guest file. + */ +typedef struct HGCMMsgFileWriteAt +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to write to. */ + HGCMFunctionParameter handle; + /** Offset where to start reading from. */ + HGCMFunctionParameter offset; + /** Actual size of data (in bytes). */ + HGCMFunctionParameter size; + /** Data buffer to write to the file. */ + HGCMFunctionParameter data; +} HGCMMsgFileWriteAt; + +/** + * Seeks the read/write position of a guest file. + */ +typedef struct HGCMMsgFileSeek +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to seek. */ + HGCMFunctionParameter handle; + /** The seeking method. */ + HGCMFunctionParameter method; + /** The seeking offset. */ + HGCMFunctionParameter offset; +} HGCMMsgFileSeek; + +/** + * Tells the current read/write position of a guest file. + */ +typedef struct HGCMMsgFileTell +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** File handle to get the current position for. */ + HGCMFunctionParameter handle; +} HGCMMsgFileTell; + +/** + * Changes the file size. + */ +typedef struct HGCMMsgFileSetSize +{ + VBGLIOCHGCMCALL Hdr; + /** Context ID. */ + HGCMFunctionParameter id32Context; + /** File handle to seek. */ + HGCMFunctionParameter id32Handle; + /** The new file size. */ + HGCMFunctionParameter cb64NewSize; +} HGCMMsgFileSetSize; + + +/****************************************************************************** +* HGCM replies from the guest. These are handled in Main's low-level HGCM * +* callbacks and dispatched to the appropriate guest object. * +******************************************************************************/ + +typedef struct HGCMReplyFileNotify +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** Notification type. */ + HGCMFunctionParameter type; + /** IPRT result of overall operation. */ + HGCMFunctionParameter rc; + union + { + struct + { + /** Guest file handle. */ + HGCMFunctionParameter handle; + } open; + /** Note: Close does not have any additional data (yet). */ + struct + { + /** Actual data read (if any). */ + HGCMFunctionParameter data; + } read; + struct + { + /** Actual data read (if any). */ + HGCMFunctionParameter pvData; + /** The new file offset (signed). Negative value if non-seekable files. */ + HGCMFunctionParameter off64New; + } ReadOffset; + struct + { + /** How much data (in bytes) have been successfully written. */ + HGCMFunctionParameter written; + } write; + struct + { + /** Number of bytes that was successfully written. */ + HGCMFunctionParameter cb32Written; + /** The new file offset (signed). Negative value if non-seekable files. */ + HGCMFunctionParameter off64New; + } WriteOffset; + struct + { + HGCMFunctionParameter offset; + } seek; + struct + { + HGCMFunctionParameter offset; + } tell; + struct + { + HGCMFunctionParameter cb64Size; + } SetSize; + } u; +} HGCMReplyFileNotify; + +typedef struct HGCMReplyDirNotify +{ + VBGLIOCHGCMCALL hdr; + /** Context ID. */ + HGCMFunctionParameter context; + /** Notification type. */ + HGCMFunctionParameter type; + /** IPRT result of overall operation. */ + HGCMFunctionParameter rc; + union + { + struct + { + /** Directory information. */ + HGCMFunctionParameter objInfo; + } info; + struct + { + /** Guest directory handle. */ + HGCMFunctionParameter handle; + } open; + struct + { + /** Current read directory entry. */ + HGCMFunctionParameter entry; + /** Extended entry object information. Optional. */ + HGCMFunctionParameter objInfo; + } read; + } u; +} HGCMReplyDirNotify; + +#pragma pack () + +/****************************************************************************** +* Callback data structures. * +******************************************************************************/ + +/** + * The guest control callback data header. Must come first + * on each callback structure defined below this struct. + */ +typedef struct CALLBACKDATA_HEADER +{ + /** Context ID to identify callback data. This is + * and *must* be the very first parameter in this + * structure to still be backwards compatible. */ + uint32_t uContextID; +} CALLBACKDATA_HEADER, *PCALLBACKDATA_HEADER; + +/* + * These structures make up the actual low level HGCM callback data sent from + * the guest back to the host. + */ + +typedef struct CALLBACKDATA_CLIENT_DISCONNECTED +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; +} CALLBACKDATA_CLIENT_DISCONNECTED, *PCALLBACKDATA_CLIENT_DISCONNECTED; + +typedef struct CALLBACKDATA_MSG_REPLY +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** Notification type. */ + uint32_t uType; + /** Notification result. Note: int vs. uint32! */ + uint32_t rc; + /** Pointer to optional payload. */ + void *pvPayload; + /** Payload size (in bytes). */ + uint32_t cbPayload; +} CALLBACKDATA_MSG_REPLY, *PCALLBACKDATA_MSG_REPLY; + +typedef struct CALLBACKDATA_SESSION_NOTIFY +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** Notification type. */ + uint32_t uType; + /** Notification result. Note: int vs. uint32! */ + uint32_t uResult; +} CALLBACKDATA_SESSION_NOTIFY, *PCALLBACKDATA_SESSION_NOTIFY; + +typedef struct CALLBACKDATA_PROC_STATUS +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** The process ID (PID). */ + uint32_t uPID; + /** The process status. */ + uint32_t uStatus; + /** Optional flags, varies, based on u32Status. */ + uint32_t uFlags; + /** Optional data buffer (not used atm). */ + void *pvData; + /** Size of optional data buffer (not used atm). */ + uint32_t cbData; +} CALLBACKDATA_PROC_STATUS, *PCALLBACKDATA_PROC_STATUS; + +typedef struct CALLBACKDATA_PROC_OUTPUT +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** The process ID (PID). */ + uint32_t uPID; + /** The handle ID (stdout/stderr). */ + uint32_t uHandle; + /** Optional flags (not used atm). */ + uint32_t uFlags; + /** Optional data buffer. */ + void *pvData; + /** Size (in bytes) of optional data buffer. */ + uint32_t cbData; +} CALLBACKDATA_PROC_OUTPUT, *PCALLBACKDATA_PROC_OUTPUT; + +typedef struct CALLBACKDATA_PROC_INPUT +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** The process ID (PID). */ + uint32_t uPID; + /** Current input status. */ + uint32_t uStatus; + /** Optional flags. */ + uint32_t uFlags; + /** Size (in bytes) of processed input data. */ + uint32_t uProcessed; +} CALLBACKDATA_PROC_INPUT, *PCALLBACKDATA_PROC_INPUT; + +/** + * General guest directory notification callback. + */ +typedef struct CALLBACKDATA_DIR_NOTIFY +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** Notification type. */ + uint32_t uType; + /** IPRT result of overall operation. */ + uint32_t rc; + union + { + struct + { + /** Size (in bytes) of directory information. */ + uint32_t cbObjInfo; + /** Pointer to directory information. */ + void *pvObjInfo; + } info; + struct + { + /** Guest directory handle. */ + uint32_t uHandle; + } open; + /** Note: Close does not have any additional data (yet). */ + struct + { + /** Size (in bytes) of directory entry information. */ + uint32_t cbEntry; + /** Pointer to directory entry information. */ + void *pvEntry; + /** Size (in bytes) of directory entry object information. */ + uint32_t cbObjInfo; + /** Pointer to directory entry object information. */ + void *pvObjInfo; + } read; + } u; +} CALLBACKDATA_DIR_NOTIFY, *PCALLBACKDATA_DIR_NOTIFY; + +/** + * General guest file notification callback. + */ +typedef struct CALLBACKDATA_FILE_NOTIFY +{ + /** Callback data header. */ + CALLBACKDATA_HEADER hdr; + /** Notification type. */ + uint32_t uType; + /** IPRT result of overall operation. */ + uint32_t rc; + union + { + struct + { + /** Guest file handle. */ + uint32_t uHandle; + } open; + /** Note: Close does not have any additional data (yet). */ + struct + { + /** How much data (in bytes) have been read. */ + uint32_t cbData; + /** Actual data read (if any). */ + void *pvData; + } read; + struct + { + /** How much data (in bytes) have been successfully written. */ + uint32_t cbWritten; + } write; + struct + { + /** New file offset after successful seek. */ + uint64_t uOffActual; + } seek; + struct + { + /** New file offset after successful tell. */ + uint64_t uOffActual; + } tell; + struct + { + /** The new file siz.e */ + uint64_t cbSize; + } SetSize; + } u; +} CALLBACKDATA_FILE_NOTIFY, *PCALLBACKDATA_FILE_NOTIFY; + +} /* namespace guestControl */ + +#endif /* !VBOX_INCLUDED_HostServices_GuestControlSvc_h */ + diff --git a/include/VBox/HostServices/GuestPropertySvc.h b/include/VBox/HostServices/GuestPropertySvc.h new file mode 100644 index 00000000..806ba306 --- /dev/null +++ b/include/VBox/HostServices/GuestPropertySvc.h @@ -0,0 +1,553 @@ +/** @file + * Guest property service - Common header for host service and guest clients. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_HostServices_GuestPropertySvc_h +#define VBOX_INCLUDED_HostServices_GuestPropertySvc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + + +/** Maximum size for property names (including the terminator). */ +#define GUEST_PROP_MAX_NAME_LEN 64 +/** Maximum size for property values (including the terminator). */ +#define GUEST_PROP_MAX_VALUE_LEN 1024 +/** Maximum number of properties per guest. */ +#define GUEST_PROP_MAX_PROPS 256 +/** Maximum size for enumeration patterns (including the terminators). */ +#define GUEST_PROP_MAX_PATTERN_LEN 1024 +/** Maximum number of changes we remember for guest notifications. */ +#define GUEST_PROP_MAX_GUEST_NOTIFICATIONS 256 +/** Maximum number of current pending waits per client. */ +#define GUEST_PROP_MAX_GUEST_CONCURRENT_WAITS 16 + + +/** @name GUEST_PROP_F_XXX - The guest property flag values which are currently accepted. + * @{ + */ +#define GUEST_PROP_F_NILFLAG UINT32_C(0) +/** Transient until VM gets shut down. */ +#define GUEST_PROP_F_TRANSIENT RT_BIT_32(1) +#define GUEST_PROP_F_RDONLYGUEST RT_BIT_32(2) +#define GUEST_PROP_F_RDONLYHOST RT_BIT_32(3) +/** Transient until VM gets a reset / restarts. + * Implies TRANSIENT. */ +#define GUEST_PROP_F_TRANSRESET RT_BIT_32(4) +#define GUEST_PROP_F_READONLY (GUEST_PROP_F_RDONLYGUEST | GUEST_PROP_F_RDONLYHOST) +#define GUEST_PROP_F_ALLFLAGS (GUEST_PROP_F_TRANSIENT | GUEST_PROP_F_READONLY | GUEST_PROP_F_TRANSRESET) +/** @} */ + +/** + * Check that a string fits our criteria for a property name. + * + * @returns IPRT status code + * @param pszName The string to check, must be valid Utf8 + * @param cbName The number of bytes @a pszName points to, including the + * terminating character. + */ +DECLINLINE(int) GuestPropValidateName(const char *pszName, size_t cbName) +{ + /* Property name is expected to be at least 1 charecter long plus terminating character. */ + AssertReturn(cbName >= 2, VERR_INVALID_PARAMETER); + AssertReturn(cbName <= GUEST_PROP_MAX_NAME_LEN, VERR_INVALID_PARAMETER); + + AssertPtrReturn(pszName, VERR_INVALID_POINTER); + + AssertReturn(memchr(pszName, '*', cbName) == NULL, VERR_INVALID_PARAMETER); + AssertReturn(memchr(pszName, '?', cbName) == NULL, VERR_INVALID_PARAMETER); + AssertReturn(memchr(pszName, '|', cbName) == NULL, VERR_INVALID_PARAMETER); + + return VINF_SUCCESS; +} + +/** + * Check a string fits our criteria for the value of a guest property. + * + * @returns IPRT status code + * @retval VINF_SUCCESS if guest property value corresponds to all criteria. + * @retval VERR_TOO_MUCH_DATA if guest property value size exceeds limits. + * @retval VERR_INVALID_PARAMETER if guest property does not correspond to all other criteria. + * @param pszValue The string to check, must be valid utf-8. + * @param cbValue The size of of @a pszValue in bytes, including the + * terminator. + * @thread HGCM + */ +DECLINLINE(int) GuestPropValidateValue(const char *pszValue, size_t cbValue) +{ + AssertPtrReturn(pszValue, VERR_INVALID_POINTER); + + /* Zero-length values are possible, however buffer should contain terminating character at least. */ + AssertReturn(cbValue > 0, VERR_INVALID_PARAMETER); + AssertReturn(cbValue <= GUEST_PROP_MAX_VALUE_LEN, VERR_TOO_MUCH_DATA); + + return VINF_SUCCESS; +} + +/** + * Get the name of a flag as a string. + * @returns the name, or NULL if fFlag is invalid. + * @param fFlag The flag, GUEST_PROP_F_XXX. + * @param pcchName Where to return the name length. + */ +DECLINLINE(const char *) GuestPropFlagNameAndLen(uint32_t fFlag, size_t *pcchName) +{ + switch (fFlag) + { + case GUEST_PROP_F_TRANSIENT: + *pcchName = sizeof("TRANSIENT") - 1; + return "TRANSIENT"; + case GUEST_PROP_F_RDONLYGUEST: + *pcchName = sizeof("RDONLYGUEST") - 1; + return "RDONLYGUEST"; + case GUEST_PROP_F_RDONLYHOST: + *pcchName = sizeof("RDONLYHOST") - 1; + return "RDONLYHOST"; + case GUEST_PROP_F_READONLY: + *pcchName = sizeof("READONLY") - 1; + return "READONLY"; + case GUEST_PROP_F_TRANSRESET: + *pcchName = sizeof("TRANSRESET") - 1; + return "TRANSRESET"; + default: + *pcchName = 0; + return NULL; + } +} + +/** + * Maximum length for the property flags field. We only ever return one of + * RDONLYGUEST, RDONLYHOST and RDONLY + */ +#define GUEST_PROP_MAX_FLAGS_LEN sizeof("TRANSIENT, RDONLYGUEST, TRANSRESET") + +/** + * Parse a guest properties flags string for flag names and make sure that + * there is no junk text in the string. + * + * @returns IPRT status code + * @retval VERR_INVALID_PARAMETER if the flag string is not valid + * @param pcszFlags the flag string to parse + * @param pfFlags where to store the parse result. May not be NULL. + * @note This function is also inline because it must be accessible from + * several modules and it does not seem reasonable to put it into + * its own library. + */ +DECLINLINE(int) GuestPropValidateFlags(const char *pcszFlags, uint32_t *pfFlags) +{ + static const uint32_t s_aFlagList[] = + { + GUEST_PROP_F_TRANSIENT, GUEST_PROP_F_READONLY, GUEST_PROP_F_RDONLYGUEST, GUEST_PROP_F_RDONLYHOST, GUEST_PROP_F_TRANSRESET + }; + const char *pcszNext = pcszFlags; + int rc = VINF_SUCCESS; + uint32_t fFlags = 0; + AssertLogRelReturn(RT_VALID_PTR(pfFlags), VERR_INVALID_POINTER); + + if (pcszFlags) + { + while (*pcszNext == ' ') + ++pcszNext; + while ((*pcszNext != '\0') && RT_SUCCESS(rc)) + { + unsigned i; + rc = VERR_PARSE_ERROR; + for (i = 0; i < RT_ELEMENTS(s_aFlagList); ++i) + { + size_t cchFlagName; + const char *pszFlagName = GuestPropFlagNameAndLen(s_aFlagList[i], &cchFlagName); + if (RTStrNICmpAscii(pcszNext, pszFlagName, cchFlagName) == 0) + { + char ch; + fFlags |= s_aFlagList[i]; + pcszNext += cchFlagName; + while ((ch = *pcszNext) == ' ') + ++pcszNext; + rc = VINF_SUCCESS; + if (ch == ',') + { + ++pcszNext; + while (*pcszNext == ' ') + ++pcszNext; + } + else if (ch != '\0') + rc = VERR_PARSE_ERROR; + break; + } + } + } + } + if (RT_SUCCESS(rc)) + *pfFlags = fFlags; + return rc; +} + + +/** + * Write out flags to a string. + * @returns IPRT status code + * @param fFlags the flags to write out + * @param pszFlags where to write the flags string. This must point to + * a buffer of size (at least) GUEST_PROP_MAX_FLAGS_LEN. + */ +DECLINLINE(int) GuestPropWriteFlags(uint32_t fFlags, char *pszFlags) +{ + /* Putting READONLY before the other RDONLY flags keeps the result short. */ + static const uint32_t s_aFlagList[] = + { + GUEST_PROP_F_TRANSIENT, GUEST_PROP_F_READONLY, GUEST_PROP_F_RDONLYGUEST, GUEST_PROP_F_RDONLYHOST, GUEST_PROP_F_TRANSRESET + }; + int rc = VINF_SUCCESS; + + AssertLogRelReturn(RT_VALID_PTR(pszFlags), VERR_INVALID_POINTER); + if ((fFlags & ~GUEST_PROP_F_ALLFLAGS) == GUEST_PROP_F_NILFLAG) + { + char *pszNext; + unsigned i; + + /* TRANSRESET implies TRANSIENT. For compatability with old clients we + always set TRANSIENT when TRANSRESET appears. */ + if (fFlags & GUEST_PROP_F_TRANSRESET) + fFlags |= GUEST_PROP_F_TRANSIENT; + + pszNext = pszFlags; + for (i = 0; i < RT_ELEMENTS(s_aFlagList); ++i) + { + if (s_aFlagList[i] == (fFlags & s_aFlagList[i])) + { + size_t cchFlagName; + const char *pszFlagName = GuestPropFlagNameAndLen(s_aFlagList[i], &cchFlagName); + memcpy(pszNext, pszFlagName, cchFlagName); + pszNext += cchFlagName; + fFlags &= ~s_aFlagList[i]; + if (fFlags != GUEST_PROP_F_NILFLAG) + { + *pszNext++ = ','; + *pszNext++ = ' '; + } + } + } + *pszNext = '\0'; + + Assert((uintptr_t)(pszNext - pszFlags) < GUEST_PROP_MAX_FLAGS_LEN); + Assert(fFlags == GUEST_PROP_F_NILFLAG); /* bad s_aFlagList */ + } + else + rc = VERR_INVALID_PARAMETER; + return rc; +} + + +/** @name The service functions which are callable by host. + * @{ + */ +/** Set properties in a block. + * The parameters are pointers to NULL-terminated arrays containing the + * parameters. These are, in order, name, value, timestamp, flags. Strings are + * stored as pointers to mutable utf8 data. All parameters must be supplied. */ +#define GUEST_PROP_FN_HOST_SET_PROPS 1 +/** Get the value attached to a guest property. + * The parameter format matches that of GET_PROP. */ +#define GUEST_PROP_FN_HOST_GET_PROP 2 +/** Set the value attached to a guest property. + * The parameter format matches that of SET_PROP. */ +#define GUEST_PROP_FN_HOST_SET_PROP 3 +/** Set the value attached to a guest property. + * The parameter format matches that of SET_PROP_VALUE. */ +#define GUEST_PROP_FN_HOST_SET_PROP_VALUE 4 +/** Remove a guest property. + * The parameter format matches that of DEL_PROP. */ +#define GUEST_PROP_FN_HOST_DEL_PROP 5 +/** Enumerate guest properties. + * The parameter format matches that of ENUM_PROPS. */ +#define GUEST_PROP_FN_HOST_ENUM_PROPS 6 +/** Set global flags for the service. + * Currently RDONLYGUEST is supported. Takes one 32-bit unsigned integer + * parameter for the flags. */ +#define GUEST_PROP_FN_HOST_SET_GLOBAL_FLAGS 7 +/** @} */ + + +/** @name The service functions which are called by guest. + * + * @note The numbers may not change! + * @{ + */ +/** Get a guest property */ +#define GUEST_PROP_FN_GET_PROP 1 +/** Set a guest property */ +#define GUEST_PROP_FN_SET_PROP 2 +/** Set just the value of a guest property */ +#define GUEST_PROP_FN_SET_PROP_VALUE 3 +/** Delete a guest property */ +#define GUEST_PROP_FN_DEL_PROP 4 +/** Enumerate guest properties */ +#define GUEST_PROP_FN_ENUM_PROPS 5 +/** Poll for guest notifications */ +#define GUEST_PROP_FN_GET_NOTIFICATION 6 +/** @} */ + + +/** + * Data structure to pass to the service extension callback. + * We use this to notify the host of changes to properties. + */ +typedef struct GUESTPROPHOSTCALLBACKDATA +{ + /** Magic number to identify the structure (GUESTPROPHOSTCALLBACKDATA_MAGIC). */ + uint32_t u32Magic; + /** The name of the property that was changed */ + const char *pcszName; + /** The new property value, or NULL if the property was deleted */ + const char *pcszValue; + /** The timestamp of the modification */ + uint64_t u64Timestamp; + /** The flags field of the modified property */ + const char *pcszFlags; +} GUESTPROPHOSTCALLBACKDATA; +/** Poitner to a data structure to pass to the service extension callback. */ +typedef GUESTPROPHOSTCALLBACKDATA *PGUESTPROPHOSTCALLBACKDATA; + +/** Magic number for sanity checking the HOSTCALLBACKDATA structure */ +#define GUESTPROPHOSTCALLBACKDATA_MAGIC UINT32_C(0x69c87a78) + +/** + * HGCM parameter structures. Packing is explicitly defined as this is a wire format. + */ +/** The guest is requesting the value of a property */ +typedef struct GuestPropMsgGetProperty +{ + VBGLIOCHGCMCALL hdr; + + /** + * The property name (IN pointer) + * This must fit to a number of criteria, namely + * - Only Utf8 strings are allowed + * - Less than or equal to MAX_NAME_LEN bytes in length + * - Zero terminated + */ + HGCMFunctionParameter name; + + /** + * The returned string data will be placed here. (OUT pointer) + * This call returns two null-terminated strings which will be placed one + * after another: value and flags. + */ + HGCMFunctionParameter buffer; + + /** + * The property timestamp. (OUT uint64_t) + */ + HGCMFunctionParameter timestamp; + + /** + * If the buffer provided was large enough this will contain the size of + * the returned data. Otherwise it will contain the size of the buffer + * needed to hold the data and VERR_BUFFER_OVERFLOW will be returned. + * (OUT uint32_t) + */ + HGCMFunctionParameter size; +} GuestPropMsgGetProperty; +AssertCompileSize(GuestPropMsgGetProperty, 40 + 4 * (ARCH_BITS == 64 ? 16 : 12)); + +/** The guest is requesting to change a property */ +typedef struct GuestPropMsgSetProperty +{ + VBGLIOCHGCMCALL hdr; + + /** + * The property name. (IN pointer) + * This must fit to a number of criteria, namely + * - Only Utf8 strings are allowed + * - Less than or equal to MAX_NAME_LEN bytes in length + * - Zero terminated + */ + HGCMFunctionParameter name; + + /** + * The value of the property (IN pointer) + * Criteria as for the name parameter, but with length less than or equal to + * MAX_VALUE_LEN. + */ + HGCMFunctionParameter value; + + /** + * The property flags (IN pointer) + * This is a comma-separated list of the format flag=value + * The length must be less than or equal to GUEST_PROP_MAX_FLAGS_LEN and only + * known flag names and values will be accepted. + */ + HGCMFunctionParameter flags; +} GuestPropMsgSetProperty; +AssertCompileSize(GuestPropMsgSetProperty, 40 + 3 * (ARCH_BITS == 64 ? 16 : 12)); + +/** The guest is requesting to change the value of a property */ +typedef struct GuestPropMsgSetPropertyValue +{ + VBGLIOCHGCMCALL hdr; + + /** + * The property name. (IN pointer) + * This must fit to a number of criteria, namely + * - Only Utf8 strings are allowed + * - Less than or equal to MAX_NAME_LEN bytes in length + * - Zero terminated + */ + HGCMFunctionParameter name; + + /** + * The value of the property (IN pointer) + * Criteria as for the name parameter, but with length less than or equal to + * MAX_VALUE_LEN. + */ + HGCMFunctionParameter value; +} GuestPropMsgSetPropertyValue; +AssertCompileSize(GuestPropMsgSetPropertyValue, 40 + 2 * (ARCH_BITS == 64 ? 16 : 12)); + +/** The guest is requesting to remove a property */ +typedef struct GuestPropMsgDelProperty +{ + VBGLIOCHGCMCALL hdr; + + /** + * The property name. This must fit to a number of criteria, namely + * - Only Utf8 strings are allowed + * - Less than or equal to MAX_NAME_LEN bytes in length + * - Zero terminated + */ + HGCMFunctionParameter name; +} GuestPropMsgDelProperty; +AssertCompileSize(GuestPropMsgDelProperty, 40 + 1 * (ARCH_BITS == 64 ? 16 : 12)); + +/** The guest is requesting to enumerate properties */ +typedef struct GuestPropMsgEnumProperties +{ + VBGLIOCHGCMCALL hdr; + + /** + * Array of patterns to match the properties against, separated by '|' + * characters. For backwards compatibility, '\\0' is also accepted + * as a separater. + * (IN pointer) + * If only a single, empty pattern is given then match all. + */ + HGCMFunctionParameter patterns; + /** + * On success, null-separated array of strings in which the properties are + * returned. (OUT pointer) + * The number of strings in the array is always a multiple of four, + * and in sequences of name, value, timestamp (hexadecimal string) and the + * flags as a comma-separated list in the format "name=value". The list + * is terminated by an empty string after a "flags" entry (or at the + * start). + */ + HGCMFunctionParameter strings; + /** + * On success, the size of the returned data. If the buffer provided is + * too small, the size of buffer needed. (OUT uint32_t) + */ + HGCMFunctionParameter size; +} GuestPropMsgEnumProperties; +AssertCompileSize(GuestPropMsgEnumProperties, 40 + 3 * (ARCH_BITS == 64 ? 16 : 12)); + +/** + * The guest is polling for notifications on changes to properties, specifying + * a set of patterns to match the names of changed properties against and + * optionally the timestamp of the last notification seen. + * On success, VINF_SUCCESS will be returned and the buffer will contain + * details of a property notification. If no new notification is available + * which matches one of the specified patterns, the call will block until one + * is. + * If the last notification could not be found by timestamp, VWRN_NOT_FOUND + * will be returned and the oldest available notification will be returned. + * If a zero timestamp is specified, the call will always wait for a new + * notification to arrive. + * If the buffer supplied was not large enough to hold the notification, + * VERR_BUFFER_OVERFLOW will be returned and the size parameter will contain + * the size of the buffer needed. + * + * The protocol for a guest to obtain notifications is to call + * GET_NOTIFICATION in a loop. On the first call, the ingoing timestamp + * parameter should be set to zero. On subsequent calls, it should be set to + * the outgoing timestamp from the previous call. + */ +typedef struct GuestPropMsgGetNotification +{ + VBGLIOCHGCMCALL hdr; + + /** + * A list of patterns to match the guest event name against, separated by + * vertical bars (|) (IN pointer) + * An empty string means match all. + */ + HGCMFunctionParameter patterns; + /** + * The timestamp of the last change seen (IN uint64_t) + * This may be zero, in which case the oldest available change will be + * sent. If the service does not remember an event matching the + * timestamp, then VWRN_NOT_FOUND will be returned, and the guest should + * assume that it has missed a certain number of notifications. + * + * The timestamp of the change being notified of (OUT uint64_t) + * Undefined on failure. + */ + HGCMFunctionParameter timestamp; + + /** + * The returned data, if any, will be placed here. (OUT pointer) + * This call returns three null-terminated strings which will be placed + * one after another: name, value and flags. For a delete notification, + * value and flags will be empty strings. Undefined on failure. + */ + HGCMFunctionParameter buffer; + + /** + * On success, the size of the returned data. (OUT uint32_t) + * On buffer overflow, the size of the buffer needed to hold the data. + * Undefined on failure. + */ + HGCMFunctionParameter size; +} GuestPropMsgGetNotification; +AssertCompileSize(GuestPropMsgGetNotification, 40 + 4 * (ARCH_BITS == 64 ? 16 : 12)); + + +#endif /* !VBOX_INCLUDED_HostServices_GuestPropertySvc_h */ + diff --git a/include/VBox/HostServices/Makefile.kup b/include/VBox/HostServices/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/VBox/HostServices/Service.h b/include/VBox/HostServices/Service.h new file mode 100644 index 00000000..d45512cb --- /dev/null +++ b/include/VBox/HostServices/Service.h @@ -0,0 +1,358 @@ +/** @file + * Base class for an host-guest service. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_HostServices_Service_h +#define VBOX_INCLUDED_HostServices_Service_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +#include +#include +#include + +#include + + +namespace HGCM +{ + +/** + * Structure for keeping a HGCM service context. + */ +typedef struct VBOXHGCMSVCTX +{ + /** HGCM helper functions. */ + PVBOXHGCMSVCHELPERS pHelpers; + /** + * Callback function supplied by the host for notification of updates + * to properties. + */ + PFNHGCMSVCEXT pfnHostCallback; + /** User data pointer to be supplied to the host callback function. */ + void *pvHostData; +} VBOXHGCMSVCTX, *PVBOXHGCMSVCTX; + +/** + * Base class encapsulating and working with a HGCM message. + */ +class Message +{ +public: + Message(void); + Message(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]); + virtual ~Message(void); + + uint32_t GetParamCount(void) const RT_NOEXCEPT; + int GetData(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]) const RT_NOEXCEPT; + int GetParmU32(uint32_t uParm, uint32_t *pu32Info) const RT_NOEXCEPT; + int GetParmU64(uint32_t uParm, uint64_t *pu64Info) const RT_NOEXCEPT; + int GetParmPtr(uint32_t uParm, void **ppvAddr, uint32_t *pcbSize) const RT_NOEXCEPT; + uint32_t GetType(void) const RT_NOEXCEPT; + +public: + static int CopyParms(PVBOXHGCMSVCPARM paParmsDst, uint32_t cParmsDst, + PVBOXHGCMSVCPARM paParmsSrc, uint32_t cParmsSrc, + bool fDeepCopy) RT_NOEXCEPT; + +protected: + int initData(uint32_t uMsg, uint32_t cParms, VBOXHGCMSVCPARM aParms[]) RT_NOEXCEPT; + void reset() RT_NOEXCEPT; + +protected: + + /** Stored message type. */ + uint32_t m_uMsg; + /** Number of stored HGCM parameters. */ + uint32_t m_cParms; + /** Stored HGCM parameters. */ + PVBOXHGCMSVCPARM m_paParms; +}; + +/** + * Class for keeping and tracking a HGCM client. + */ +class Client +{ +public: + Client(uint32_t idClient); + virtual ~Client(void); + +public: + int Complete(VBOXHGCMCALLHANDLE hHandle, int rcOp = VINF_SUCCESS) RT_NOEXCEPT; + int CompleteDeferred(int rcOp = VINF_SUCCESS) RT_NOEXCEPT; + uint32_t GetClientID(void) const RT_NOEXCEPT; + VBOXHGCMCALLHANDLE GetHandle(void) const RT_NOEXCEPT; + uint32_t GetMsgType(void) const RT_NOEXCEPT; + uint32_t GetMsgParamCount(void) const RT_NOEXCEPT; + bool IsDeferred(void) const RT_NOEXCEPT; + void SetDeferred(VBOXHGCMCALLHANDLE hHandle, uint32_t u32Function, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT; + void SetSvcContext(const VBOXHGCMSVCTX &SvcCtx) RT_NOEXCEPT; + +public: + int SetDeferredMsgInfo(uint32_t uMsg, uint32_t cParms) RT_NOEXCEPT; + int SetDeferredMsgInfo(const Message *pMessage) RT_NOEXCEPT; + +protected: + int completeInternal(VBOXHGCMCALLHANDLE hHandle, int rcOp) RT_NOEXCEPT; + void reset(void) RT_NOEXCEPT; + +protected: + /** The client's HGCM client ID. */ + uint32_t m_idClient; + /** The HGCM service context this client is bound to. */ + VBOXHGCMSVCTX m_SvcCtx; + /** Flag indicating whether this client currently is deferred mode, + * meaning that it did not return to the caller yet. */ + bool m_fDeferred; + /** Structure for keeping the client's deferred state. + * A client is in a deferred state when it asks for the next HGCM message, + * but the service can't provide it yet. That way a client will block (on the guest side, does not return) + * until the service can complete the call. */ + struct + { + /** The client's HGCM call handle. Needed for completing a deferred call. */ + VBOXHGCMCALLHANDLE hHandle; + /** Message type (function number) to use when completing the deferred call. + * @todo r=bird: uType or uMsg? Make up your mind (Message::m_uMsg). */ + uint32_t uType; + /** Parameter count to use when completing the deferred call. */ + uint32_t cParms; + /** Parameters to use when completing the deferred call. */ + PVBOXHGCMSVCPARM paParms; + } m_Deferred; +}; + +template +class AbstractService : public RTCNonCopyable +{ +public: + /** + * @copydoc FNVBOXHGCMSVCLOAD + */ + static DECLCALLBACK(int) svcLoad(VBOXHGCMSVCFNTABLE *pTable) + { + LogFlowFunc(("ptable = %p\n", pTable)); + int rc = VINF_SUCCESS; + + if (!RT_VALID_PTR(pTable)) + rc = VERR_INVALID_PARAMETER; + else + { + LogFlowFunc(("ptable->cbSize = %d, ptable->u32Version = 0x%08X\n", pTable->cbSize, pTable->u32Version)); + + if ( pTable->cbSize != sizeof (VBOXHGCMSVCFNTABLE) + || pTable->u32Version != VBOX_HGCM_SVC_VERSION) + rc = VERR_VERSION_MISMATCH; + else + { + AbstractService *pService = NULL; + /* No exceptions may propagate outside (callbacks like this one are nothrow/noexcept). */ + try { pService = new T(pTable->pHelpers); } + catch (std::bad_alloc &) { rc = VERR_NO_MEMORY; } + catch (...) { rc = VERR_UNEXPECTED_EXCEPTION; } + if (RT_SUCCESS(rc)) + { + /* We don't need an additional client data area on the host, + because we're a class which can have members for that :-). */ + /** @todo r=bird: What the comment above says is that we can duplicate the + * work of associating data with a client ID already done by the HGCM and create + * additional bugs because we think that's cool. It's not. Utterly + * appalling as well as inefficient. Just a structure with a pointer to a + * client base class would go a long way here. */ + pTable->cbClient = 0; + + /* These functions are mandatory */ + pTable->pfnUnload = svcUnload; + pTable->pfnConnect = svcConnect; + pTable->pfnDisconnect = svcDisconnect; + pTable->pfnCall = svcCall; + /* Clear obligatory functions. */ + pTable->pfnHostCall = NULL; + pTable->pfnSaveState = NULL; + pTable->pfnLoadState = NULL; + pTable->pfnRegisterExtension = NULL; + + /* Let the service itself initialize. */ + rc = pService->init(pTable); + if (RT_SUCCESS(rc)) + pTable->pvService = pService; + else + delete pService; + } + } + } + + LogFlowFunc(("returning %Rrc\n", rc)); + return rc; + } + virtual ~AbstractService() {}; + +protected: + explicit AbstractService(PVBOXHGCMSVCHELPERS pHelpers) + { + RT_ZERO(m_SvcCtx); + m_SvcCtx.pHelpers = pHelpers; + } + virtual int init(VBOXHGCMSVCFNTABLE *ptable) RT_NOEXCEPT + { RT_NOREF1(ptable); return VINF_SUCCESS; } + virtual int uninit() RT_NOEXCEPT + { return VINF_SUCCESS; } + virtual int clientConnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT = 0; + virtual int clientDisconnect(uint32_t idClient, void *pvClient) RT_NOEXCEPT = 0; + virtual void guestCall(VBOXHGCMCALLHANDLE callHandle, uint32_t idClient, void *pvClient, uint32_t eFunction, + uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT = 0; + virtual int hostCall(uint32_t eFunction, uint32_t cParms, VBOXHGCMSVCPARM paParms[]) RT_NOEXCEPT + { RT_NOREF3(eFunction, cParms, paParms); return VINF_SUCCESS; } + + /** Type definition for use in callback functions. */ + typedef AbstractService SELF; + /** The HGCM service context this service is bound to. */ + VBOXHGCMSVCTX m_SvcCtx; + + /** + * @copydoc VBOXHGCMSVCFNTABLE::pfnUnload + * Simply deletes the service object + */ + static DECLCALLBACK(int) svcUnload(void *pvService) + { + AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER); + SELF *pSelf = reinterpret_cast(pvService); + int rc = pSelf->uninit(); + AssertRC(rc); + if (RT_SUCCESS(rc)) + delete pSelf; + return rc; + } + + /** + * @copydoc VBOXHGCMSVCFNTABLE::pfnConnect + * Stub implementation of pfnConnect and pfnDisconnect. + */ + static DECLCALLBACK(int) svcConnect(void *pvService, + uint32_t idClient, + void *pvClient, + uint32_t fRequestor, + bool fRestoring) + { + RT_NOREF(fRequestor, fRestoring); + AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER); + LogFlowFunc(("pvService=%p, idClient=%u, pvClient=%p\n", pvService, idClient, pvClient)); + SELF *pSelf = reinterpret_cast(pvService); + int rc = pSelf->clientConnect(idClient, pvClient); + LogFlowFunc(("rc=%Rrc\n", rc)); + return rc; + } + + /** + * @copydoc VBOXHGCMSVCFNTABLE::pfnConnect + * Stub implementation of pfnConnect and pfnDisconnect. + */ + static DECLCALLBACK(int) svcDisconnect(void *pvService, + uint32_t idClient, + void *pvClient) + { + AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER); + LogFlowFunc(("pvService=%p, idClient=%u, pvClient=%p\n", pvService, idClient, pvClient)); + SELF *pSelf = reinterpret_cast(pvService); + int rc = pSelf->clientDisconnect(idClient, pvClient); + LogFlowFunc(("rc=%Rrc\n", rc)); + return rc; + } + + /** + * @copydoc VBOXHGCMSVCFNTABLE::pfnCall + * Wraps to the call member function + */ + static DECLCALLBACK(void) svcCall(void *pvService, + VBOXHGCMCALLHANDLE callHandle, + uint32_t idClient, + void *pvClient, + uint32_t u32Function, + uint32_t cParms, + VBOXHGCMSVCPARM paParms[], + uint64_t tsArrival) + { + AssertLogRelReturnVoid(RT_VALID_PTR(pvService)); + LogFlowFunc(("pvService=%p, callHandle=%p, idClient=%u, pvClient=%p, u32Function=%u, cParms=%u, paParms=%p\n", + pvService, callHandle, idClient, pvClient, u32Function, cParms, paParms)); + SELF *pSelf = reinterpret_cast(pvService); + pSelf->guestCall(callHandle, idClient, pvClient, u32Function, cParms, paParms); + LogFlowFunc(("returning\n")); + RT_NOREF_PV(tsArrival); + } + + /** + * @copydoc VBOXHGCMSVCFNTABLE::pfnHostCall + * Wraps to the hostCall member function + */ + static DECLCALLBACK(int) svcHostCall(void *pvService, + uint32_t u32Function, + uint32_t cParms, + VBOXHGCMSVCPARM paParms[]) + { + AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER); + LogFlowFunc(("pvService=%p, u32Function=%u, cParms=%u, paParms=%p\n", pvService, u32Function, cParms, paParms)); + SELF *pSelf = reinterpret_cast(pvService); + int rc = pSelf->hostCall(u32Function, cParms, paParms); + LogFlowFunc(("rc=%Rrc\n", rc)); + return rc; + } + + /** + * @copydoc VBOXHGCMSVCFNTABLE::pfnRegisterExtension + * Installs a host callback for notifications of property changes. + */ + static DECLCALLBACK(int) svcRegisterExtension(void *pvService, + PFNHGCMSVCEXT pfnExtension, + void *pvExtension) + { + AssertLogRelReturn(RT_VALID_PTR(pvService), VERR_INVALID_PARAMETER); + LogFlowFunc(("pvService=%p, pfnExtension=%p, pvExtention=%p\n", pvService, pfnExtension, pvExtension)); + SELF *pSelf = reinterpret_cast(pvService); + pSelf->m_SvcCtx.pfnHostCallback = pfnExtension; + pSelf->m_SvcCtx.pvHostData = pvExtension; + return VINF_SUCCESS; + } + + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AbstractService); +}; + +} +#endif /* !VBOX_INCLUDED_HostServices_Service_h */ + diff --git a/include/VBox/HostServices/VBoxClipboardExt.h b/include/VBox/HostServices/VBoxClipboardExt.h new file mode 100644 index 00000000..d93acf23 --- /dev/null +++ b/include/VBox/HostServices/VBoxClipboardExt.h @@ -0,0 +1,66 @@ +/** @file + * Shared Clipboard - Common header for the service extension. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_HostServices_VBoxClipboardExt_h +#define VBOX_INCLUDED_HostServices_VBoxClipboardExt_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +# include +#endif + +#define VBOX_CLIPBOARD_EXT_FN_SET_CALLBACK (0) +#define VBOX_CLIPBOARD_EXT_FN_FORMAT_ANNOUNCE (1) +#define VBOX_CLIPBOARD_EXT_FN_DATA_READ (2) +#define VBOX_CLIPBOARD_EXT_FN_DATA_WRITE (3) + +typedef DECLCALLBACKTYPE(int, FNVRDPCLIPBOARDEXTCALLBACK,(uint32_t u32Function, uint32_t u32Format, void *pvData, uint32_t cbData)); +typedef FNVRDPCLIPBOARDEXTCALLBACK *PFNVRDPCLIPBOARDEXTCALLBACK; + +typedef struct _SHCLEXTPARMS +{ + uint32_t uFormat; + union + { + void *pvData; + PFNVRDPCLIPBOARDEXTCALLBACK pfnCallback; + } u; + uint32_t cbData; +} SHCLEXTPARMS; + +#endif /* !VBOX_INCLUDED_HostServices_VBoxClipboardExt_h */ diff --git a/include/VBox/HostServices/VBoxClipboardSvc.h b/include/VBox/HostServices/VBoxClipboardSvc.h new file mode 100644 index 00000000..45bb954a --- /dev/null +++ b/include/VBox/HostServices/VBoxClipboardSvc.h @@ -0,0 +1,1220 @@ +/** @file + * Shared Clipboard - Common header for host service and guest clients. + * + * Protocol history notes (incomplete): + * + * - VirtualBox 6.1.0 betas: Started work on adding support for copying & + * pasting files and directories, refactoring the protocol in the process. + * - Adds guest/host feature flags. + * - Adds context IDs (via guest feature flags). + * - Borrowed the message handling from guest controls. + * - Adds a multitude of functions and messages for dealing with file & dir + * copying, most inte + * + * - VirtualBox x.x.x: Missing a lot of gradual improvements here. + * + * - VirtualBox 1.3.2 (r17182): Initial implementation, supporting text. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_HostServices_VBoxClipboardSvc_h +#define VBOX_INCLUDED_HostServices_VBoxClipboardSvc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/** @name VBOX_SHCL_MODE_XXX - The Shared Clipboard modes of operation. + * @{ + */ +/** Shared Clipboard is disabled completely. */ +#define VBOX_SHCL_MODE_OFF 0 +/** Only transfers from host to the guest are possible. */ +#define VBOX_SHCL_MODE_HOST_TO_GUEST 1 +/** Only transfers from guest to the host are possible. */ +#define VBOX_SHCL_MODE_GUEST_TO_HOST 2 +/** Bidirectional transfers between guest and host are possible. */ +#define VBOX_SHCL_MODE_BIDIRECTIONAL 3 +/** @} */ + +/** @name VBOX_SHCL_TRANSFER_MODE_XXX - The Shared Clipboard file transfer mode (bit field). + * @{ + */ +/** Shared Clipboard file transfers are disabled. */ +#define VBOX_SHCL_TRANSFER_MODE_DISABLED UINT32_C(0) +/** Shared Clipboard file transfers are enabled. */ +#define VBOX_SHCL_TRANSFER_MODE_ENABLED RT_BIT(0) +/** Shared Clipboard file transfer mode valid mask. */ +#define VBOX_SHCL_TRANSFER_MODE_VALID_MASK UINT32_C(0x1) +/** @} */ + + +/** @name VBOX_SHCL_HOST_FN_XXX - The service functions which are callable by host. + * @note These are not sacred and can be modified at will as long as all host + * clients are updated accordingly (probably just Main). + * @{ + */ +/** Sets the current Shared Clipboard operation mode. */ +#define VBOX_SHCL_HOST_FN_SET_MODE 1 +/** Sets the current Shared Clipboard (file) transfers mode. + * Operates on the VBOX_SHCL_TRANSFERS_XXX defines. + * @since 6.1 */ +#define VBOX_SHCL_HOST_FN_SET_TRANSFER_MODE 2 +/** Run headless on the host, i.e. do not touch the host clipboard. */ +#define VBOX_SHCL_HOST_FN_SET_HEADLESS 3 + +/** Reports cancellation of the current operation to the guest. + * @since 6.1 - still a todo */ +#define VBOX_SHCL_HOST_FN_CANCEL 4 +/** Reports an error to the guest. + * @since 6.1 - still a todo */ +#define VBOX_SHCL_HOST_FN_ERROR 5 +/** @} */ + + +/** @name VBOX_SHCL_HOST_MSG_XXX - The host messages for the guest. + * @{ + */ +/** Returned only when the HGCM client session is closed (by different thread). + * + * This can require no futher host interaction since the session has been + * closed. + * + * @since 1.3.2 + */ +#define VBOX_SHCL_HOST_MSG_QUIT 1 +/** Request data for a specific format from the guest. + * + * Two parameters, first the 32-bit message ID followed by a 32-bit format bit + * (VBOX_SHCL_FMT_XXX). The guest will respond by issuing a + * VBOX_SHCL_GUEST_FN_DATA_WRITE. + * + * @note The host may sometimes incorrectly set more than one format bit, in + * which case it's up to the guest to pick which to write back. + * @since 1.3.2 + */ +#define VBOX_SHCL_HOST_MSG_READ_DATA 2 +/** Reports available clipboard format on the host to the guest. + * + * Two parameters, first the 32-bit message ID followed by a 32-bit format mask + * containing zero or more VBOX_SHCL_FMT_XXX flags. The guest is not require to + * respond to the host when receiving this message. + * + * @since 1.3.2 + */ +#define VBOX_SHCL_HOST_MSG_FORMATS_REPORT 3 +/** Message PEEK or GET operation was canceled, try again. + * + * This is returned by VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT and + * VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT in response to the guest calling + * VBOX_SHCL_GUEST_FN_MSG_CANCEL. The 2nd parameter is set to zero (be it + * thought of as a parameter count or a format mask). + * + * @since 6.1.0 + */ +#define VBOX_SHCL_HOST_MSG_CANCELED 4 + +/** Request data for a specific format from the guest with context ID. + * + * This is send instead of the VBOX_SHCL_HOST_MSG_READ_DATA message to guest + * that advertises VBOX_SHCL_GF_0_CONTEXT_ID. The first parameter is a 64-bit + * context ID which is to be used when issuing VBOX_SHCL_GUEST_F_DATA_WRITE, and + * the second parameter is a 32-bit format bit (VBOX_SHCL_FMT_XXX). The guest + * will respond by issuing a VBOX_SHCL_GUEST_F_DATA_WRITE. + * + * @note The host may sometimes incorrectly set more than one format bit, in + * which case it's up to the guest to pick which to write back. + * @since 6.1.2 + */ +#define VBOX_SHCL_HOST_MSG_READ_DATA_CID 5 + +/** Sends a transfer status to the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_STATUS 50 +/** Reads the root list header from the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_READ 51 +/** Writes the root list header to the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_HDR_WRITE 52 +/** Reads a root list entry from the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_READ 53 +/** Writes a root list entry to the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_ROOT_LIST_ENTRY_WRITE 54 +/** Open a transfer list on the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_LIST_OPEN 55 +/** Closes a formerly opened transfer list on the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_LIST_CLOSE 56 +/** Reads a list header from the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_READ 57 +/** Writes a list header to the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_LIST_HDR_WRITE 58 +/** Reads a list entry from the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_READ 59 +/** Writes a list entry to the guest. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_LIST_ENTRY_WRITE 60 +/** Open a transfer object on the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_OPEN 61 +/** Closes a formerly opened transfer object on the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_CLOSE 62 +/** Reads from an object on the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_READ 63 +/** Writes to an object on the guest side. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_OBJ_WRITE 64 +/** Indicates that the host has canceled a transfer. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_CANCEL 65 +/** Indicates that the an unrecoverable error on the host occurred. + * @since 6.1.? + */ +#define VBOX_SHCL_HOST_MSG_TRANSFER_ERROR 66 +/** @} */ + + +/** @name VBOX_SHCL_GUEST_FN_XXX - The service functions which are called by guest. + * @{ + */ +/** Calls the host and waits (blocking) for an host event VBOX_SHCL_HOST_MSG_XXX. + * + * @deprecated Replaced by VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT, + * VBOX_SHCL_GUEST_FN_MSG_GET, VBOX_SHCL_GUEST_FN_MSG_CANCEL. + * @since 1.3.2 + */ +#define VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT 1 +/** Sends a list of available formats to the host. + * + * This function takes a single parameter, a 32-bit set of formats + * (VBOX_SHCL_FMT_XXX), this can be zero if the clipboard is empty or previously + * reported formats are no longer avaible (logout, shutdown, whatever). + * + * There was a period during 6.1 development where it would take three + * parameters, a 64-bit context ID preceeded the formats and a 32-bit MBZ flags + * parameter was appended. This is still accepted, though deprecated. + * + * @returns May return informational statuses indicating partial success, just + * ignore it. + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @retval VERR_NOT_SUPPORTED if all the formats are unsupported, host + * clipboard will be empty. + * @since 1.3.2 + */ +#define VBOX_SHCL_GUEST_FN_REPORT_FORMATS 2 +/** Reads data in specified format from the host. + * + * This function takes three parameters, a 32-bit format bit + * (VBOX_SHCL_FMT_XXX), a buffer and 32-bit number of bytes read (output). + * + * There was a period during 6.1 development where it would take five parameters + * when VBOX_SHCL_GF_0_CONTEXT_ID was reported by the guest. A 64-bit context + * ID (ignored as purpose undefined), a 32-bit unused flag (MBZ), then the + * 32-bit format bits, number of bytes read (output), and the buffer. This + * format is still accepted. + * + * @retval VINF_SUCCESS on success. + * @retval VINF_BUFFER_OVERLFLOW (VBox >= 6.1 only) if not enough buffer space + * has been given to retrieve the actual data, no data actually copied. + * The call then must be repeated with a buffer size returned from the + * host in cbData. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 1.3.2 + */ +#define VBOX_SHCL_GUEST_FN_DATA_READ 3 +/** Writes requested data to the host. + * + * This function takes either 2 or 3 parameters. The last two parameters are a + * 32-bit format bit (VBOX_SHCL_FMT_XXX) and a data buffer holding the related + * data. The three parameter variant have a context ID first, which shall be a + * copy of the ID in the data request message. + * + * There was a period during 6.1 development where there would be a 5 parameter + * version of this, inserting an unused flags parameter between the context ID + * and the format bit, as well as a 32-bit data buffer size repate between the + * format bit and the data buffer. This format is still accepted, though + * deprecated. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @retval VERR_INVALID_CONTEXT if the context ID didn't match up. + * @since 1.3.2 + */ +#define VBOX_SHCL_GUEST_FN_DATA_WRITE 4 + +/** This is a left-over from the 6.1 dev cycle and will always fail. + * + * It used to take three 32-bit parameters, only one of which was actually used. + * + * It was replaced by VBOX_SHCL_GUEST_FN_REPORT_FEATURES and + * VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE. + * + * @retval VERR_NOT_IMPLEMENTED + * @since 6.1 + */ +#define VBOX_SHCL_GUEST_FN_CONNECT 5 +/** Report guest side feature flags and retrieve the host ones. + * + * Two 64-bit parameters are passed in from the guest with the guest features + * (VBOX_SHCL_GF_XXX), the host replies by replacing the parameter values with + * the host ones (VBOX_SHCL_HF_XXX). + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.0 + */ +#define VBOX_SHCL_GUEST_FN_REPORT_FEATURES 6 +/** Query the host ones feature masks. + * + * That way the guest (client) can get hold of the features from the host. + * Again, it is prudent to set the 127 bit and observe it being cleared on + * success, as older hosts might return success without doing anything. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.0 + */ +#define VBOX_SHCL_GUEST_FN_QUERY_FEATURES 7 +/** Peeks at the next message, returning immediately. + * + * Returns two 32-bit parameters, first is the message ID and the second the + * parameter count. May optionally return additional 32-bit parameters with the + * sizes of respective message parameters. To distinguish buffer sizes from + * integer parameters, the latter gets their sizes inverted (uint32_t is ~4U, + * uint64_t is ~8U). + * + * Does also support the VM restore checking as in VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT + * (64-bit param \# 0), see documentation there. + * + * @retval VINF_SUCCESS if a message was pending and is being returned. + * @retval VERR_TRY_AGAIN if no message pending. + * @retval VERR_VM_RESTORED if first parameter is a non-zero 64-bit value that + * does not match VbglR3GetSessionId() any more. The new value is + * returned. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.0 + */ +#define VBOX_SHCL_GUEST_FN_MSG_PEEK_NOWAIT 8 +/** Peeks at the next message, waiting for one to arrive. + * + * Returns two 32-bit parameters, first is the message ID and the second the + * parameter count. May optionally return additional 32-bit parameters with the + * sizes of respective message parameters. To distinguish buffer sizes from + * integer parameters, the latter gets their sizes inverted (uint32_t is ~4U, + * uint64_t is ~8U). + * + * To facilitate VM restore checking, the first parameter can be a 64-bit + * integer holding the VbglR3GetSessionId() value the guest knowns. The + * function will then check this before going to sleep and return + * VERR_VM_RESTORED if it doesn't match, same thing happens when the VM is + * restored. + * + * @retval VINF_SUCCESS if info about an pending message is being returned. + * @retval VINF_TRY_AGAIN and message set to VBOX_SHCL_HOST_MSG_CANCELED if + * cancelled by VBOX_SHCL_GUEST_FN_MSG_CANCEL. + * @retval VERR_RESOURCE_BUSY if another thread already made a waiting call. + * @retval VERR_VM_RESTORED if first parameter is a non-zero 64-bit value that + * does not match VbglR3GetSessionId() any more. The new value is + * returned. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @note This replaces VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT. + * @since 6.1.0 + */ +#define VBOX_SHCL_GUEST_FN_MSG_PEEK_WAIT 9 +/** Gets the next message, returning immediately. + * + * All parameters are specific to the message being retrieved, however if the + * first one is an integer value it shall be an input parameter holding the + * ID of the message being retrieved. While it would be nice to add a separate + * parameter for this purpose, this is done so because the code was liften from + * Guest Controls which had backwards compatibilities to consider and we just + * kept it like that. + * + * @retval VINF_SUCCESS if message retrieved and removed from the pending queue. + * @retval VERR_TRY_AGAIN if no message pending. + * @retval VERR_MISMATCH if the incoming message ID does not match the pending. + * @retval VERR_BUFFER_OVERFLOW if a parmeter buffer is too small. The buffer + * size was updated to reflect the required size. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @note This replaces VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT. + * @since 6.1.0 + */ +#define VBOX_SHCL_GUEST_FN_MSG_GET 10 +/** Cancels pending calls for this client session. + * + * This should be used if a VBOX_SHCL_GUEST_FN__MSG_PEEK_WAIT or + * VBOX_SHCL_GUEST_FN_MSG_OLD_GET_WAIT call gets interrupted on the client end, + * so as to prevent being rebuffed with VERR_RESOURCE_BUSY when restarting the + * call. + * + * @retval VINF_SUCCESS if cancelled any calls. + * @retval VWRN_NOT_FOUND if no callers. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @since 6.1.0 + */ +#define VBOX_SHCL_GUEST_FN_MSG_CANCEL 26 + +/** Replies to a function from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_REPLY 11 +/** Gets the root list header from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_READ 12 +/** Sends the root list header to the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_ROOT_LIST_HDR_WRITE 13 +/** Gets a root list root entry from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_READ 14 +/** Sends a root list root entry to the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_ROOT_LIST_ENTRY_WRITE 15 +/** Opens / gets a list handle from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_LIST_OPEN 16 +/** Closes a list handle from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_LIST_CLOSE 17 +/** Reads a list header from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_LIST_HDR_READ 18 +/** Writes a list header to the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_LIST_HDR_WRITE 19 +/** Reads a list entry from the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_LIST_ENTRY_READ 20 +/** Sends a list entry to the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_LIST_ENTRY_WRITE 21 +/** Opens an object on the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_OBJ_OPEN 22 +/** Closes an object on the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_OBJ_CLOSE 23 +/** Reads from an object on the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_OBJ_READ 24 +/** Writes to an object on the host. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1.x + */ +#define VBOX_SHCL_GUEST_FN_OBJ_WRITE 25 +/** Reports an error to the host. + * + * @todo r=bird: Smells like GUEST_MSG_SKIP + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @since 6.1 + */ +#define VBOX_SHCL_GUEST_FN_ERROR 27 + +/** For negotiating a chunk size between the guest and host. + * + * Takes two 32-bit parameters both being byte counts, the first one gives the + * maximum chunk size the guest can handle and the second the preferred choice + * of the guest. Upon return, the host will have updated both of them to + * reflect the maximum and default chunk sizes this client connect. The guest + * may set the 2nd value to zero and let the host choose. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_INVALID_CLIENT_ID + * @retval VERR_WRONG_PARAMETER_COUNT + * @retval VERR_WRONG_PARAMETER_TYPE + * @retval VERR_INVALID_PARAMETER if the 2nd parameter is larger than the + * first one + * @since 6.1 + */ +#define VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE 28 + +/** The last function number (used for validation/sanity). */ +#define VBOX_SHCL_GUEST_FN_LAST VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE +/** @} */ + + +/** Maximum chunk size for a single data transfer. */ +#define VBOX_SHCL_MAX_CHUNK_SIZE VMMDEV_MAX_HGCM_DATA_SIZE - _4K +/** Default chunk size for a single data transfer. */ +#define VBOX_SHCL_DEFAULT_CHUNK_SIZE RT_MIN(_64K, VBOX_SHCL_MAX_CHUNK_SIZE); + + +/** @name VBOX_SHCL_GF_XXX - Guest features. + * @sa VBOX_SHCL_GUEST_FN_REPORT_FEATURES + * @{ */ +/** No flags set. */ +#define VBOX_SHCL_GF_NONE 0 +/** The guest can handle context IDs where applicable. */ +#define VBOX_SHCL_GF_0_CONTEXT_ID RT_BIT_64(0) +/** The guest can copy & paste files and directories. + * @since 6.x */ +#define VBOX_SHCL_GF_0_TRANSFERS RT_BIT_64(1) +/** The guest supports a (guest OS-)native frontend for showing and handling file transfers. + * If not set, the host will show a modal progress dialog instead and transferring file to + * a guest-specific temporary location first. + * Currently only supported for Windows guests (integrated into Windows Explorer via IDataObject). */ +#define VBOX_SHCL_GF_0_TRANSFERS_FRONTEND RT_BIT_64(2) +/** Bit that must be set in the 2nd parameter, will be cleared if the host reponds + * correctly (old hosts might not). */ +#define VBOX_SHCL_GF_1_MUST_BE_ONE RT_BIT_64(63) +/** @} */ + +/** @name VBOX_GUESTCTRL_HF_XXX - Host features. + * @sa VBOX_SHCL_GUEST_FN_REPORT_FEATURES + * @{ */ +/** No flags set. */ +#define VBOX_SHCL_HF_NONE 0 +/** The host can handle context IDs where applicable as well as the new + * message handling functions. */ +#define VBOX_SHCL_HF_0_CONTEXT_ID RT_BIT_64(0) +/** The host can copy & paste files and directories. + * This includes messages like + * @since 6.1.? */ +#define VBOX_SHCL_HF_0_TRANSFERS RT_BIT_64(1) +/** @} */ + +/** @name Context ID related macros and limits + * @{ */ +/** + * Creates a context ID out of a client ID, a transfer ID and an event ID (count). + */ +#define VBOX_SHCL_CONTEXTID_MAKE(a_idSession, a_idTransfer, a_idEvent) \ + ( ((uint64_t)((a_idSession) & 0xffff) << 48) \ + | ((uint64_t)((a_idTransfer) & 0xffff) << 32) \ + | ((uint32_t) (a_idEvent)) \ + ) +/** Creates a context ID out of a session ID. */ +#define VBOX_SHCL_CONTEXTID_MAKE_SESSION(a_idSession) VBOX_SHCL_CONTEXTID_MAKE(a_idSession, 0, 0) +/** Gets the session ID out of a context ID. */ +#define VBOX_SHCL_CONTEXTID_GET_SESSION(a_idContext) ( (uint16_t)(((a_idContext) >> 48) & UINT16_MAX) ) +/** Gets the transfer ID out of a context ID. */ +#define VBOX_SHCL_CONTEXTID_GET_TRANSFER(a_idContext) ( (uint16_t)(((a_idContext) >> 32) & UINT16_MAX) ) +/** Gets the transfer event out of a context ID. */ +#define VBOX_SHCL_CONTEXTID_GET_EVENT(a_idContext) ( (uint32_t)( (a_idContext) & UINT32_MAX) ) + +/** Maximum number of concurrent Shared Clipboard client sessions a VM can have. */ +#define VBOX_SHCL_MAX_SESSIONS (UINT16_MAX - 1) +/** Maximum number of concurrent Shared Clipboard transfers a single client can have. */ +#define VBOX_SHCL_MAX_TRANSFERS (UINT16_MAX - 1) +/** Maximum number of events a single Shared Clipboard transfer can have. */ +#define VBOX_SHCL_MAX_EVENTS (UINT32_MAX - 1) +/** @} */ + + +/* + * HGCM parameter structures. + */ +/** @todo r=bird: These structures are mostly pointless, as they're only + * ever used by the VbglR3 part. The host service does not use these + * structures for decoding guest requests, instead it's all hardcoded. */ +#pragma pack(1) +/** + * Waits (blocking) for a new host message to arrive. + * Deprecated; do not use anymore. + * Kept for maintaining compatibility with older Guest Additions. + */ +typedef struct _VBoxShClGetHostMsgOld +{ + VBGLIOCHGCMCALL hdr; + + /** uint32_t, out: Host message type. */ + HGCMFunctionParameter msg; + /** uint32_t, out: VBOX_SHCL_FMT_*, depends on the 'msg'. + * r=andy This actual can have *different* meanings, depending on the host message type. */ + HGCMFunctionParameter formats; /* OUT uint32_t */ +} VBoxShClGetHostMsgOld; + +#define VBOX_SHCL_CPARMS_GET_HOST_MSG_OLD 2 + +/** @name VBOX_SHCL_GUEST_FN_REPORT_FORMATS + * @{ */ +/** VBOX_SHCL_GUEST_FN_REPORT_FORMATS parameters. */ +typedef struct VBoxShClParmReportFormats +{ + /** uint32_t, int: Zero or more VBOX_SHCL_FMT_XXX bits. */ + HGCMFunctionParameter f32Formats; +} VBoxShClParmReportFormats; + +#define VBOX_SHCL_CPARMS_REPORT_FORMATS 1 /**< The parameter count for VBOX_SHCL_GUEST_FN_REPORT_FORMATS. */ +#define VBOX_SHCL_CPARMS_REPORT_FORMATS_61B 3 /**< The 6.1 dev cycle variant, see VBOX_SHCL_GUEST_FN_REPORT_FORMATS. */ +/** @} */ + +/** @name VBOX_SHCL_GUEST_FN_DATA_READ + * @{ */ +/** VBOX_SHCL_GUEST_FN_DATA_READ parameters. */ +typedef struct VBoxShClParmDataRead +{ + /** uint32_t, in: Requested format (VBOX_SHCL_FMT_XXX). */ + HGCMFunctionParameter f32Format; + /** ptr, out: The data buffer to put the data in on success. */ + HGCMFunctionParameter pData; + /** uint32_t, out: Size of returned data, if larger than the buffer, then no + * data was actually transferred and the guest must repeat the call. */ + HGCMFunctionParameter cb32Needed; +} VBoxShClParmDataRead; + +#define VBOX_SHCL_CPARMS_DATA_READ 3 /**< The parameter count for VBOX_SHCL_GUEST_FN_DATA_READ. */ +#define VBOX_SHCL_CPARMS_DATA_READ_61B 5 /**< The 6.1 dev cycle variant, see VBOX_SHCL_GUEST_FN_DATA_READ. */ +/** @} */ + +/** @name + * @{ */ + +/** VBOX_SHCL_GUEST_FN_DATA_WRITE parameters. */ +typedef struct VBoxShClParmDataWrite +{ + /** uint64_t, in: Context ID from VBOX_SHCL_HOST_MSG_READ_DATA. */ + HGCMFunctionParameter id64Context; + /** uint32_t, in: The data format (VBOX_SHCL_FMT_XXX). */ + HGCMFunctionParameter f32Format; + /** ptr, in: The data. */ + HGCMFunctionParameter pData; +} VBoxShClParmDataWrite; + +/** Old VBOX_SHCL_GUEST_FN_DATA_WRITE parameters. */ +typedef struct VBoxShClParmDataWriteOld +{ + /** uint32_t, in: The data format (VBOX_SHCL_FMT_XXX). */ + HGCMFunctionParameter f32Format; + /** ptr, in: The data. */ + HGCMFunctionParameter pData; +} VBoxShClParmDataWriteOld; + +#define VBOX_SHCL_CPARMS_DATA_WRITE 3 /**< The variant used when VBOX_SHCL_GF_0_CONTEXT_ID is reported. */ +#define VBOX_SHCL_CPARMS_DATA_WRITE_OLD 2 /**< The variant used when VBOX_SHCL_GF_0_CONTEXT_ID isn't reported. */ +#define VBOX_SHCL_CPARMS_DATA_WRITE_61B 5 /**< The 6.1 dev cycle variant, see VBOX_SHCL_GUEST_FN_DATA_WRITE. */ +/** @} */ + +/** + * Reports a transfer status. + */ +typedef struct _VBoxShClTransferStatusMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, out: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, out: Direction of transfer; of type SHCLTRANSFERDIR_. */ + HGCMFunctionParameter enmDir; + /** uint32_t, out: Status to report; of type SHCLTRANSFERSTATUS_. */ + HGCMFunctionParameter enmStatus; + /** uint32_t, out: Result code to report. Optional. */ + HGCMFunctionParameter rc; + /** uint32_t, out: Reporting flags. Currently unused and must be 0. */ + HGCMFunctionParameter fFlags; +} VBoxShClTransferStatusMsg; + +#define VBOX_SHCL_CPARMS_TRANSFER_STATUS 5 + +/** + * Asks the host for the next command to process, along + * with the needed amount of parameters and an optional blocking + * flag. + * + * Used by: VBOX_SHCL_GUEST_FN_GET_HOST_MSG + * + */ +typedef struct _VBoxShClGetHostMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint32_t, out: Message ID. */ + HGCMFunctionParameter uMsg; + /** uint32_t, out: Number of parameters the message needs. */ + HGCMFunctionParameter cParms; + /** uint32_t, in: Whether or not to block (wait) for a new message to arrive. */ + HGCMFunctionParameter fBlock; +} VBoxShClPeekMsg; + +#define VBOX_SHCL_CPARMS_GET_HOST_MSG 3 + +/** No listing flags specified. */ +#define VBOX_SHCL_LIST_FLAG_NONE 0 +/** Only returns one entry per read. */ +#define VBOX_SHCL_LIST_FLAG_RETURN_ONE RT_BIT(0) +/** Restarts reading a list from the beginning. */ +#define VBOX_SHCL_LIST_FLAG_RESTART RT_BIT(1) + +#define VBOX_SHCL_LISTHDR_FLAG_NONE 0 + +/** No additional information provided. */ +#define VBOX_SHCL_INFO_FLAG_NONE 0 +/** Get object information of type SHCLFSOBJINFO. */ +#define VBOX_SHCL_INFO_FLAG_FSOBJINFO RT_BIT(0) + +/** + * Status message for lists and objects. + */ +typedef struct _VBoxShClStatusMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, in: Transfer status of type SHCLTRANSFERSTATUS. */ + HGCMFunctionParameter uStatus; + /** pointer, in: Optional payload of this status, based on the status type. */ + HGCMFunctionParameter pvPayload; +} VBoxShClStatusMsg; + +#define VBOX_SHCL_CPARMS_STATUS 3 + +/** Invalid message type, do not use. */ +#define VBOX_SHCL_REPLYMSGTYPE_INVALID 0 +/** Replies a transfer status. */ +#define VBOX_SHCL_REPLYMSGTYPE_TRANSFER_STATUS 1 +/** Replies a list open status. */ +#define VBOX_SHCL_REPLYMSGTYPE_LIST_OPEN 2 +/** Replies a list close status. */ +#define VBOX_SHCL_REPLYMSGTYPE_LIST_CLOSE 3 +/** Replies an object open status. */ +#define VBOX_SHCL_REPLYMSGTYPE_OBJ_OPEN 4 +/** Replies an object close status. */ +#define VBOX_SHCL_REPLYMSGTYPE_OBJ_CLOSE 5 + +/** + * Generic reply message. + */ +typedef struct _VBoxShClReplyMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, out: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, out: Message type of type VBOX_SHCL_REPLYMSGTYPE_XXX. */ + HGCMFunctionParameter enmType; + /** uint32_t, out: IPRT result of overall operation. */ + HGCMFunctionParameter rc; + /** pointer, out: Optional payload of this reply, based on the message type. */ + HGCMFunctionParameter pvPayload; + union + { + struct + { + HGCMFunctionParameter enmStatus; + } TransferStatus; + struct + { + HGCMFunctionParameter uHandle; + } ListOpen; + struct + { + HGCMFunctionParameter uHandle; + } ObjOpen; + struct + { + HGCMFunctionParameter uHandle; + } ObjClose; + } u; +} VBoxShClReplyMsg; + +/** Minimum parameters (HGCM function parameters minus the union) a reply message must have. */ +#define VBOX_SHCL_CPARMS_REPLY_MIN 4 + +/** + * Structure for keeping root list message parameters. + */ +typedef struct _VBoxShClRootListParms +{ + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, in: Roots listing flags; unused at the moment. */ + HGCMFunctionParameter fRoots; +} VBoxShClRootListParms; + +#define VBOX_SHCL_CPARMS_ROOT_LIST 2 + +/** + * Requests to read the root list header. + */ +typedef struct _VBoxShClRootListReadReqMsg +{ + VBGLIOCHGCMCALL hdr; + + VBoxShClRootListParms ReqParms; +} VBoxShClRootListReadReqMsg; + +#define VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ_REQ VBOX_SHCL_CPARMS_ROOT_LIST + +/** + * Reads / Writes a root list header. + */ +typedef struct _VBoxShClRootListHdrMsg +{ + VBGLIOCHGCMCALL hdr; + + VBoxShClRootListParms ReqParms; + /** uint64_t, in/out: Number of total root list entries. */ + HGCMFunctionParameter cRoots; +} VBoxShClRootListHdrMsg; + +#define VBOX_SHCL_CPARMS_ROOT_LIST_HDR_READ VBOX_SHCL_CPARMS_ROOT_LIST + 1 +#define VBOX_SHCL_CPARMS_ROOT_LIST_HDR_WRITE VBOX_SHCL_CPARMS_ROOT_LIST + 1 + +/** + * Structure for keeping list entry message parameters. + */ +typedef struct _VBoxShClRootListEntryParms +{ + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, in: VBOX_SHCL_INFO_FLAG_XXX. */ + HGCMFunctionParameter fInfo; + /** uint32_t, in: Index of root list entry to get (zero-based). */ + HGCMFunctionParameter uIndex; +} VBoxShClRootListEntryParms; + +#define VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY 3 + +/** + * Request to read a list root entry. + */ +typedef struct _VBoxShClRootListEntryReadReqMsg +{ + VBGLIOCHGCMCALL hdr; + + /** in: Request parameters. */ + VBoxShClRootListEntryParms Parms; +} VBoxShClRootListEntryReadReqMsg; + +#define VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ_REQ VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY + +/** + * Reads / Writes a root list entry. + */ +typedef struct _VBoxShClRootListEntryMsg +{ + VBGLIOCHGCMCALL hdr; + + /** in/out: Request parameters. */ + VBoxShClRootListEntryParms Parms; + /** pointer, in/out: Entry name. */ + HGCMFunctionParameter szName; + /** uint32_t, out: Bytes to be used for information/How many bytes were used. */ + HGCMFunctionParameter cbInfo; + /** pointer, in/out: Information to be set/get (SHCLFSOBJINFO only currently). + * Do not forget to set the SHCLFSOBJINFO::Attr::enmAdditional for Get operation as well. */ + HGCMFunctionParameter pvInfo; +} VBoxShClRootListEntryMsg; + +#define VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_READ VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY + 3 +#define VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY_WRITE VBOX_SHCL_CPARMS_ROOT_LIST_ENTRY + 3 + +/** + * Opens a list. + */ +typedef struct _VBoxShClListOpenMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, in: Listing flags (see VBOX_SHCL_LIST_FLAG_XXX). */ + HGCMFunctionParameter fList; + /** pointer, in: Filter string. */ + HGCMFunctionParameter pvFilter; + /** pointer, in: Listing poth. If empty or NULL the listing's root path will be opened. */ + HGCMFunctionParameter pvPath; + /** uint64_t, out: List handle. */ + HGCMFunctionParameter uHandle; +} VBoxShClListOpenMsg; + +#define VBOX_SHCL_CPARMS_LIST_OPEN 5 + +/** + * Closes a list. + */ +typedef struct _VBoxShClListCloseMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in/out: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, in: List handle. */ + HGCMFunctionParameter uHandle; +} VBoxShClListCloseMsg; + +#define VBOX_SHCL_CPARMS_LIST_CLOSE 2 + +typedef struct _VBoxShClListHdrReqParms +{ + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, in: List handle. */ + HGCMFunctionParameter uHandle; + /** uint32_t, in: Flags of type VBOX_SHCL_LISTHDR_FLAG_XXX. */ + HGCMFunctionParameter fFlags; +} VBoxShClListHdrReqParms; + +#define VBOX_SHCL_CPARMS_LIST_HDR_REQ 3 + +/** + * Request to read a list header. + */ +typedef struct _VBoxShClListHdrReadReqMsg +{ + VBGLIOCHGCMCALL hdr; + + VBoxShClListHdrReqParms ReqParms; +} VBoxShClListHdrReadReqMsg; + +#define VBOX_SHCL_CPARMS_LIST_HDR_READ_REQ VBOX_SHCL_CPARMS_LIST_HDR_REQ + +/** + * Reads / Writes a list header. + */ +typedef struct _VBoxShClListHdrMsg +{ + VBGLIOCHGCMCALL hdr; + + VBoxShClListHdrReqParms ReqParms; + /** uint32_t, in/out: Feature flags (see VBOX_SHCL_FEATURE_FLAG_XXX). */ + HGCMFunctionParameter fFeatures; + /** uint64_t, in/out: Number of total objects to transfer. */ + HGCMFunctionParameter cTotalObjects; + /** uint64_t, in/out: Number of total bytes to transfer. */ + HGCMFunctionParameter cbTotalSize; +} VBoxShClListHdrMsg; + +#define VBOX_SHCL_CPARMS_LIST_HDR VBOX_SHCL_CPARMS_LIST_HDR_REQ + 3 + +typedef struct _VBoxShClListEntryReqParms +{ + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, in: List handle. */ + HGCMFunctionParameter uHandle; + /** uint32_t, in: VBOX_SHCL_INFO_FLAG_XXX. */ + HGCMFunctionParameter fInfo; +} VBoxShClListEntryReqParms; + +#define VBOX_SHCL_CPARMS_LIST_ENTRY_REQ 3 + +/** + * Request to read a list entry. + */ +typedef struct _VBoxShClListEntryReadReqMsg +{ + VBGLIOCHGCMCALL hdr; + + VBoxShClListEntryReqParms ReqParms; +} VBoxShClListEntryReadReqMsg; + +#define VBOX_SHCL_CPARMS_LIST_ENTRY_READ VBOX_SHCL_CPARMS_LIST_ENTRY_REQ + +/** + * Reads / Writes a list entry. + */ +typedef struct _VBoxShClListEntryMsg +{ + VBGLIOCHGCMCALL hdr; + + /** in/out: Request parameters. */ + VBoxShClListEntryReqParms ReqParms; + /** pointer, in/out: Entry name. */ + HGCMFunctionParameter szName; + /** uint32_t, out: Bytes to be used for information/How many bytes were used. */ + HGCMFunctionParameter cbInfo; + /** pointer, in/out: Information to be set/get (SHCLFSOBJINFO only currently). + * Do not forget to set the SHCLFSOBJINFO::Attr::enmAdditional for Get operation as well. */ + HGCMFunctionParameter pvInfo; +} VBoxShClListEntryMsg; + +#define VBOX_SHCL_CPARMS_LIST_ENTRY VBOX_SHCL_CPARMS_LIST_ENTRY_REQ + 3 + +/** + * Opens a Shared Clipboard object. + */ +typedef struct _VBoxShClObjOpenMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in/out: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, out: Object handle. */ + HGCMFunctionParameter uHandle; + /** pointer, in: Absoulte path of object to open/create. */ + HGCMFunctionParameter szPath; + /** uint32_t in: Open / Create flags of type SHCL_OBJ_CF_. */ + HGCMFunctionParameter fCreate; +} VBoxShClObjOpenMsg; + +#define VBOX_SHCL_CPARMS_OBJ_OPEN 4 + +/** + * Closes a Shared Clipboard object. + */ +typedef struct _VBoxShClObjCloseMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in/out: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, in: SHCLOBJHANDLE of object to close. */ + HGCMFunctionParameter uHandle; +} VBoxShClObjCloseMsg; + +#define VBOX_SHCL_CPARMS_OBJ_CLOSE 2 + +/** + * Structure for keeping read parameters of a Shared Clipboard object. + */ +typedef struct _VBoxShClObjReadReqParms +{ + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, in: SHCLOBJHANDLE of object to write to. */ + HGCMFunctionParameter uHandle; + /** uint32_t, in: How many bytes to read. */ + HGCMFunctionParameter cbToRead; + /** uint32_t, in: Read flags. Currently unused and must be 0. */ + HGCMFunctionParameter fRead; +} VBoxShClObjReadReqParms; + +/** + * Reads from a Shared Clipboard object. + */ +typedef struct _VBoxShClObjReadReqMsg +{ + VBGLIOCHGCMCALL hdr; + + VBoxShClObjReadReqParms ReqParms; +} VBoxShClObjReadReqMsg; + +#define VBOX_SHCL_CPARMS_OBJ_READ_REQ 4 + +/** + * Reads / writes data of / to an object. + * + * Used by: + * VBOX_SHCL_FN_OBJ_READ + * VBOX_SHCL_FN_OBJ_WRITE + */ +typedef struct _VBoxShClObjReadWriteMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in/out: Context ID. */ + HGCMFunctionParameter uContext; + /** uint64_t, in/out: SHCLOBJHANDLE of object to write to. */ + HGCMFunctionParameter uHandle; + /** uint32_t, out: Size (in bytes) read/written. */ + HGCMFunctionParameter cbData; + /** pointer, in/out: Current data chunk. */ + HGCMFunctionParameter pvData; + /** uint32_t, in/out: Size (in bytes) of current data chunk checksum. */ + HGCMFunctionParameter cbChecksum; + /** pointer, in/out: Checksum of data block, based on the checksum + * type in the data header. Optional. */ + HGCMFunctionParameter pvChecksum; +} VBoxShClObjReadWriteMsg; + +#define VBOX_SHCL_CPARMS_OBJ_READ 6 +#define VBOX_SHCL_CPARMS_OBJ_WRITE 6 + +/** + * Sends an error event. + * + * Used by: + * VBOX_SHCL_FN_WRITE_ERROR + */ +typedef struct _VBoxShClErrorMsg +{ + VBGLIOCHGCMCALL hdr; + + /** uint64_t, in: Context ID. */ + HGCMFunctionParameter uContext; + /** uint32_t, in: The error code (IPRT-style). */ + HGCMFunctionParameter rc; +} VBoxShClWriteErrorMsg; + +#define VBOX_SHCL_CPARMS_ERROR 2 + +/** @name VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE + * @{ */ +/** VBOX_SHCL_GUEST_FN_NEGOTIATE_CHUNK_SIZE parameters. */ +typedef struct _VBoxShClParmNegotiateChunkSize +{ + VBGLIOCHGCMCALL hdr; + + /** uint32_t, in: Maximum chunk size. */ + HGCMFunctionParameter cb32MaxChunkSize; + /** uint32_t, in: Default chunk size. */ + HGCMFunctionParameter cb32ChunkSize; +} VBoxShClParmNegotiateChunkSize; + +#define VBOX_SHCL_CPARMS_NEGOTIATE_CHUNK_SIZE 2 +/** @} */ + +#pragma pack() + +#endif /* !VBOX_INCLUDED_HostServices_VBoxClipboardSvc_h */ + diff --git a/include/VBox/HostServices/VBoxHostChannel.h b/include/VBox/HostServices/VBoxHostChannel.h new file mode 100644 index 00000000..7ac452de --- /dev/null +++ b/include/VBox/HostServices/VBoxHostChannel.h @@ -0,0 +1,229 @@ +/** @file + * + * Host Channel: the service definition. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_HostServices_VBoxHostChannel_h +#define VBOX_INCLUDED_HostServices_VBoxHostChannel_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +/* + * Host calls. + */ +#define VBOX_HOST_CHANNEL_HOST_FN_REGISTER 1 +#define VBOX_HOST_CHANNEL_HOST_FN_UNREGISTER 2 + +/* + * Guest calls. + */ +#define VBOX_HOST_CHANNEL_FN_ATTACH 1 /* Attach to a channel. */ +#define VBOX_HOST_CHANNEL_FN_DETACH 2 /* Detach from the channel. */ +#define VBOX_HOST_CHANNEL_FN_SEND 3 /* Send data to the host. */ +#define VBOX_HOST_CHANNEL_FN_RECV 4 /* Receive data from the host. */ +#define VBOX_HOST_CHANNEL_FN_CONTROL 5 /* Generic data exchange using a channel instance. */ +#define VBOX_HOST_CHANNEL_FN_EVENT_WAIT 6 /* Blocking wait for a host event. */ +#define VBOX_HOST_CHANNEL_FN_EVENT_CANCEL 7 /* Cancel the blocking wait. */ +#define VBOX_HOST_CHANNEL_FN_QUERY 8 /* Generic data exchange using a channel name. */ + +/* + * The host event ids for the guest. + */ +#define VBOX_HOST_CHANNEL_EVENT_CANCELLED 0 /* Event was cancelled by FN_EVENT_CANCEL. */ +#define VBOX_HOST_CHANNEL_EVENT_UNREGISTERED 1 /* Channel was unregistered on host. */ +#define VBOX_HOST_CHANNEL_EVENT_RECV 2 /* Data is available for receiving. */ +#define VBOX_HOST_CHANNEL_EVENT_USER 1000 /* Base of channel specific events. */ + +/* + * The common control code ids for the VBOX_HOST_CHANNEL_FN_[CONTROL|QUERY] + */ +#define VBOX_HOST_CHANNEL_CTRL_EXISTS 0 /* Whether the channel instance or provider exists. */ +#define VBOX_HOST_CHANNEL_CTRL_USER 1000 /* Base of channel specific events. */ + +#pragma pack(1) + +/* Parameter of VBOX_HOST_CHANNEL_EVENT_RECV */ +typedef struct VBOXHOSTCHANNELEVENTRECV +{ + uint32_t u32SizeAvailable; /* How many bytes can be read from the channel. */ +} VBOXHOSTCHANNELEVENTRECV; + +/* + * Guest calls. + */ + +typedef struct VBoxHostChannelAttach +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter name; /* IN linear ptr: Channel name utf8 nul terminated. */ + HGCMFunctionParameter flags; /* IN uint32_t: Channel specific flags. */ + HGCMFunctionParameter handle; /* OUT uint32_t: The channel handle. */ +} VBoxHostChannelAttach; + +typedef struct VBoxHostChannelDetach +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter handle; /* IN uint32_t: The channel handle. */ +} VBoxHostChannelDetach; + +typedef struct VBoxHostChannelSend +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter handle; /* IN uint32_t: The channel handle. */ + HGCMFunctionParameter data; /* IN linear pointer: Data to be sent. */ +} VBoxHostChannelSend; + +typedef struct VBoxHostChannelRecv +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter handle; /* IN uint32_t: The channel handle. */ + HGCMFunctionParameter data; /* OUT linear pointer: Buffer for data to be received. */ + HGCMFunctionParameter sizeReceived; /* OUT uint32_t: Bytes received. */ + HGCMFunctionParameter sizeRemaining; /* OUT uint32_t: Bytes remaining in the channel. */ +} VBoxHostChannelRecv; + +typedef struct VBoxHostChannelControl +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter handle; /* IN uint32_t: The channel handle. */ + HGCMFunctionParameter code; /* IN uint32_t: The channel specific control code. */ + HGCMFunctionParameter parm; /* IN linear pointer: Parameters of the function. */ + HGCMFunctionParameter data; /* OUT linear pointer: Buffer for results. */ + HGCMFunctionParameter sizeDataReturned; /* OUT uint32_t: Bytes returned in the 'data' buffer. */ +} VBoxHostChannelControl; + +typedef struct VBoxHostChannelEventWait +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter handle; /* OUT uint32_t: The channel which generated the event. */ + HGCMFunctionParameter id; /* OUT uint32_t: The event VBOX_HOST_CHANNEL_EVENT_*. */ + HGCMFunctionParameter parm; /* OUT linear pointer: Parameters of the event. */ + HGCMFunctionParameter sizeReturned; /* OUT uint32_t: Size of the parameters. */ +} VBoxHostChannelEventWait; + +typedef struct VBoxHostChannelEventCancel +{ + VBGLIOCHGCMCALL hdr; +} VBoxHostChannelEventCancel; + +typedef struct VBoxHostChannelQuery +{ + VBGLIOCHGCMCALL hdr; + HGCMFunctionParameter name; /* IN linear ptr: Channel name utf8 nul terminated. */ + HGCMFunctionParameter code; /* IN uint32_t: The control code. */ + HGCMFunctionParameter parm; /* IN linear pointer: Parameters of the function. */ + HGCMFunctionParameter data; /* OUT linear pointer: Buffer for results. */ + HGCMFunctionParameter sizeDataReturned; /* OUT uint32_t: Bytes returned in the 'data' buffer. */ +} VBoxHostChannelQuery; + + +/* + * Host calls + */ + +typedef struct VBoxHostChannelHostRegister +{ + VBOXHGCMSVCPARM name; /* IN ptr: Channel name utf8 nul terminated. */ + VBOXHGCMSVCPARM iface; /* IN ptr: VBOXHOSTCHANNELINTERFACE. */ +} VBoxHostChannelHostRegister; + +typedef struct VBoxHostChannelHostUnregister +{ + VBOXHGCMSVCPARM name; /* IN ptr: Channel name utf8 nul terminated */ +} VBoxHostChannelHostUnregister; + +/* The channel provider will invoke this callback to report channel events. */ +typedef struct VBOXHOSTCHANNELCALLBACKS +{ + /* A channel event occured. + * + * @param pvCallbacks The callback context specified in HostChannelAttach. + * @param pvChannel The channel instance returned by HostChannelAttach. + * @param u32Id The event id. + * @param pvEvent The event parameters. + * @param cbEvent The size of event parameters. + */ + DECLR3CALLBACKMEMBER(void, HostChannelCallbackEvent, (void *pvCallbacks, void *pvChannel, + uint32_t u32Id, const void *pvEvent, uint32_t cbEvent)); + + /* The channel has been deleted by the provider. pvCallback will not be used anymore. + * + * @param pvCallbacks The callback context specified in HostChannelAttach. + * @param pvChannel The channel instance returned by HostChannelAttach. + */ + DECLR3CALLBACKMEMBER(void, HostChannelCallbackDeleted, (void *pvCallbacks, void *pvChannel)); +} VBOXHOSTCHANNELCALLBACKS; + +typedef struct VBOXHOSTCHANNELINTERFACE +{ + /* The channel provider context. */ + void *pvProvider; + + /* A new channel is requested. + * + * @param pvProvider The provider context VBOXHOSTCHANNELINTERFACE::pvProvider. + * @param ppvChannel Where to store pointer to the channel instance created by the provider. + * @param u32Flags Channel specific flags. + * @param pCallbacks Callbacks to be invoked by the channel provider. + * @param pvCallbacks The context of callbacks. + */ + DECLR3CALLBACKMEMBER(int, HostChannelAttach, (void *pvProvider, void **ppvChannel, uint32_t u32Flags, + VBOXHOSTCHANNELCALLBACKS *pCallbacks, void *pvCallbacks)); + + /* The channel is closed. */ + DECLR3CALLBACKMEMBER(void, HostChannelDetach, (void *pvChannel)); + + /* The guest sends data to the channel. */ + DECLR3CALLBACKMEMBER(int, HostChannelSend, (void *pvChannel, const void *pvData, uint32_t cbData)); + + /* The guest reads data from the channel. */ + DECLR3CALLBACKMEMBER(int, HostChannelRecv, (void *pvChannel, void *pvData, uint32_t cbData, + uint32_t *pcbReceived, uint32_t *pcbRemaining)); + + /* The guest talks to the provider of the channel. + * @param pvChannel The channel instance. NULL if the target is the provider, rather than a channel. + */ + DECLR3CALLBACKMEMBER(int, HostChannelControl, (void *pvChannel, uint32_t u32Code, + const void *pvParm, uint32_t cbParm, + const void *pvData, uint32_t cbData, uint32_t *pcbDataReturned)); +} VBOXHOSTCHANNELINTERFACE; + +#pragma pack() + +#endif /* !VBOX_INCLUDED_HostServices_VBoxHostChannel_h */ diff --git a/include/VBox/Makefile.kup b/include/VBox/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/VBox/RemoteDesktop/Makefile.kup b/include/VBox/RemoteDesktop/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/VBox/RemoteDesktop/VRDE.h b/include/VBox/RemoteDesktop/VRDE.h new file mode 100644 index 00000000..56c03226 --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDE.h @@ -0,0 +1,1615 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - Public APIs. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDE_h +#define VBOX_INCLUDED_RemoteDesktop_VRDE_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +/** @defgroup grp_vrdp VRDE + * VirtualBox Remote Desktop Extension (VRDE) interface that lets to use + * a Remote Desktop server like RDP. + * @{ + */ + +RT_C_DECLS_BEGIN + +/* Forward declaration of the VRDE server instance handle. + * This is an opaque pointer for VirtualBox. + * The VRDE library uses it as a pointer to some internal data. + */ +#ifdef __cplusplus +class VRDEServer; +typedef class VRDEServerType *HVRDESERVER; +#else +struct VRDEServer; +typedef struct VRDEServerType *HVRDESERVER; +#endif /* !__cplusplus */ + +/* Callback based VRDE server interface declarations. */ + +/** The color mouse pointer information. */ +typedef struct _VRDECOLORPOINTER +{ + uint16_t u16HotX; + uint16_t u16HotY; + uint16_t u16Width; + uint16_t u16Height; + uint16_t u16MaskLen; + uint16_t u16DataLen; + /* The 1BPP mask and the 24BPP bitmap follow. */ +} VRDECOLORPOINTER; + +/** Audio format information packed in a 32 bit value. */ +typedef uint32_t VRDEAUDIOFORMAT; + +/** Constructs 32 bit value for given frequency, number of channel and bits per sample. */ +#define VRDE_AUDIO_FMT_MAKE(freq, c, bps, s) ((((s) & 0x1) << 28) + (((bps) & 0xFF) << 20) + (((c) & 0xF) << 16) + ((freq) & 0xFFFF)) + +/** Decode frequency. */ +#define VRDE_AUDIO_FMT_SAMPLE_FREQ(a) ((a) & 0xFFFF) +/** Decode number of channels. */ +#define VRDE_AUDIO_FMT_CHANNELS(a) (((a) >> 16) & 0xF) +/** Decode number signess. */ +#define VRDE_AUDIO_FMT_SIGNED(a) (((a) >> 28) & 0x1) +/** Decode number of bits per sample. */ +#define VRDE_AUDIO_FMT_BITS_PER_SAMPLE(a) (((a) >> 20) & 0xFF) +/** Decode number of bytes per sample. */ +#define VRDE_AUDIO_FMT_BYTES_PER_SAMPLE(a) ((VRDE_AUDIO_FMT_BITS_PER_SAMPLE(a) + 7) / 8) + + +/* + * Audio input. + */ + +/* Audio input notifications. */ +#define VRDE_AUDIOIN_BEGIN 1 +#define VRDE_AUDIOIN_DATA 2 +#define VRDE_AUDIOIN_END 3 + +typedef struct VRDEAUDIOINBEGIN +{ + VRDEAUDIOFORMAT fmt; /* Actual format of data, which will be sent in VRDE_AUDIOIN_DATA events. */ +} VRDEAUDIOINBEGIN, *PVRDEAUDIOINBEGIN; + + +/* + * Remote USB protocol. + */ + +/* The initial version 1. */ +#define VRDE_USB_VERSION_1 (1) +/* Version 2: look for VRDE_USB_VERSION_2 comments in the code. */ +#define VRDE_USB_VERSION_2 (2) +/* Version 3: look for VRDE_USB_VERSION_3 comments in the code. */ +#define VRDE_USB_VERSION_3 (3) + +/* The default VRDE server version of Remote USB Protocol. */ +#define VRDE_USB_VERSION VRDE_USB_VERSION_3 + + +/** USB backend operations. */ +#define VRDE_USB_REQ_OPEN (0) +#define VRDE_USB_REQ_CLOSE (1) +#define VRDE_USB_REQ_RESET (2) +#define VRDE_USB_REQ_SET_CONFIG (3) +#define VRDE_USB_REQ_CLAIM_INTERFACE (4) +#define VRDE_USB_REQ_RELEASE_INTERFACE (5) +#define VRDE_USB_REQ_INTERFACE_SETTING (6) +#define VRDE_USB_REQ_QUEUE_URB (7) +#define VRDE_USB_REQ_REAP_URB (8) +#define VRDE_USB_REQ_CLEAR_HALTED_EP (9) +#define VRDE_USB_REQ_CANCEL_URB (10) + +/** USB service operations. */ +#define VRDE_USB_REQ_DEVICE_LIST (11) +#define VRDE_USB_REQ_NEGOTIATE (12) + +/** An operation completion status is a byte. */ +typedef uint8_t VRDEUSBSTATUS; + +/** USB device identifier is an 32 bit value. */ +typedef uint32_t VRDEUSBDEVID; + +/** Status codes. */ +#define VRDE_USB_STATUS_SUCCESS ((VRDEUSBSTATUS)0) +#define VRDE_USB_STATUS_ACCESS_DENIED ((VRDEUSBSTATUS)1) +#define VRDE_USB_STATUS_DEVICE_REMOVED ((VRDEUSBSTATUS)2) + +/* + * Data structures to use with VRDEUSBRequest. + * The *RET* structures always represent the layout of VRDE data. + * The *PARM* structures normally the same as VRDE layout. + * However the VRDE_USB_REQ_QUEUE_URB_PARM has a pointer to + * URB data in place where actual data will be in VRDE layout. + * + * Since replies (*RET*) are asynchronous, the 'success' + * replies are not required for operations which return + * only the status code (VRDEUSBREQRETHDR only): + * VRDE_USB_REQ_OPEN + * VRDE_USB_REQ_RESET + * VRDE_USB_REQ_SET_CONFIG + * VRDE_USB_REQ_CLAIM_INTERFACE + * VRDE_USB_REQ_RELEASE_INTERFACE + * VRDE_USB_REQ_INTERFACE_SETTING + * VRDE_USB_REQ_CLEAR_HALTED_EP + * + */ + +/* VRDE layout has no alignments. */ +#pragma pack(1) +/* Common header for all VRDE USB packets. After the reply hdr follows *PARM* or *RET* data. */ +typedef struct _VRDEUSBPKTHDR +{ + /* Total length of the reply NOT including the 'length' field. */ + uint32_t length; + /* The operation code for which the reply was sent by the client. */ + uint8_t code; +} VRDEUSBPKTHDR; + +/* Common header for all return structures. */ +typedef struct _VRDEUSBREQRETHDR +{ + /* Device status. */ + VRDEUSBSTATUS status; + /* Device id. */ + VRDEUSBDEVID id; +} VRDEUSBREQRETHDR; + + +/* VRDE_USB_REQ_OPEN + */ +typedef struct _VRDE_USB_REQ_OPEN_PARM +{ + uint8_t code; + VRDEUSBDEVID id; +} VRDE_USB_REQ_OPEN_PARM; + +typedef struct _VRDE_USB_REQ_OPEN_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_OPEN_RET; + + +/* VRDE_USB_REQ_CLOSE + */ +typedef struct _VRDE_USB_REQ_CLOSE_PARM +{ + uint8_t code; + VRDEUSBDEVID id; +} VRDE_USB_REQ_CLOSE_PARM; + +/* The close request has no returned data. */ + + +/* VRDE_USB_REQ_RESET + */ +typedef struct _VRDE_USB_REQ_RESET_PARM +{ + uint8_t code; + VRDEUSBDEVID id; +} VRDE_USB_REQ_RESET_PARM; + +typedef struct _VRDE_USB_REQ_RESET_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_RESET_RET; + + +/* VRDE_USB_REQ_SET_CONFIG + */ +typedef struct _VRDE_USB_REQ_SET_CONFIG_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint8_t configuration; +} VRDE_USB_REQ_SET_CONFIG_PARM; + +typedef struct _VRDE_USB_REQ_SET_CONFIG_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_SET_CONFIG_RET; + + +/* VRDE_USB_REQ_CLAIM_INTERFACE + */ +typedef struct _VRDE_USB_REQ_CLAIM_INTERFACE_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint8_t iface; +} VRDE_USB_REQ_CLAIM_INTERFACE_PARM; + +typedef struct _VRDE_USB_REQ_CLAIM_INTERFACE_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_CLAIM_INTERFACE_RET; + + +/* VRDE_USB_REQ_RELEASE_INTERFACE + */ +typedef struct _VRDE_USB_REQ_RELEASE_INTERFACE_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint8_t iface; +} VRDE_USB_REQ_RELEASE_INTERFACE_PARM; + +typedef struct _VRDE_USB_REQ_RELEASE_INTERFACE_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_RELEASE_INTERFACE_RET; + + +/* VRDE_USB_REQ_INTERFACE_SETTING + */ +typedef struct _VRDE_USB_REQ_INTERFACE_SETTING_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint8_t iface; + uint8_t setting; +} VRDE_USB_REQ_INTERFACE_SETTING_PARM; + +typedef struct _VRDE_USB_REQ_INTERFACE_SETTING_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_INTERFACE_SETTING_RET; + + +/* VRDE_USB_REQ_QUEUE_URB + */ + +#define VRDE_USB_TRANSFER_TYPE_CTRL (0) +#define VRDE_USB_TRANSFER_TYPE_ISOC (1) +#define VRDE_USB_TRANSFER_TYPE_BULK (2) +#define VRDE_USB_TRANSFER_TYPE_INTR (3) +#define VRDE_USB_TRANSFER_TYPE_MSG (4) + +#define VRDE_USB_DIRECTION_SETUP (0) +#define VRDE_USB_DIRECTION_IN (1) +#define VRDE_USB_DIRECTION_OUT (2) + +typedef struct _VRDE_USB_REQ_QUEUE_URB_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint32_t handle; /* Distinguishes that particular URB. Later used in CancelURB and returned by ReapURB */ + uint8_t type; + uint8_t ep; + uint8_t direction; + uint32_t urblen; /* Length of the URB. */ + uint32_t datalen; /* Length of the data. */ + void *data; /* In RDP layout the data follow. */ +} VRDE_USB_REQ_QUEUE_URB_PARM; + +/* The queue URB has no explicit return. The reap URB reply will be + * eventually the indirect result. + */ + + +/* VRDE_USB_REQ_REAP_URB + * Notificationg from server to client that server expects an URB + * from any device. + * Only sent if negotiated URB return method is polling. + * Normally, the client will send URBs back as soon as they are ready. + */ +typedef struct _VRDE_USB_REQ_REAP_URB_PARM +{ + uint8_t code; +} VRDE_USB_REQ_REAP_URB_PARM; + + +#define VRDE_USB_XFER_OK (0) +#define VRDE_USB_XFER_STALL (1) +#define VRDE_USB_XFER_DNR (2) +#define VRDE_USB_XFER_CRC (3) +/* VRDE_USB_VERSION_2: New error codes. OHCI Completion Codes. */ +#define VRDE_USB_XFER_BS (4) /* BitStuffing */ +#define VRDE_USB_XFER_DTM (5) /* DataToggleMismatch */ +#define VRDE_USB_XFER_PCF (6) /* PIDCheckFailure */ +#define VRDE_USB_XFER_UPID (7) /* UnexpectedPID */ +#define VRDE_USB_XFER_DO (8) /* DataOverrun */ +#define VRDE_USB_XFER_DU (9) /* DataUnderrun */ +#define VRDE_USB_XFER_BO (10) /* BufferOverrun */ +#define VRDE_USB_XFER_BU (11) /* BufferUnderrun */ +#define VRDE_USB_XFER_ERR (12) /* VBox protocol error. */ + +#define VRDE_USB_REAP_FLAG_CONTINUED (0x0) +#define VRDE_USB_REAP_FLAG_LAST (0x1) +/* VRDE_USB_VERSION_3: Fragmented URBs. */ +#define VRDE_USB_REAP_FLAG_FRAGMENT (0x2) + +#define VRDE_USB_REAP_VALID_FLAGS (VRDE_USB_REAP_FLAG_LAST) +/* VRDE_USB_VERSION_3: Fragmented URBs. */ +#define VRDE_USB_REAP_VALID_FLAGS_3 (VRDE_USB_REAP_FLAG_LAST | VRDE_USB_REAP_FLAG_FRAGMENT) + +typedef struct _VRDEUSBREQREAPURBBODY +{ + VRDEUSBDEVID id; /* From which device the URB arrives. */ + uint8_t flags; /* VRDE_USB_REAP_FLAG_* */ + uint8_t error; /* VRDE_USB_XFER_* */ + uint32_t handle; /* Handle of returned URB. Not 0. */ + uint32_t len; /* Length of data actually transferred. */ + /* 'len' bytes of data follow if direction of this URB was VRDE_USB_DIRECTION_IN. */ +} VRDEUSBREQREAPURBBODY; + +typedef struct _VRDE_USB_REQ_REAP_URB_RET +{ + /* The REAP URB has no header, only completed URBs are returned. */ + VRDEUSBREQREAPURBBODY body; + /* Another body may follow, depending on flags. */ +} VRDE_USB_REQ_REAP_URB_RET; + + +/* VRDE_USB_REQ_CLEAR_HALTED_EP + */ +typedef struct _VRDE_USB_REQ_CLEAR_HALTED_EP_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint8_t ep; +} VRDE_USB_REQ_CLEAR_HALTED_EP_PARM; + +typedef struct _VRDE_USB_REQ_CLEAR_HALTED_EP_RET +{ + VRDEUSBREQRETHDR hdr; +} VRDE_USB_REQ_CLEAR_HALTED_EP_RET; + + +/* VRDE_USB_REQ_CANCEL_URB + */ +typedef struct _VRDE_USB_REQ_CANCEL_URB_PARM +{ + uint8_t code; + VRDEUSBDEVID id; + uint32_t handle; +} VRDE_USB_REQ_CANCEL_URB_PARM; + +/* The cancel URB request has no return. */ + + +/* VRDE_USB_REQ_DEVICE_LIST + * + * Server polls USB devices on client by sending this request + * periodically. Client sends back a list of all devices + * connected to it. Each device is assigned with an identifier, + * that is used to distinguish the particular device. + */ +typedef struct _VRDE_USB_REQ_DEVICE_LIST_PARM +{ + uint8_t code; +} VRDE_USB_REQ_DEVICE_LIST_PARM; + +/* Data is a list of the following variable length structures. */ +typedef struct _VRDEUSBDEVICEDESC +{ + /* Offset of the next structure. 0 if last. */ + uint16_t oNext; + + /* Identifier of the device assigned by client. */ + VRDEUSBDEVID id; + + /** USB version number. */ + uint16_t bcdUSB; + /** Device class. */ + uint8_t bDeviceClass; + /** Device subclass. */ + uint8_t bDeviceSubClass; + /** Device protocol */ + uint8_t bDeviceProtocol; + /** Vendor ID. */ + uint16_t idVendor; + /** Product ID. */ + uint16_t idProduct; + /** Revision, integer part. */ + uint16_t bcdRev; + /** Offset of the UTF8 manufacturer string relative to the structure start. */ + uint16_t oManufacturer; + /** Offset of the UTF8 product string relative to the structure start. */ + uint16_t oProduct; + /** Offset of the UTF8 serial number string relative to the structure start. */ + uint16_t oSerialNumber; + /** Physical USB port the device is connected to. */ + uint16_t idPort; + +} VRDEUSBDEVICEDESC; + +#define VRDE_USBDEVICESPEED_UNKNOWN 0 /* Unknown. */ +#define VRDE_USBDEVICESPEED_LOW 1 /* Low speed (1.5 Mbit/s). */ +#define VRDE_USBDEVICESPEED_FULL 2 /* Full speed (12 Mbit/s). */ +#define VRDE_USBDEVICESPEED_HIGH 3 /* High speed (480 Mbit/s). */ +#define VRDE_USBDEVICESPEED_VARIABLE 4 /* Variable speed - USB 2.5 / wireless. */ +#define VRDE_USBDEVICESPEED_SUPERSPEED 5 /* Super Speed - USB 3.0 */ + +typedef struct _VRDEUSBDEVICEDESCEXT +{ + VRDEUSBDEVICEDESC desc; + + /* Extended info. + */ + + /** The USB device speed: VRDE_USBDEVICESPEED_*. */ + uint16_t u16DeviceSpeed; +} VRDEUSBDEVICEDESCEXT; + +typedef struct _VRDE_USB_REQ_DEVICE_LIST_RET +{ + VRDEUSBDEVICEDESC body; + /* Other devices may follow. + * The list ends with (uint16_t)0, + * which means that an empty list consists of 2 zero bytes. + */ +} VRDE_USB_REQ_DEVICE_LIST_RET; + +typedef struct _VRDE_USB_REQ_DEVICE_LIST_EXT_RET +{ + VRDEUSBDEVICEDESCEXT body; + /* Other devices may follow. + * The list ends with (uint16_t)0, + * which means that an empty list consists of 2 zero bytes. + */ +} VRDE_USB_REQ_DEVICE_LIST_EXT_RET; + +/* The server requests the version of the port the device is attached to. + * The client must use VRDEUSBDEVICEDESCEXT structure. + */ +#define VRDE_USB_SERVER_CAPS_PORT_VERSION 0x0001 + +typedef struct _VRDEUSBREQNEGOTIATEPARM +{ + uint8_t code; + + /* Remote USB Protocol version. */ + /* VRDE_USB_VERSION_3: the 32 bit field is splitted to 16 bit version and 16 bit flags. + * Version 1 and 2 servers therefore have 'flags' == 0. + * Version 3+ servers can send some capabilities in this field, this way it is possible to add + * a new capability without increasing the protocol version. + */ + uint16_t version; + uint16_t flags; /* See VRDE_USB_SERVER_CAPS_* */ + +} VRDEUSBREQNEGOTIATEPARM; + +/* VRDEUSBREQNEGOTIATERET flags. */ +#define VRDE_USB_CAPS_FLAG_ASYNC (0x0) +#define VRDE_USB_CAPS_FLAG_POLL (0x1) +/* VRDE_USB_VERSION_2: New flag. */ +#define VRDE_USB_CAPS2_FLAG_VERSION (0x2) /* The client is negotiating the protocol version. */ +/* VRDE_USB_VERSION_3: New flag. */ +#define VRDE_USB_CAPS3_FLAG_EXT (0x4) /* The client is negotiating the extended flags. + * If this flag is set, then the VRDE_USB_CAPS2_FLAG_VERSION + * must also be set. + */ + + +#define VRDE_USB_CAPS_VALID_FLAGS (VRDE_USB_CAPS_FLAG_POLL) +/* VRDE_USB_VERSION_2: A set of valid flags. */ +#define VRDE_USB_CAPS2_VALID_FLAGS (VRDE_USB_CAPS_FLAG_POLL | VRDE_USB_CAPS2_FLAG_VERSION) +/* VRDE_USB_VERSION_3: A set of valid flags. */ +#define VRDE_USB_CAPS3_VALID_FLAGS (VRDE_USB_CAPS_FLAG_POLL | VRDE_USB_CAPS2_FLAG_VERSION | VRDE_USB_CAPS3_FLAG_EXT) + +typedef struct _VRDEUSBREQNEGOTIATERET +{ + uint8_t flags; +} VRDEUSBREQNEGOTIATERET; + +typedef struct _VRDEUSBREQNEGOTIATERET_2 +{ + uint8_t flags; + uint32_t u32Version; /* This field presents only if the VRDE_USB_CAPS2_FLAG_VERSION flag is set. */ +} VRDEUSBREQNEGOTIATERET_2; + +/* The server requests the version of the port the device is attached to. + * The client must use VRDEUSBDEVICEDESCEXT structure. + */ +#define VRDE_USB_CLIENT_CAPS_PORT_VERSION 0x00000001 + +typedef struct _VRDEUSBREQNEGOTIATERET_3 +{ + uint8_t flags; + uint32_t u32Version; /* This field presents only if the VRDE_USB_CAPS2_FLAG_VERSION flag is set. */ + uint32_t u32Flags; /* This field presents only if both VRDE_USB_CAPS2_FLAG_VERSION and + * VRDE_USB_CAPS2_FLAG_EXT flag are set. + * See VRDE_USB_CLIENT_CAPS_* + */ +} VRDEUSBREQNEGOTIATERET_3; +#pragma pack() + +#define VRDE_CLIPBOARD_FORMAT_NULL (0x0) +#define VRDE_CLIPBOARD_FORMAT_UNICODE_TEXT (0x1) +#define VRDE_CLIPBOARD_FORMAT_BITMAP (0x2) +#define VRDE_CLIPBOARD_FORMAT_HTML (0x4) + +#define VRDE_CLIPBOARD_FUNCTION_FORMAT_ANNOUNCE (0) +#define VRDE_CLIPBOARD_FUNCTION_DATA_READ (1) +#define VRDE_CLIPBOARD_FUNCTION_DATA_WRITE (2) + + +/** Indexes of information values. */ + +/** Whether a client is connected at the moment. + * uint32_t + */ +#define VRDE_QI_ACTIVE (0) + +/** How many times a client connected up to current moment. + * uint32_t + */ +#define VRDE_QI_NUMBER_OF_CLIENTS (1) + +/** When last connection was established. + * int64_t time in milliseconds since 1970-01-01 00:00:00 UTC + */ +#define VRDE_QI_BEGIN_TIME (2) + +/** When last connection was terminated or current time if connection still active. + * int64_t time in milliseconds since 1970-01-01 00:00:00 UTC + */ +#define VRDE_QI_END_TIME (3) + +/** How many bytes were sent in last (current) connection. + * uint64_t + */ +#define VRDE_QI_BYTES_SENT (4) + +/** How many bytes were sent in all connections. + * uint64_t + */ +#define VRDE_QI_BYTES_SENT_TOTAL (5) + +/** How many bytes were received in last (current) connection. + * uint64_t + */ +#define VRDE_QI_BYTES_RECEIVED (6) + +/** How many bytes were received in all connections. + * uint64_t + */ +#define VRDE_QI_BYTES_RECEIVED_TOTAL (7) + +/** Login user name supplied by the client. + * UTF8 nul terminated string. + */ +#define VRDE_QI_USER (8) + +/** Login domain supplied by the client. + * UTF8 nul terminated string. + */ +#define VRDE_QI_DOMAIN (9) + +/** The client name supplied by the client. + * UTF8 nul terminated string. + */ +#define VRDE_QI_CLIENT_NAME (10) + +/** IP address of the client. + * UTF8 nul terminated string. + */ +#define VRDE_QI_CLIENT_IP (11) + +/** The client software version number. + * uint32_t. + */ +#define VRDE_QI_CLIENT_VERSION (12) + +/** Public key exchange method used when connection was established. + * Values: 0 - RDP4 public key exchange scheme. + * 1 - X509 sertificates were sent to client. + * uint32_t. + */ +#define VRDE_QI_ENCRYPTION_STYLE (13) + +/** TCP port where the server listens. + * Values: 0 - VRDE server failed to start. + * -1 - . + * int32_t. + */ +#define VRDE_QI_PORT (14) + + +/** Hints what has been intercepted by the application. */ +#define VRDE_CLIENT_INTERCEPT_AUDIO RT_BIT(0) +#define VRDE_CLIENT_INTERCEPT_USB RT_BIT(1) +#define VRDE_CLIENT_INTERCEPT_CLIPBOARD RT_BIT(2) +#define VRDE_CLIENT_INTERCEPT_AUDIO_INPUT RT_BIT(3) + + +/** The version of the VRDE server interface. */ +#define VRDE_INTERFACE_VERSION_1 (1) +#define VRDE_INTERFACE_VERSION_2 (2) +#define VRDE_INTERFACE_VERSION_3 (3) +#define VRDE_INTERFACE_VERSION_4 (4) + +/** The header that does not change when the interface changes. */ +typedef struct _VRDEINTERFACEHDR +{ + /** The version of the interface. */ + uint64_t u64Version; + + /** The size of the structure. */ + uint64_t u64Size; + +} VRDEINTERFACEHDR; + +/** The VRDE server entry points. Interface version 1. */ +typedef struct _VRDEENTRYPOINTS_1 +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Destroy the server instance. + * + * @param hServer The server instance handle. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(void, VRDEDestroy,(HVRDESERVER hServer)); + + /** The server should start to accept clients connections. + * + * @param hServer The server instance handle. + * @param fEnable Whether to enable or disable client connections. + * When is false, all existing clients are disconnected. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEEnableConnections,(HVRDESERVER hServer, + bool fEnable)); + + /** The server should disconnect the client. + * + * @param hServer The server instance handle. + * @param u32ClientId The client identifier. + * @param fReconnect Whether to send a "REDIRECT to the same server" packet to the + * client before disconnecting. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(void, VRDEDisconnect,(HVRDESERVER hServer, + uint32_t u32ClientId, + bool fReconnect)); + + /** + * Inform the server that the display was resized. + * The server will query information about display + * from the application via callbacks. + * + * @param hServer Handle of VRDE server instance. + */ + DECLR3CALLBACKMEMBER(void, VRDEResize,(HVRDESERVER hServer)); + + /** + * Send a update. + * + * Note: the server must access the framebuffer bitmap only when VRDEUpdate is called. + * If the have to access the bitmap later or from another thread, then + * it must used an intermediate buffer and copy the framebuffer data to the + * intermediate buffer in VRDEUpdate. + * + * @param hServer Handle of VRDE server instance. + * @param uScreenId The screen index. + * @param pvUpdate Pointer to VRDEOrders.h::VRDEORDERHDR structure with extra data. + * @param cbUpdate Size of the update data. + */ + DECLR3CALLBACKMEMBER(void, VRDEUpdate,(HVRDESERVER hServer, + unsigned uScreenId, + void *pvUpdate, + uint32_t cbUpdate)); + + /** + * Set the mouse pointer shape. + * + * @param hServer Handle of VRDE server instance. + * @param pPointer The pointer shape information. + */ + DECLR3CALLBACKMEMBER(void, VRDEColorPointer,(HVRDESERVER hServer, + const VRDECOLORPOINTER *pPointer)); + + /** + * Hide the mouse pointer. + * + * @param hServer Handle of VRDE server instance. + */ + DECLR3CALLBACKMEMBER(void, VRDEHidePointer,(HVRDESERVER hServer)); + + /** + * Queues the samples to be sent to clients. + * + * @param hServer Handle of VRDE server instance. + * @param pvSamples Address of samples to be sent. + * @param cSamples Number of samples. + * @param format Encoded audio format for these samples. + * + * @note Initialized to NULL when the application audio callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEAudioSamples,(HVRDESERVER hServer, + const void *pvSamples, + uint32_t cSamples, + VRDEAUDIOFORMAT format)); + + /** + * Sets the sound volume on clients. + * + * @param hServer Handle of VRDE server instance. + * @param left 0..0xFFFF volume level for left channel. + * @param right 0..0xFFFF volume level for right channel. + * + * @note Initialized to NULL when the application audio callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEAudioVolume,(HVRDESERVER hServer, + uint16_t u16Left, + uint16_t u16Right)); + + /** + * Sends a USB request. + * + * @param hServer Handle of VRDE server instance. + * @param u32ClientId An identifier that allows the server to find the corresponding client. + * The identifier is always passed by the server as a parameter + * of the FNVRDEUSBCALLBACK. Note that the value is the same as + * in the VRDESERVERCALLBACK functions. + * @param pvParm Function specific parameters buffer. + * @param cbParm Size of the buffer. + * + * @note Initialized to NULL when the application USB callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEUSBRequest,(HVRDESERVER hServer, + uint32_t u32ClientId, + void *pvParm, + uint32_t cbParm)); + + /** + * Called by the application when (VRDE_CLIPBOARD_FUNCTION_*): + * - (0) guest announces available clipboard formats; + * - (1) guest requests clipboard data; + * - (2) guest responds to the client's request for clipboard data. + * + * @param hServer The VRDE server handle. + * @param u32Function The cause of the call. + * @param u32Format Bitmask of announced formats or the format of data. + * @param pvData Points to: (1) buffer to be filled with clients data; + * (2) data from the host. + * @param cbData Size of 'pvData' buffer in bytes. + * @param pcbActualRead Size of the copied data in bytes. + * + * @note Initialized to NULL when the application clipboard callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEClipboard,(HVRDESERVER hServer, + uint32_t u32Function, + uint32_t u32Format, + void *pvData, + uint32_t cbData, + uint32_t *pcbActualRead)); + + /** + * Query various information from the VRDE server. + * + * @param hServer The VRDE server handle. + * @param index VRDE_QI_* identifier of information to be returned. + * @param pvBuffer Address of memory buffer to which the information must be written. + * @param cbBuffer Size of the memory buffer in bytes. + * @param pcbOut Size in bytes of returned information value. + * + * @remark The caller must check the *pcbOut. 0 there means no information was returned. + * A value greater than cbBuffer means that information is too big to fit in the + * buffer, in that case no information was placed to the buffer. + */ + DECLR3CALLBACKMEMBER(void, VRDEQueryInfo,(HVRDESERVER hServer, + uint32_t index, + void *pvBuffer, + uint32_t cbBuffer, + uint32_t *pcbOut)); +} VRDEENTRYPOINTS_1; + +/** The VRDE server entry points. Interface version 2. + * A new entry point VRDERedirect has been added relative to version 1. + */ +typedef struct _VRDEENTRYPOINTS_2 +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Destroy the server instance. + * + * @param hServer The server instance handle. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(void, VRDEDestroy,(HVRDESERVER hServer)); + + /** The server should start to accept clients connections. + * + * @param hServer The server instance handle. + * @param fEnable Whether to enable or disable client connections. + * When is false, all existing clients are disconnected. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEEnableConnections,(HVRDESERVER hServer, + bool fEnable)); + + /** The server should disconnect the client. + * + * @param hServer The server instance handle. + * @param u32ClientId The client identifier. + * @param fReconnect Whether to send a "REDIRECT to the same server" packet to the + * client before disconnecting. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(void, VRDEDisconnect,(HVRDESERVER hServer, + uint32_t u32ClientId, + bool fReconnect)); + + /** + * Inform the server that the display was resized. + * The server will query information about display + * from the application via callbacks. + * + * @param hServer Handle of VRDE server instance. + */ + DECLR3CALLBACKMEMBER(void, VRDEResize,(HVRDESERVER hServer)); + + /** + * Send a update. + * + * Note: the server must access the framebuffer bitmap only when VRDEUpdate is called. + * If the have to access the bitmap later or from another thread, then + * it must used an intermediate buffer and copy the framebuffer data to the + * intermediate buffer in VRDEUpdate. + * + * @param hServer Handle of VRDE server instance. + * @param uScreenId The screen index. + * @param pvUpdate Pointer to VRDEOrders.h::VRDEORDERHDR structure with extra data. + * @param cbUpdate Size of the update data. + */ + DECLR3CALLBACKMEMBER(void, VRDEUpdate,(HVRDESERVER hServer, + unsigned uScreenId, + void *pvUpdate, + uint32_t cbUpdate)); + + /** + * Set the mouse pointer shape. + * + * @param hServer Handle of VRDE server instance. + * @param pPointer The pointer shape information. + */ + DECLR3CALLBACKMEMBER(void, VRDEColorPointer,(HVRDESERVER hServer, + const VRDECOLORPOINTER *pPointer)); + + /** + * Hide the mouse pointer. + * + * @param hServer Handle of VRDE server instance. + */ + DECLR3CALLBACKMEMBER(void, VRDEHidePointer,(HVRDESERVER hServer)); + + /** + * Queues the samples to be sent to clients. + * + * @param hServer Handle of VRDE server instance. + * @param pvSamples Address of samples to be sent. + * @param cSamples Number of samples. + * @param format Encoded audio format for these samples. + * + * @note Initialized to NULL when the application audio callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEAudioSamples,(HVRDESERVER hServer, + const void *pvSamples, + uint32_t cSamples, + VRDEAUDIOFORMAT format)); + + /** + * Sets the sound volume on clients. + * + * @param hServer Handle of VRDE server instance. + * @param left 0..0xFFFF volume level for left channel. + * @param right 0..0xFFFF volume level for right channel. + * + * @note Initialized to NULL when the application audio callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEAudioVolume,(HVRDESERVER hServer, + uint16_t u16Left, + uint16_t u16Right)); + + /** + * Sends a USB request. + * + * @param hServer Handle of VRDE server instance. + * @param u32ClientId An identifier that allows the server to find the corresponding client. + * The identifier is always passed by the server as a parameter + * of the FNVRDEUSBCALLBACK. Note that the value is the same as + * in the VRDESERVERCALLBACK functions. + * @param pvParm Function specific parameters buffer. + * @param cbParm Size of the buffer. + * + * @note Initialized to NULL when the application USB callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEUSBRequest,(HVRDESERVER hServer, + uint32_t u32ClientId, + void *pvParm, + uint32_t cbParm)); + + /** + * Called by the application when (VRDE_CLIPBOARD_FUNCTION_*): + * - (0) guest announces available clipboard formats; + * - (1) guest requests clipboard data; + * - (2) guest responds to the client's request for clipboard data. + * + * @param hServer The VRDE server handle. + * @param u32Function The cause of the call. + * @param u32Format Bitmask of announced formats or the format of data. + * @param pvData Points to: (1) buffer to be filled with clients data; + * (2) data from the host. + * @param cbData Size of 'pvData' buffer in bytes. + * @param pcbActualRead Size of the copied data in bytes. + * + * @note Initialized to NULL when the application clipboard callbacks are NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEClipboard,(HVRDESERVER hServer, + uint32_t u32Function, + uint32_t u32Format, + void *pvData, + uint32_t cbData, + uint32_t *pcbActualRead)); + + /** + * Query various information from the VRDE server. + * + * @param hServer The VRDE server handle. + * @param index VRDE_QI_* identifier of information to be returned. + * @param pvBuffer Address of memory buffer to which the information must be written. + * @param cbBuffer Size of the memory buffer in bytes. + * @param pcbOut Size in bytes of returned information value. + * + * @remark The caller must check the *pcbOut. 0 there means no information was returned. + * A value greater than cbBuffer means that information is too big to fit in the + * buffer, in that case no information was placed to the buffer. + */ + DECLR3CALLBACKMEMBER(void, VRDEQueryInfo,(HVRDESERVER hServer, + uint32_t index, + void *pvBuffer, + uint32_t cbBuffer, + uint32_t *pcbOut)); + + /** + * The server should redirect the client to the specified server. + * + * @param hServer The server instance handle. + * @param u32ClientId The client identifier. + * @param pszServer The server to redirect the client to. + * @param pszUser The username to use for the redirection. + * Can be NULL. + * @param pszDomain The domain. Can be NULL. + * @param pszPassword The password. Can be NULL. + * @param u32SessionId The ID of the session to redirect to. + * @param pszCookie The routing token used by a load balancer to + * route the redirection. Can be NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDERedirect,(HVRDESERVER hServer, + uint32_t u32ClientId, + const char *pszServer, + const char *pszUser, + const char *pszDomain, + const char *pszPassword, + uint32_t u32SessionId, + const char *pszCookie)); +} VRDEENTRYPOINTS_2; + +/** The VRDE server entry points. Interface version 3. + * New entry points VRDEAudioInOpen and VRDEAudioInClose has been added relative to version 2. + */ +typedef struct _VRDEENTRYPOINTS_3 +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* + * Same as version 2. See comment in VRDEENTRYPOINTS_2. + */ + + DECLR3CALLBACKMEMBER(void, VRDEDestroy,(HVRDESERVER hServer)); + + DECLR3CALLBACKMEMBER(int, VRDEEnableConnections,(HVRDESERVER hServer, + bool fEnable)); + + DECLR3CALLBACKMEMBER(void, VRDEDisconnect,(HVRDESERVER hServer, + uint32_t u32ClientId, + bool fReconnect)); + + DECLR3CALLBACKMEMBER(void, VRDEResize,(HVRDESERVER hServer)); + + DECLR3CALLBACKMEMBER(void, VRDEUpdate,(HVRDESERVER hServer, + unsigned uScreenId, + void *pvUpdate, + uint32_t cbUpdate)); + + DECLR3CALLBACKMEMBER(void, VRDEColorPointer,(HVRDESERVER hServer, + const VRDECOLORPOINTER *pPointer)); + + DECLR3CALLBACKMEMBER(void, VRDEHidePointer,(HVRDESERVER hServer)); + + DECLR3CALLBACKMEMBER(void, VRDEAudioSamples,(HVRDESERVER hServer, + const void *pvSamples, + uint32_t cSamples, + VRDEAUDIOFORMAT format)); + + DECLR3CALLBACKMEMBER(void, VRDEAudioVolume,(HVRDESERVER hServer, + uint16_t u16Left, + uint16_t u16Right)); + + DECLR3CALLBACKMEMBER(void, VRDEUSBRequest,(HVRDESERVER hServer, + uint32_t u32ClientId, + void *pvParm, + uint32_t cbParm)); + + DECLR3CALLBACKMEMBER(void, VRDEClipboard,(HVRDESERVER hServer, + uint32_t u32Function, + uint32_t u32Format, + void *pvData, + uint32_t cbData, + uint32_t *pcbActualRead)); + + DECLR3CALLBACKMEMBER(void, VRDEQueryInfo,(HVRDESERVER hServer, + uint32_t index, + void *pvBuffer, + uint32_t cbBuffer, + uint32_t *pcbOut)); + + DECLR3CALLBACKMEMBER(void, VRDERedirect,(HVRDESERVER hServer, + uint32_t u32ClientId, + const char *pszServer, + const char *pszUser, + const char *pszDomain, + const char *pszPassword, + uint32_t u32SessionId, + const char *pszCookie)); + + /* + * New for version 3. + */ + + /** + * Audio input open request. + * + * @param hServer Handle of VRDE server instance. + * @param pvCtx To be used in VRDECallbackAudioIn. + * @param u32ClientId An identifier that allows the server to find the corresponding client. + * @param audioFormat Preferred format of audio data. + * @param u32SamplesPerBlock Preferred number of samples in one block of audio input data. + * + * @note Initialized to NULL when the VRDECallbackAudioIn callback is NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEAudioInOpen,(HVRDESERVER hServer, + void *pvCtx, + uint32_t u32ClientId, + VRDEAUDIOFORMAT audioFormat, + uint32_t u32SamplesPerBlock)); + + /** + * Audio input close request. + * + * @param hServer Handle of VRDE server instance. + * @param u32ClientId An identifier that allows the server to find the corresponding client. + * + * @note Initialized to NULL when the VRDECallbackAudioIn callback is NULL. + */ + DECLR3CALLBACKMEMBER(void, VRDEAudioInClose,(HVRDESERVER hServer, + uint32_t u32ClientId)); +} VRDEENTRYPOINTS_3; + + +/* Indexes for VRDECallbackProperty. + * *_QP_* queries a property. + * *_SP_* sets a property. + */ +#define VRDE_QP_NETWORK_PORT (1) /* Obsolete. Use VRDE_QP_NETWORK_PORT_RANGE instead. */ +#define VRDE_QP_NETWORK_ADDRESS (2) /* UTF8 string. Host network interface IP address to bind to. */ +#define VRDE_QP_NUMBER_MONITORS (3) /* 32 bit. Number of monitors in the VM. */ +#define VRDE_QP_NETWORK_PORT_RANGE (4) /* UTF8 string. List of ports. The server must bind to one of + * free ports from the list. Example: "3000,3010-3012,4000", + * which tells the server to bind to either of ports: + * 3000, 3010, 3011, 3012, 4000. + */ +#define VRDE_QP_VIDEO_CHANNEL (5) +#define VRDE_QP_VIDEO_CHANNEL_QUALITY (6) +#define VRDE_QP_VIDEO_CHANNEL_SUNFLSH (7) +#define VRDE_QP_FEATURE (8) /* VRDEFEATURE structure. Generic interface to query named VRDE properties. */ +#define VRDE_QP_UNIX_SOCKET_PATH (9) /* Path to a UNIX Socket for incoming connections */ + +#define VRDE_SP_BASE 0x1000 +#define VRDE_SP_NETWORK_BIND_PORT (VRDE_SP_BASE + 1) /* 32 bit. The port number actually used by the server. + * If VRDECreateServer fails, it should set the port to 0. + * If VRDECreateServer succeeds, then the port must be set + * in VRDEEnableConnections to the actually used value. + * VRDEDestroy must set the port to 0xFFFFFFFF. + */ +#define VRDE_SP_CLIENT_STATUS (VRDE_SP_BASE + 2) /* UTF8 string. The change of the generic client status: + * "ATTACH" - the client is attached; + * "DETACH" - the client is detached; + * "NAME=..." - the client name changes. + * Can be used for other notifications. + */ + +#pragma pack(1) +/* VRDE_QP_FEATURE data. */ +typedef struct _VRDEFEATURE +{ + uint32_t u32ClientId; + char achInfo[1]; /* UTF8 property input name and output value. */ +} VRDEFEATURE; + +/* VRDE_SP_CLIENT_STATUS data. */ +typedef struct VRDECLIENTSTATUS +{ + uint32_t u32ClientId; + uint32_t cbStatus; + char achStatus[1]; /* UTF8 status string. */ +} VRDECLIENTSTATUS; + +/* A framebuffer description. */ +typedef struct _VRDEFRAMEBUFFERINFO +{ + const uint8_t *pu8Bits; + int xOrigin; + int yOrigin; + unsigned cWidth; + unsigned cHeight; + unsigned cBitsPerPixel; + unsigned cbLine; +} VRDEFRAMEBUFFERINFO; + +#define VRDE_INPUT_SCANCODE 0 +#define VRDE_INPUT_POINT 1 +#define VRDE_INPUT_CAD 2 +#define VRDE_INPUT_RESET 3 +#define VRDE_INPUT_SYNCH 4 + +typedef struct _VRDEINPUTSCANCODE +{ + unsigned uScancode; +} VRDEINPUTSCANCODE; + +#define VRDE_INPUT_POINT_BUTTON1 0x01 +#define VRDE_INPUT_POINT_BUTTON2 0x02 +#define VRDE_INPUT_POINT_BUTTON3 0x04 +#define VRDE_INPUT_POINT_WHEEL_UP 0x08 +#define VRDE_INPUT_POINT_WHEEL_DOWN 0x10 + +typedef struct _VRDEINPUTPOINT +{ + int x; + int y; + unsigned uButtons; +} VRDEINPUTPOINT; + +#define VRDE_INPUT_SYNCH_SCROLL 0x01 +#define VRDE_INPUT_SYNCH_NUMLOCK 0x02 +#define VRDE_INPUT_SYNCH_CAPITAL 0x04 + +typedef struct _VRDEINPUTSYNCH +{ + unsigned uLockStatus; +} VRDEINPUTSYNCH; +#pragma pack() + +/** The VRDE server callbacks. Interface version 1. */ +typedef struct _VRDECALLBACKS_1 +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** + * Query or set various information, on how the VRDE server operates, from or to the application. + * Queries for properties will always return success, and if the key is not known or has no + * value associated with it an empty string is returned. + * + * + * @param pvCallback The callback specific pointer. + * @param index VRDE_[Q|S]P_* identifier of information to be returned or set. + * @param pvBuffer Address of memory buffer to which the information must be written or read. + * @param cbBuffer Size of the memory buffer in bytes. + * @param pcbOut Size in bytes of returned information value. + * + * @return IPRT status code. VINF_BUFFER_OVERFLOW if the buffer is too small for the value. + */ + DECLR3CALLBACKMEMBER(int, VRDECallbackProperty,(void *pvCallback, + uint32_t index, + void *pvBuffer, + uint32_t cbBuffer, + uint32_t *pcbOut)); + + /* A client is logging in, the application must decide whether + * to let to connect the client. The server will drop the connection, + * when an error code is returned by the callback. + * + * @param pvCallback The callback specific pointer. + * @param u32ClientId An unique client identifier generated by the server. + * @param pszUser The username. + * @param pszPassword The password. + * @param pszDomain The domain. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDECallbackClientLogon,(void *pvCallback, + uint32_t u32ClientId, + const char *pszUser, + const char *pszPassword, + const char *pszDomain)); + + /* The client has been successfully connected. That is logon was successful and the + * remote desktop protocol connection completely established. + * + * @param pvCallback The callback specific pointer. + * @param u32ClientId An unique client identifier generated by the server. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackClientConnect,(void *pvCallback, + uint32_t u32ClientId)); + + /* The client has been disconnected. + * + * @param pvCallback The callback specific pointer. + * @param u32ClientId An unique client identifier generated by the server. + * @param fu32Intercepted What was intercepted by the client (VRDE_CLIENT_INTERCEPT_*). + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackClientDisconnect,(void *pvCallback, + uint32_t u32ClientId, + uint32_t fu32Intercepted)); + /* The client supports one of RDP channels. + * + * @param pvCallback The callback specific pointer. + * @param u32ClientId An unique client identifier generated by the server. + * @param fu32Intercept What the client wants to intercept. One of VRDE_CLIENT_INTERCEPT_* flags. + * @param ppvIntercept The value to be passed to the channel specific callback. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDECallbackIntercept,(void *pvCallback, + uint32_t u32ClientId, + uint32_t fu32Intercept, + void **ppvIntercept)); + + /** + * Called by the server when a reply is received from a client. + * + * @param pvCallback The callback specific pointer. + * @param ppvIntercept The value returned by VRDECallbackIntercept for the VRDE_CLIENT_INTERCEPT_USB. + * @param u32ClientId Identifies the client that sent the reply. + * @param u8Code The operation code VRDE_USB_REQ_*. + * @param pvRet Points to data received from the client. + * @param cbRet Size of the data in bytes. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDECallbackUSB,(void *pvCallback, + void *pvIntercept, + uint32_t u32ClientId, + uint8_t u8Code, + const void *pvRet, + uint32_t cbRet)); + + /** + * Called by the server when (VRDE_CLIPBOARD_FUNCTION_*): + * - (0) client announces available clipboard formats; + * - (1) client requests clipboard data. + * + * @param pvCallback The callback specific pointer. + * @param ppvIntercept The value returned by VRDECallbackIntercept for the VRDE_CLIENT_INTERCEPT_CLIPBOARD. + * @param u32ClientId Identifies the RDP client that sent the reply. + * @param u32Function The cause of the callback. + * @param u32Format Bitmask of reported formats or the format of received data. + * @param pvData Reserved. + * @param cbData Reserved. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDECallbackClipboard,(void *pvCallback, + void *pvIntercept, + uint32_t u32ClientId, + uint32_t u32Function, + uint32_t u32Format, + const void *pvData, + uint32_t cbData)); + + /* The framebuffer information is queried. + * + * @param pvCallback The callback specific pointer. + * @param uScreenId The framebuffer index. + * @param pInfo The information structure to ber filled. + * + * @return Whether the framebuffer is available. + */ + DECLR3CALLBACKMEMBER(bool, VRDECallbackFramebufferQuery,(void *pvCallback, + unsigned uScreenId, + VRDEFRAMEBUFFERINFO *pInfo)); + + /* Request the exclusive access to the framebuffer bitmap. + * Currently not used because VirtualBox makes sure that the framebuffer is available + * when VRDEUpdate is called. + * + * @param pvCallback The callback specific pointer. + * @param uScreenId The framebuffer index. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackFramebufferLock,(void *pvCallback, + unsigned uScreenId)); + + /* Release the exclusive access to the framebuffer bitmap. + * Currently not used because VirtualBox makes sure that the framebuffer is available + * when VRDEUpdate is called. + * + * @param pvCallback The callback specific pointer. + * @param uScreenId The framebuffer index. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackFramebufferUnlock,(void *pvCallback, + unsigned uScreenId)); + + /* Input from the client. + * + * @param pvCallback The callback specific pointer. + * @param pvInput The input information. + * @param cbInput The size of the input information. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackInput,(void *pvCallback, + int type, + const void *pvInput, + unsigned cbInput)); + + /* Video mode hint from the client. + * + * @param pvCallback The callback specific pointer. + * @param cWidth Requested width. + * @param cHeight Requested height. + * @param cBitsPerPixel Requested color depth. + * @param uScreenId The framebuffer index. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackVideoModeHint,(void *pvCallback, + unsigned cWidth, + unsigned cHeight, + unsigned cBitsPerPixel, + unsigned uScreenId)); + +} VRDECALLBACKS_1; + +/* Callbacks are the same for the version 1 and version 2 interfaces. */ +typedef VRDECALLBACKS_1 VRDECALLBACKS_2; + +/** The VRDE server callbacks. Interface version 3. */ +typedef struct _VRDECALLBACKS_3 +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* + * Same as in version 1 and 2. See comment in VRDECALLBACKS_1. + */ + DECLR3CALLBACKMEMBER(int, VRDECallbackProperty,(void *pvCallback, + uint32_t index, + void *pvBuffer, + uint32_t cbBuffer, + uint32_t *pcbOut)); + + DECLR3CALLBACKMEMBER(int, VRDECallbackClientLogon,(void *pvCallback, + uint32_t u32ClientId, + const char *pszUser, + const char *pszPassword, + const char *pszDomain)); + + DECLR3CALLBACKMEMBER(void, VRDECallbackClientConnect,(void *pvCallback, + uint32_t u32ClientId)); + + DECLR3CALLBACKMEMBER(void, VRDECallbackClientDisconnect,(void *pvCallback, + uint32_t u32ClientId, + uint32_t fu32Intercepted)); + DECLR3CALLBACKMEMBER(int, VRDECallbackIntercept,(void *pvCallback, + uint32_t u32ClientId, + uint32_t fu32Intercept, + void **ppvIntercept)); + + DECLR3CALLBACKMEMBER(int, VRDECallbackUSB,(void *pvCallback, + void *pvIntercept, + uint32_t u32ClientId, + uint8_t u8Code, + const void *pvRet, + uint32_t cbRet)); + + DECLR3CALLBACKMEMBER(int, VRDECallbackClipboard,(void *pvCallback, + void *pvIntercept, + uint32_t u32ClientId, + uint32_t u32Function, + uint32_t u32Format, + const void *pvData, + uint32_t cbData)); + + DECLR3CALLBACKMEMBER(bool, VRDECallbackFramebufferQuery,(void *pvCallback, + unsigned uScreenId, + VRDEFRAMEBUFFERINFO *pInfo)); + + DECLR3CALLBACKMEMBER(void, VRDECallbackFramebufferLock,(void *pvCallback, + unsigned uScreenId)); + + DECLR3CALLBACKMEMBER(void, VRDECallbackFramebufferUnlock,(void *pvCallback, + unsigned uScreenId)); + + DECLR3CALLBACKMEMBER(void, VRDECallbackInput,(void *pvCallback, + int type, + const void *pvInput, + unsigned cbInput)); + + DECLR3CALLBACKMEMBER(void, VRDECallbackVideoModeHint,(void *pvCallback, + unsigned cWidth, + unsigned cHeight, + unsigned cBitsPerPixel, + unsigned uScreenId)); + + /* + * New for version 3. + */ + + /** + * Called by the server when something happens with audio input. + * + * @param pvCallback The callback specific pointer. + * @param pvCtx The value passed in VRDEAudioInOpen. + * @param u32ClientId Identifies the client that sent the reply. + * @param u32Event The event code VRDE_AUDIOIN_*. + * @param pvData Points to data received from the client. + * @param cbData Size of the data in bytes. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackAudioIn,(void *pvCallback, + void *pvCtx, + uint32_t u32ClientId, + uint32_t u32Event, + const void *pvData, + uint32_t cbData)); +} VRDECALLBACKS_3; + +/** The VRDE server entry points. Interface version 4. + * New entry point VRDEGetInterface has been added relative to version 3. + */ +typedef struct _VRDEENTRYPOINTS_4 +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* + * Same as version 3. See comment in VRDEENTRYPOINTS_3. + */ + + DECLR3CALLBACKMEMBER(void, VRDEDestroy,(HVRDESERVER hServer)); + DECLR3CALLBACKMEMBER(int, VRDEEnableConnections,(HVRDESERVER hServer, bool fEnable)); + DECLR3CALLBACKMEMBER(void, VRDEDisconnect,(HVRDESERVER hServer, uint32_t u32ClientId, bool fReconnect)); + DECLR3CALLBACKMEMBER(void, VRDEResize,(HVRDESERVER hServer)); + DECLR3CALLBACKMEMBER(void, VRDEUpdate,(HVRDESERVER hServer, unsigned uScreenId, void *pvUpdate, + uint32_t cbUpdate)); + DECLR3CALLBACKMEMBER(void, VRDEColorPointer,(HVRDESERVER hServer, const VRDECOLORPOINTER *pPointer)); + DECLR3CALLBACKMEMBER(void, VRDEHidePointer,(HVRDESERVER hServer)); + DECLR3CALLBACKMEMBER(void, VRDEAudioSamples,(HVRDESERVER hServer, const void *pvSamples, uint32_t cSamples, + VRDEAUDIOFORMAT format)); + DECLR3CALLBACKMEMBER(void, VRDEAudioVolume,(HVRDESERVER hServer, uint16_t u16Left, uint16_t u16Right)); + DECLR3CALLBACKMEMBER(void, VRDEUSBRequest,(HVRDESERVER hServer, uint32_t u32ClientId, void *pvParm, + uint32_t cbParm)); + DECLR3CALLBACKMEMBER(void, VRDEClipboard,(HVRDESERVER hServer, uint32_t u32Function, uint32_t u32Format, + void *pvData, uint32_t cbData, uint32_t *pcbActualRead)); + DECLR3CALLBACKMEMBER(void, VRDEQueryInfo,(HVRDESERVER hServer, uint32_t index, void *pvBuffer, uint32_t cbBuffer, + uint32_t *pcbOut)); + DECLR3CALLBACKMEMBER(void, VRDERedirect,(HVRDESERVER hServer, uint32_t u32ClientId, const char *pszServer, + const char *pszUser, const char *pszDomain, const char *pszPassword, + uint32_t u32SessionId, const char *pszCookie)); + DECLR3CALLBACKMEMBER(void, VRDEAudioInOpen,(HVRDESERVER hServer, void *pvCtx, uint32_t u32ClientId, + VRDEAUDIOFORMAT audioFormat, uint32_t u32SamplesPerBlock)); + DECLR3CALLBACKMEMBER(void, VRDEAudioInClose,(HVRDESERVER hServer, uint32_t u32ClientId)); + + /** + * Generic interface query. An interface is a set of entry points and callbacks. + * It is not a reference counted interface. + * + * @param hServer Handle of VRDE server instance. + * @param pszId String identifier of the interface, like uuid. + * @param pInterface The interface structure to be initialized by the VRDE server. + * Only VRDEINTERFACEHDR is initialized by the caller. + * @param pCallbacks Callbacks required by the interface. The server makes a local copy. + * VRDEINTERFACEHDR version must correspond to the requested interface version. + * @param pvContext The context to be used in callbacks. + */ + + DECLR3CALLBACKMEMBER(int, VRDEGetInterface, (HVRDESERVER hServer, + const char *pszId, + VRDEINTERFACEHDR *pInterface, + const VRDEINTERFACEHDR *pCallbacks, + void *pvContext)); +} VRDEENTRYPOINTS_4; + +/* Callbacks are the same for the version 3 and version 4 interfaces. */ +typedef VRDECALLBACKS_3 VRDECALLBACKS_4; + +/** + * Create a new VRDE server instance. The instance is fully functional but refuses + * client connections until the entry point VRDEEnableConnections is called by the application. + * + * The caller prepares the VRDECALLBACKS_* structure. The header.u64Version field of the + * structure must be initialized with the version of the interface to use. + * The server will return pointer to VRDEENTRYPOINTS_* table in *ppEntryPoints + * to match the requested interface. + * That is if pCallbacks->header.u64Version == VRDE_INTERFACE_VERSION_1, then the server + * expects pCallbacks to point to VRDECALLBACKS_1 and will return a pointer to VRDEENTRYPOINTS_1. + * + * @param pCallback Pointer to the application callbacks which let the server to fetch + * the configuration data and to access the desktop. + * @param pvCallback The callback specific pointer to be passed back to the application. + * @param ppEntryPoints Where to store the pointer to the VRDE entry points structure. + * @param phServer Pointer to the created server instance handle. + * + * @return IPRT status code. + */ +DECLEXPORT(int) VRDECreateServer (const VRDEINTERFACEHDR *pCallbacks, + void *pvCallback, + VRDEINTERFACEHDR **ppEntryPoints, + HVRDESERVER *phServer); + +typedef DECLCALLBACKTYPE(int, FNVRDECREATESERVER,(const VRDEINTERFACEHDR *pCallbacks, + void *pvCallback, + VRDEINTERFACEHDR **ppEntryPoints, + HVRDESERVER *phServer)); +typedef FNVRDECREATESERVER *PFNVRDECREATESERVER; + +/** + * List of names of the VRDE properties, which are recognized by the VRDE. + * + * For example VRDESupportedProperties should return gapszProperties declared as: + * + * static const char * const gapszProperties[] = + * { + * "TCP/Ports", + * "TCP/Address", + * NULL + * }; + * + * @returns pointer to array of pointers to name strings (UTF8). + */ +DECLEXPORT(const char * const *) VRDESupportedProperties (void); + +typedef DECLCALLBACKTYPE(const char * const *, FNVRDESUPPORTEDPROPERTIES,(void)); +typedef FNVRDESUPPORTEDPROPERTIES *PFNVRDESUPPORTEDPROPERTIES; + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDE_h */ diff --git a/include/VBox/RemoteDesktop/VRDEImage.h b/include/VBox/RemoteDesktop/VRDEImage.h new file mode 100644 index 00000000..54cd674e --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDEImage.h @@ -0,0 +1,256 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - Image updates interface. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDEImage_h +#define VBOX_INCLUDED_RemoteDesktop_VRDEImage_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* + * Generic interface for external image updates with a clipping region to be sent + * to the client. + * + * Async callbacks are used for reporting errors, providing feedback, etc. + */ + +#define VRDE_IMAGE_INTERFACE_NAME "IMAGE" + +#ifdef __cplusplus +class VRDEImage; +typedef class VRDEImage *HVRDEIMAGE; +#else +struct VRDEImage; +typedef struct VRDEImage *HVRDEIMAGE; +#endif /* __cplusplus */ + +/* + * Format description structures for VRDEImageHandleCreate. + */ +typedef struct VRDEIMAGEFORMATBITMAP +{ + uint32_t u32BytesPerPixel; /** @todo impl */ +} VRDEIMAGEFORMATBITMAP; + +typedef struct VRDEIMAGEBITMAP +{ + uint32_t cWidth; /* The width of the bitmap in pixels. */ + uint32_t cHeight; /* The height of the bitmap in pixels. */ + const void *pvData; /* Address of pixel buffer. */ + uint32_t cbData; /* Size of pixel buffer. */ + const void *pvScanLine0; /* Address of first scanline. */ + int32_t iScanDelta; /* Difference between two scanlines. */ +} VRDEIMAGEBITMAP; + +/* + * Image update handle creation flags. + */ +#define VRDE_IMAGE_F_CREATE_DEFAULT 0x00000000 +#define VRDE_IMAGE_F_CREATE_CONTENT_3D 0x00000001 /* Input image data is a rendered 3d scene. */ +#define VRDE_IMAGE_F_CREATE_CONTENT_VIDEO 0x00000002 /* Input image data is a sequence of video frames. */ +#define VRDE_IMAGE_F_CREATE_WINDOW 0x00000004 /* pRect parameter is the image update area. */ + +/* + * Completion flags for image update handle creation. + */ +#define VRDE_IMAGE_F_COMPLETE_DEFAULT 0x00000000 /* The handle has been created. */ +#define VRDE_IMAGE_F_COMPLETE_ASYNC 0x00000001 /* The server will call VRDEImageCbNotify when the handle is ready. */ + +/* + * Supported input image formats. + * + * The identifiers are arbitrary and new formats can be introduced later. + * + */ +#define VRDE_IMAGE_FMT_ID_BITMAP_BGRA8 "BITMAP_BGRA8.07e46a64-e93e-41d4-a845-204094f5ccf1" + +/** The VRDE server external image updates interface entry points. Interface version 1. */ +typedef struct VRDEIMAGEINTERFACE +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Create image updates handle. + * + * The server can setup a context which will speed up further updates. + * + * A failure is returned if the server either does not support requested updates + * or it failed to create a handle. + * + * A success means that the server was able to create an internal context for + * the updates. + * + * @param hServer The server instance handle. + * @param phImage The returned image updates handle. + * @param pvUser The caller context of the call. + * @param u32ScreenId Updates are for this screen in a multimonitor config. + * @param fu32Flags VRDE_IMAGE_F_CREATE_* flags, which describe input data. + * @param pRect If VRDE_IMAGE_F_CREATE_WINDOW is set, this is the area of expected updates. + * Otherwise the entire screen will be used for updates. + * @param pvFormat Format specific data. + * @param cbFormat Size of format specific data. + * @param *pfu32CompletionFlags VRDE_IMAGE_F_COMPLETE_* flags. Async handle creation, etc. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEImageHandleCreate, (HVRDESERVER hServer, + HVRDEIMAGE *phImage, + void *pvUser, + uint32_t u32ScreenId, + uint32_t fu32Flags, + const RTRECT *pRect, + const char *pszFormatId, + const void *pvFormat, + uint32_t cbFormat, + uint32_t *pfu32CompletionFlags)); + + /** Create image updates handle. + * + * @param hImage The image updates handle, which the caller will not use anymore. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(void, VRDEImageHandleClose, (HVRDEIMAGE hImage)); + + /** Set a clipping region for a particular screen. + * + * @param hImage The image updates handle. + * @param cRects How many rectangles. 0 clears region for this screen. + * @param paRects Rectangles in the screen coordinates. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEImageRegionSet, (HVRDEIMAGE hImage, + uint32_t cRects, + const RTRECT *paRects)); + + /** Set the new position of the update area. Only works if the image handle + * has been created with VRDE_IMAGE_F_CREATE_WINDOW. + * + * @param hImage The image updates handle. + * @param pRect New area rectangle in the screen coordinates. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEImageGeometrySet, (HVRDEIMAGE hImage, + const RTRECT *pRect)); + + /** Set a configuration parameter. + * + * @param hImage The image updates handle. + * @param pszName The parameter name. + * @param pszValue The parameter value. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEImagePropertySet, (HVRDEIMAGE hImage, + const char *pszName, + const char *pszValue)); + + /** Query a configuration parameter. + * + * @param hImage The image updates handle. + * @param pszName The parameter name. + * @param pszValue The parameter value. + * @param cbValueIn The size of pszValue buffer. + * @param pcbValueOut The length of data returned in pszValue buffer. + * + * Properties names: + * "ID" - an unique string for this hImage. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEImagePropertyQuery, (HVRDEIMAGE hImage, + const char *pszName, + char *pszValue, + uint32_t cbValueIn, + uint32_t *pcbValueOut)); + + /** Data for an image update. + * + * @param hImage The image updates handle. + * @param i32TargetX Target x. + * @param i32TargetY Target y. + * @param i32TargetW Target width. + * @param i32TargetH Target height. + * @param pvImageData Format specific image data (for example VRDEIMAGEBITMAP). + * @param cbImageData Size of format specific image data. + */ + DECLR3CALLBACKMEMBER(void, VRDEImageUpdate, (HVRDEIMAGE hImage, + int32_t i32TargetX, + int32_t i32TargetY, + uint32_t u32TargetW, + uint32_t u32TargetH, + const void *pvImageData, + uint32_t cbImageData)); +} VRDEIMAGEINTERFACE; + +/* + * Notifications. + * u32Id parameter of VRDEIMAGECALLBACKS::VRDEImageCbNotify. + */ +#define VRDE_IMAGE_NOTIFY_HANDLE_CREATE 1 /* Async result of VRDEImageHandleCreate. + * pvData: uint32_t = 0 if stream was not created, + * a non zero value otherwise. + */ + +typedef struct VRDEIMAGECALLBACKS +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Generic notification callback. + * + * @param hServer The server instance handle. + * @param pvContext The callbacks context specified in VRDEGetInterface. + * @param pvUser The pvUser parameter of VRDEImageHandleCreate. + * @param hImage The handle, same as returned by VRDEImageHandleCreate. + * @param u32Id The notification identifier: VRDE_IMAGE_NOTIFY_*. + * @param pvData The callback specific data. + * @param cbData The size of buffer pointed by pvData. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEImageCbNotify,(void *pvContext, + void *pvUser, + HVRDEIMAGE hVideo, + uint32_t u32Id, + void *pvData, + uint32_t cbData)); +} VRDEIMAGECALLBACKS; + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDEImage_h */ diff --git a/include/VBox/RemoteDesktop/VRDEInput.h b/include/VBox/RemoteDesktop/VRDEInput.h new file mode 100644 index 00000000..378520ec --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDEInput.h @@ -0,0 +1,234 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - Input interface. + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDEInput_h +#define VBOX_INCLUDED_RemoteDesktop_VRDEInput_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* + * Interface for receiving input events from the client. + */ + +/* All structures in this file are packed. + * Everything is little-endian. + */ +#pragma pack(1) + +/* + * The application interface between VirtualBox and the VRDE server. + */ + +#define VRDE_INPUT_INTERFACE_NAME "VRDE::INPUT" + +/* + * Supported input methods. + */ +#define VRDE_INPUT_METHOD_TOUCH 1 + +/* + * fu32Flags for VRDEInputSetup + */ +#define VRDE_INPUT_F_ENABLE 1 + +/* The interface entry points. Interface version 1. */ +typedef struct VRDEINPUTINTERFACE +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* Tell the server that an input method will be used or disabled, etc. + * VRDECallbackInputSetup will be called with a result. + * + * @param hServer The VRDE server instance. + * @param u32Method The method VRDE_INPUT_METHOD_*. + * @param fu32Flags What to do with the method VRDE_INPUT_F_*. + * @param pvSetup Method specific parameters (optional). + * @param cbSetup Size of method specific parameters (optional). + */ + DECLR3CALLBACKMEMBER(void, VRDEInputSetup, (HVRDESERVER hServer, + uint32_t u32Method, + uint32_t fu32Flags, + const void *pvSetup, + uint32_t cbSetup)); +} VRDEINPUTINTERFACE; + + +/* Interface callbacks. */ +typedef struct VRDEINPUTCALLBACKS +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* VRDPInputSetup async result. + * + * @param pvCallback The callbacks context specified in VRDEGetInterface. + * @param rcSetup The result code of the request. + * @param u32Method The method VRDE_INPUT_METHOD_*. + * @param pvResult The result information. + * @param cbResult The size of buffer pointed by pvResult. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackInputSetup,(void *pvCallback, + int rcRequest, + uint32_t u32Method, + const void *pvResult, + uint32_t cbResult)); + + /* Input event. + * + * @param pvCallback The callbacks context specified in VRDEGetInterface. + * @param u32Method The method VRDE_INPUT_METHOD_*. + * @param pvEvent The event data. + * @param cbEvent The size of buffer pointed by pvEvent. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackInputEvent,(void *pvCallback, + uint32_t u32Method, + const void *pvEvent, + uint32_t cbEvent)); +} VRDEINPUTCALLBACKS; + + +/* + * Touch input definitions VRDE_INPUT_METHOD_TOUCH. + */ + +/* pvResult is not used */ + +/* RDPINPUT_HEADER */ +typedef struct VRDEINPUTHEADER +{ + uint16_t u16EventId; + uint32_t u32PDULength; +} VRDEINPUTHEADER; + +/* VRDEINPUTHEADER::u16EventId */ +#define VRDEINPUT_EVENTID_SC_READY 0x0001 +#define VRDEINPUT_EVENTID_CS_READY 0x0002 +#define VRDEINPUT_EVENTID_TOUCH 0x0003 +#define VRDEINPUT_EVENTID_SUSPEND_TOUCH 0x0004 +#define VRDEINPUT_EVENTID_RESUME_TOUCH 0x0005 +#define VRDEINPUT_EVENTID_DISMISS_HOVERING_CONTACT 0x0006 + +/* RDPINPUT_SC_READY_PDU */ +typedef struct VRDEINPUT_SC_READY_PDU +{ + VRDEINPUTHEADER header; + uint32_t u32ProtocolVersion; +} VRDEINPUT_SC_READY_PDU; + +#define VRDEINPUT_PROTOCOL_V1 0x00010000 +#define VRDEINPUT_PROTOCOL_V101 0x00010001 + +/* RDPINPUT_CS_READY_PDU */ +typedef struct VRDEINPUT_CS_READY_PDU +{ + VRDEINPUTHEADER header; + uint32_t u32Flags; + uint32_t u32ProtocolVersion; + uint16_t u16MaxTouchContacts; +} VRDEINPUT_CS_READY_PDU; + +#define VRDEINPUT_READY_FLAGS_SHOW_TOUCH_VISUALS 0x00000001 +#define VRDEINPUT_READY_FLAGS_DISABLE_TIMESTAMP_INJECTION 0x00000002 + +/* RDPINPUT_CONTACT_DATA */ +typedef struct VRDEINPUT_CONTACT_DATA +{ + uint8_t u8ContactId; + uint16_t u16FieldsPresent; + int32_t i32X; + int32_t i32Y; + uint32_t u32ContactFlags; + int16_t i16ContactRectLeft; + int16_t i16ContactRectTop; + int16_t i16ContactRectRight; + int16_t i16ContactRectBottom; + uint32_t u32Orientation; + uint32_t u32Pressure; +} VRDEINPUT_CONTACT_DATA; + +#define VRDEINPUT_CONTACT_DATA_CONTACTRECT_PRESENT 0x0001 +#define VRDEINPUT_CONTACT_DATA_ORIENTATION_PRESENT 0x0002 +#define VRDEINPUT_CONTACT_DATA_PRESSURE_PRESENT 0x0004 + +#define VRDEINPUT_CONTACT_FLAG_DOWN 0x0001 +#define VRDEINPUT_CONTACT_FLAG_UPDATE 0x0002 +#define VRDEINPUT_CONTACT_FLAG_UP 0x0004 +#define VRDEINPUT_CONTACT_FLAG_INRANGE 0x0008 +#define VRDEINPUT_CONTACT_FLAG_INCONTACT 0x0010 +#define VRDEINPUT_CONTACT_FLAG_CANCELED 0x0020 + +/* RDPINPUT_TOUCH_FRAME */ +typedef struct VRDEINPUT_TOUCH_FRAME +{ + uint16_t u16ContactCount; + uint64_t u64FrameOffset; + VRDEINPUT_CONTACT_DATA aContacts[1]; +} VRDEINPUT_TOUCH_FRAME; + +/* RDPINPUT_TOUCH_EVENT_PDU */ +typedef struct VRDEINPUT_TOUCH_EVENT_PDU +{ + VRDEINPUTHEADER header; + uint32_t u32EncodeTime; + uint16_t u16FrameCount; + VRDEINPUT_TOUCH_FRAME aFrames[1]; +} VRDEINPUT_TOUCH_EVENT_PDU; + +/* RDPINPUT_SUSPEND_TOUCH_PDU */ +typedef struct VRDEINPUT_SUSPEND_TOUCH_PDU +{ + VRDEINPUTHEADER header; +} VRDEINPUT_SUSPEND_TOUCH_PDU; + +/* RDPINPUT_RESUME_TOUCH_PDU */ +typedef struct VRDEINPUT_RESUME_TOUCH_PDU +{ + VRDEINPUTHEADER header; +} VRDEINPUT_RESUME_TOUCH_PDU; + +/* RDPINPUT_DISMISS_HOVERING_CONTACT_PDU */ +typedef struct VRDEINPUT_DISMISS_HOVERING_CONTACT_PDU +{ + VRDEINPUTHEADER header; + uint8_t u8ContactId; +} VRDEINPUT_DISMISS_HOVERING_CONTACT_PDU; + +#pragma pack() + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDEInput_h */ diff --git a/include/VBox/RemoteDesktop/VRDEMousePtr.h b/include/VBox/RemoteDesktop/VRDEMousePtr.h new file mode 100644 index 00000000..e62bc708 --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDEMousePtr.h @@ -0,0 +1,82 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - Mouse pointer updates interface. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDEMousePtr_h +#define VBOX_INCLUDED_RemoteDesktop_VRDEMousePtr_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* + * Interface for mouse pointer updates. + */ + +#define VRDE_MOUSEPTR_INTERFACE_NAME "MOUSEPTR" + +#pragma pack(1) +/* The color mouse pointer information: maximum allowed pointer size is 256x256. */ +typedef struct VRDEMOUSEPTRDATA +{ + uint16_t u16HotX; + uint16_t u16HotY; + uint16_t u16Width; + uint16_t u16Height; + uint16_t u16MaskLen; /* 0 for 32BPP pointers with alpha channel. */ + uint32_t u32DataLen; + /* uint8_t au8Mask[u16MaskLen]; The 1BPP mask. Optional: does not exist if u16MaskLen == 0. */ + /* uint8_t au8Data[u16DataLen]; The color bitmap, 32 bits color depth. */ +} VRDEMOUSEPTRDATA; +#pragma pack() + +/** The VRDE server external mouse pointer updates interface entry points. Interface version 1. */ +typedef struct VRDEMOUSEPTRINTERFACE +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Set the mouse pointer. + * + * @param hServer The server instance handle. + * @param pPointer The mouse pointer description. + * + */ + DECLR3CALLBACKMEMBER(void, VRDEMousePtr, (HVRDESERVER hServer, + const VRDEMOUSEPTRDATA *pPointer)); + +} VRDEMOUSEPTRINTERFACE; + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDEMousePtr_h */ diff --git a/include/VBox/RemoteDesktop/VRDEOrders.h b/include/VBox/RemoteDesktop/VRDEOrders.h new file mode 100644 index 00000000..06428fe0 --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDEOrders.h @@ -0,0 +1,310 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - Graphics Orders Structures. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDEOrders_h +#define VBOX_INCLUDED_RemoteDesktop_VRDEOrders_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* + * VRDE gets an information about a graphical update as a pointer + * to a memory block and the size of the memory block. + * The memory block layout is: + * VRDEORDERHDR - Describes the affected rectangle. + * Then VRDE orders follow: + * VRDEORDERCODE; + * a VRDEORDER* structure. + * + * If size of the memory block is equal to the VRDEORDERHDR, then a bitmap + * update is assumed. + */ + +/* VRDE order codes. Must be >= 0, because the VRDE internally + * uses negative values to mark some operations. + */ +#define VRDE_ORDER_DIRTY_RECT (0) +#define VRDE_ORDER_SOLIDRECT (1) +#define VRDE_ORDER_SOLIDBLT (2) +#define VRDE_ORDER_DSTBLT (3) +#define VRDE_ORDER_SCREENBLT (4) +#define VRDE_ORDER_PATBLTBRUSH (5) +#define VRDE_ORDER_MEMBLT (6) +#define VRDE_ORDER_CACHED_BITMAP (7) +#define VRDE_ORDER_DELETED_BITMAP (8) +#define VRDE_ORDER_LINE (9) +#define VRDE_ORDER_BOUNDS (10) +#define VRDE_ORDER_REPEAT (11) +#define VRDE_ORDER_POLYLINE (12) +#define VRDE_ORDER_ELLIPSE (13) +#define VRDE_ORDER_SAVESCREEN (14) +#define VRDE_ORDER_TEXT (15) + +/* 128 bit bitmap hash. */ +typedef uint8_t VRDEBITMAPHASH[16]; + +#pragma pack(1) +typedef struct _VRDEORDERHDR +{ + /** Coordinates of the affected rectangle. */ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; +} VRDEORDERHDR; + +typedef struct _VRDEORDERCODE +{ + uint32_t u32Code; +} VRDEORDERCODE; + +typedef struct _VRDEORDERPOINT +{ + int16_t x; + int16_t y; +} VRDEORDERPOINT; + +typedef struct _VRDEORDERPOLYPOINTS +{ + uint8_t c; + VRDEORDERPOINT a[16]; +} VRDEORDERPOLYPOINTS; + +typedef struct _VRDEORDERAREA +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; +} VRDEORDERAREA; + +typedef struct _VRDEORDERRECT +{ + int16_t left; + int16_t top; + int16_t right; + int16_t bottom; +} VRDEORDERRECT; + + +typedef struct _VRDEORDERBOUNDS +{ + VRDEORDERPOINT pt1; + VRDEORDERPOINT pt2; +} VRDEORDERBOUNDS; + +typedef struct _VRDEORDERREPEAT +{ + VRDEORDERBOUNDS bounds; +} VRDEORDERREPEAT; + + +/* Header for bitmap bits. */ +typedef struct _VRDEDATABITS +{ + uint32_t cb; /* Size of bitmap data without the header. */ + int16_t x; + int16_t y; + uint16_t cWidth; + uint16_t cHeight; + uint8_t cbPixel; + /* Bitmap data follow. */ +} VRDEDATABITS; + +typedef struct _VRDEORDERSOLIDRECT +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; + uint32_t rgb; +} VRDEORDERSOLIDRECT; + +typedef struct _VRDEORDERSOLIDBLT +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; + uint32_t rgb; + uint8_t rop; +} VRDEORDERSOLIDBLT; + +typedef struct _VRDEORDERDSTBLT +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; + uint8_t rop; +} VRDEORDERDSTBLT; + +typedef struct _VRDEORDERSCREENBLT +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; + int16_t xSrc; + int16_t ySrc; + uint8_t rop; +} VRDEORDERSCREENBLT; + +typedef struct _VRDEORDERPATBLTBRUSH +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; + int8_t xSrc; + int8_t ySrc; + uint32_t rgbFG; + uint32_t rgbBG; + uint8_t rop; + uint8_t pattern[8]; +} VRDEORDERPATBLTBRUSH; + +typedef struct _VRDEORDERMEMBLT +{ + int16_t x; + int16_t y; + uint16_t w; + uint16_t h; + int16_t xSrc; + int16_t ySrc; + uint8_t rop; + VRDEBITMAPHASH hash; +} VRDEORDERMEMBLT; + +typedef struct _VRDEORDERCACHEDBITMAP +{ + VRDEBITMAPHASH hash; + /* VRDEDATABITS and the bitmap data follow. */ +} VRDEORDERCACHEDBITMAP; + +typedef struct _VRDEORDERDELETEDBITMAP +{ + VRDEBITMAPHASH hash; +} VRDEORDERDELETEDBITMAP; + +typedef struct _VRDEORDERLINE +{ + int16_t x1; + int16_t y1; + int16_t x2; + int16_t y2; + int16_t xBounds1; + int16_t yBounds1; + int16_t xBounds2; + int16_t yBounds2; + uint8_t mix; + uint32_t rgb; +} VRDEORDERLINE; + +typedef struct _VRDEORDERPOLYLINE +{ + VRDEORDERPOINT ptStart; + uint8_t mix; + uint32_t rgb; + VRDEORDERPOLYPOINTS points; +} VRDEORDERPOLYLINE; + +typedef struct _VRDEORDERELLIPSE +{ + VRDEORDERPOINT pt1; + VRDEORDERPOINT pt2; + uint8_t mix; + uint8_t fillMode; + uint32_t rgb; +} VRDEORDERELLIPSE; + +typedef struct _VRDEORDERSAVESCREEN +{ + VRDEORDERPOINT pt1; + VRDEORDERPOINT pt2; + uint8_t ident; + uint8_t restore; +} VRDEORDERSAVESCREEN; + +typedef struct _VRDEORDERGLYPH +{ + uint32_t o32NextGlyph; + uint64_t u64Handle; + + /* The glyph origin position on the screen. */ + int16_t x; + int16_t y; + + /* The glyph bitmap dimensions. Note w == h == 0 for the space character. */ + uint16_t w; + uint16_t h; + + /* The character origin in the bitmap. */ + int16_t xOrigin; + int16_t yOrigin; + + /* 1BPP bitmap. Rows are byte aligned. Size is (((w + 7)/8) * h + 3) & ~3. */ + uint8_t au8Bitmap[1]; +} VRDEORDERGLYPH; + +typedef struct _VRDEORDERTEXT +{ + uint32_t cbOrder; + + int16_t xBkGround; + int16_t yBkGround; + uint16_t wBkGround; + uint16_t hBkGround; + + int16_t xOpaque; + int16_t yOpaque; + uint16_t wOpaque; + uint16_t hOpaque; + + uint16_t u16MaxGlyph; + + uint8_t u8Glyphs; + uint8_t u8Flags; + uint16_t u8CharInc; + uint32_t u32FgRGB; + uint32_t u32BgRGB; + + /* u8Glyphs glyphs follow. Size of each glyph structure may vary. */ +} VRDEORDERTEXT; +#pragma pack() + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDEOrders_h */ diff --git a/include/VBox/RemoteDesktop/VRDESCard.h b/include/VBox/RemoteDesktop/VRDESCard.h new file mode 100644 index 00000000..9281ebed --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDESCard.h @@ -0,0 +1,528 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - SmartCard interface. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDESCard_h +#define VBOX_INCLUDED_RemoteDesktop_VRDESCard_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* + * Interface for accessing the smart card reader devices on the client. + * + * Async callbacks are used for providing feedback, reporting errors, etc. + * + * The caller prepares a VRDESCARD*REQ structure and submits it. + */ + +#define VRDE_SCARD_INTERFACE_NAME "SCARD" + +/** The VRDE server smart card access interface entry points. Interface version 1. */ +typedef struct VRDESCARDINTERFACE +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Submit an async IO request to the client. + * + * @param hServer The VRDE server instance. + * @param pvUser The callers context of this request. + * @param u32Function The function: VRDE_SCARD_FN_*. + * @param pvData Function specific data: VRDESCARD*REQ. + * @param cbData Size of data. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDESCardRequest, (HVRDESERVER hServer, + void *pvUser, + uint32_t u32Function, + const void *pvData, + uint32_t cbData)); + +} VRDESCARDINTERFACE; + +/* Smartcard interface callbacks. */ +typedef struct VRDESCARDCALLBACKS +{ + /** The header. */ + VRDEINTERFACEHDR header; + + /** Notifications. + * + * @param pvContext The callbacks context specified in VRDEGetInterface. + * @param u32Id The notification identifier: VRDE_SCARD_NOTIFY_*. + * @param pvData The notification specific data. + * @param cbData The size of buffer pointed by pvData. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDESCardCbNotify, (void *pvContext, + uint32_t u32Id, + void *pvData, + uint32_t cbData)); + + /** IO response. + * + * @param pvContext The callbacks context specified in VRDEGetInterface. + * @param rcRequest The IPRT status code for the request. + * @param pvUser The pvUser parameter of VRDESCardRequest. + * @param u32Function The completed function: VRDE_SCARD_FN_*. + * @param pvData Function specific response data: VRDESCARD*RSP. + * @param cbData The size of the buffer pointed by pvData. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDESCardCbResponse, (void *pvContext, + int rcRequest, + void *pvUser, + uint32_t u32Function, + void *pvData, + uint32_t cbData)); +} VRDESCARDCALLBACKS; + + +/* + * Notifications. + * u32Id parameter of VRDESCARDCALLBACKS::VRDESCardCbNotify. + */ + +#define VRDE_SCARD_NOTIFY_ATTACH 1 /* A SCARD RDPDR device has been attached. */ +#define VRDE_SCARD_NOTIFY_DETACH 2 /* A SCARD RDPDR device has been detached. */ + +/* + * Notifications. + * Data structures: pvData of VRDESCARDCALLBACKS::VRDESCardCbNotify. + */ +typedef struct VRDESCARDNOTIFYATTACH +{ + uint32_t u32ClientId; + uint32_t u32DeviceId; +} VRDESCARDNOTIFYATTACH; + +typedef struct VRDESCARDNOTIFYDETACH +{ + uint32_t u32ClientId; + uint32_t u32DeviceId; +} VRDESCARDNOTIFYDETACH; + + +/* + * IO request codes. + * Must be not 0, which is used internally. + */ + +#define VRDE_SCARD_FN_ESTABLISHCONTEXT 1 +#define VRDE_SCARD_FN_LISTREADERS 2 +#define VRDE_SCARD_FN_RELEASECONTEXT 3 +#define VRDE_SCARD_FN_GETSTATUSCHANGE 4 +#define VRDE_SCARD_FN_CANCEL 5 +#define VRDE_SCARD_FN_CONNECT 6 +#define VRDE_SCARD_FN_RECONNECT 7 +#define VRDE_SCARD_FN_DISCONNECT 8 +#define VRDE_SCARD_FN_BEGINTRANSACTION 9 +#define VRDE_SCARD_FN_ENDTRANSACTION 10 +#define VRDE_SCARD_FN_STATE 11 +#define VRDE_SCARD_FN_STATUS 12 +#define VRDE_SCARD_FN_TRANSMIT 13 +#define VRDE_SCARD_FN_CONTROL 14 +#define VRDE_SCARD_FN_GETATTRIB 15 +#define VRDE_SCARD_FN_SETATTRIB 16 + +#define VRDE_SCARD_MAX_READERS 10 +#define VRDE_SCARD_MAX_ATR_LENGTH 36 +#define VRDE_SCARD_MAX_PCI_DATA 1024 + +#define VRDE_SCARD_S_SUCCESS 0x00000000 +#define VRDE_SCARD_F_INTERNAL_ERROR 0x80100001 +#define VRDE_SCARD_E_CANCELLED 0x80100002 +#define VRDE_SCARD_E_INVALID_HANDLE 0x80100003 +#define VRDE_SCARD_E_INVALID_PARAMETER 0x80100004 +#define VRDE_SCARD_E_INVALID_TARGET 0x80100005 +#define VRDE_SCARD_E_NO_MEMORY 0x80100006 +#define VRDE_SCARD_F_WAITED_TOO_LONG 0x80100007 +#define VRDE_SCARD_E_INSUFFICIENT_BUFFER 0x80100008 +#define VRDE_SCARD_E_UNKNOWN_READER 0x80100009 +#define VRDE_SCARD_E_TIMEOUT 0x8010000A +#define VRDE_SCARD_E_SHARING_VIOLATION 0x8010000B +#define VRDE_SCARD_E_NO_SMARTCARD 0x8010000C +#define VRDE_SCARD_E_UNKNOWN_CARD 0x8010000D +#define VRDE_SCARD_E_CANT_DISPOSE 0x8010000E +#define VRDE_SCARD_E_PROTO_MISMATCH 0x8010000F +#define VRDE_SCARD_E_NOT_READY 0x80100010 +#define VRDE_SCARD_E_INVALID_VALUE 0x80100011 +#define VRDE_SCARD_E_SYSTEM_CANCELLED 0x80100012 +#define VRDE_SCARD_F_COMM_ERROR 0x80100013 +#define VRDE_SCARD_F_UNKNOWN_ERROR 0x80100014 +#define VRDE_SCARD_E_INVALID_ATR 0x80100015 +#define VRDE_SCARD_E_NOT_TRANSACTED 0x80100016 +#define VRDE_SCARD_E_READER_UNAVAILABLE 0x80100017 +#define VRDE_SCARD_P_SHUTDOWN 0x80100018 +#define VRDE_SCARD_E_PCI_TOO_SMALL 0x80100019 +#define VRDE_SCARD_E_ICC_INSTALLATION 0x80100020 +#define VRDE_SCARD_E_ICC_CREATEORDER 0x80100021 +#define VRDE_SCARD_E_UNSUPPORTED_FEATURE 0x80100022 +#define VRDE_SCARD_E_DIR_NOT_FOUND 0x80100023 +#define VRDE_SCARD_E_FILE_NOT_FOUND 0x80100024 +#define VRDE_SCARD_E_NO_DIR 0x80100025 +#define VRDE_SCARD_E_READER_UNSUPPORTED 0x8010001A +#define VRDE_SCARD_E_DUPLICATE_READER 0x8010001B +#define VRDE_SCARD_E_CARD_UNSUPPORTED 0x8010001C +#define VRDE_SCARD_E_NO_SERVICE 0x8010001D +#define VRDE_SCARD_E_SERVICE_STOPPED 0x8010001E +#define VRDE_SCARD_E_UNEXPECTED 0x8010001F +#define VRDE_SCARD_E_NO_FILE 0x80100026 +#define VRDE_SCARD_E_NO_ACCESS 0x80100027 +#define VRDE_SCARD_E_WRITE_TOO_MANY 0x80100028 +#define VRDE_SCARD_E_BAD_SEEK 0x80100029 +#define VRDE_SCARD_E_INVALID_CHV 0x8010002A +#define VRDE_SCARD_E_UNKNOWN_RES_MSG 0x8010002B +#define VRDE_SCARD_E_NO_SUCH_CERTIFICATE 0x8010002C +#define VRDE_SCARD_E_CERTIFICATE_UNAVAILABLE 0x8010002D +#define VRDE_SCARD_E_NO_READERS_AVAILABLE 0x8010002E +#define VRDE_SCARD_E_COMM_DATA_LOST 0x8010002F +#define VRDE_SCARD_E_NO_KEY_CONTAINER 0x80100030 +#define VRDE_SCARD_E_SERVER_TOO_BUSY 0x80100031 +#define VRDE_SCARD_E_PIN_CACHE_EXPIRED 0x80100032 +#define VRDE_SCARD_E_NO_PIN_CACHE 0x80100033 +#define VRDE_SCARD_E_READ_ONLY_CARD 0x80100034 +#define VRDE_SCARD_W_UNSUPPORTED_CARD 0x80100065 +#define VRDE_SCARD_W_UNRESPONSIVE_CARD 0x80100066 +#define VRDE_SCARD_W_UNPOWERED_CARD 0x80100067 +#define VRDE_SCARD_W_RESET_CARD 0x80100068 +#define VRDE_SCARD_W_REMOVED_CARD 0x80100069 +#define VRDE_SCARD_W_SECURITY_VIOLATION 0x8010006A +#define VRDE_SCARD_W_WRONG_CHV 0x8010006B +#define VRDE_SCARD_W_CHV_BLOCKED 0x8010006C +#define VRDE_SCARD_W_EOF 0x8010006D +#define VRDE_SCARD_W_CANCELLED_BY_USER 0x8010006E +#define VRDE_SCARD_W_CARD_NOT_AUTHENTICATED 0x8010006F +#define VRDE_SCARD_W_CACHE_ITEM_NOT_FOUND 0x80100070 +#define VRDE_SCARD_W_CACHE_ITEM_STALE 0x80100071 +#define VRDE_SCARD_W_CACHE_ITEM_TOO_BIG 0x80100072 + +#define VRDE_SCARD_STATE_UNAWARE 0x0000 +#define VRDE_SCARD_STATE_IGNORE 0x0001 +#define VRDE_SCARD_STATE_CHANGED 0x0002 +#define VRDE_SCARD_STATE_UNKNOWN 0x0004 +#define VRDE_SCARD_STATE_UNAVAILABLE 0x0008 +#define VRDE_SCARD_STATE_EMPTY 0x0010 +#define VRDE_SCARD_STATE_PRESENT 0x0020 +#define VRDE_SCARD_STATE_ATRMATCH 0x0040 +#define VRDE_SCARD_STATE_EXCLUSIVE 0x0080 +#define VRDE_SCARD_STATE_INUSE 0x0100 +#define VRDE_SCARD_STATE_MUTE 0x0200 +#define VRDE_SCARD_STATE_UNPOWERED 0x0400 +#define VRDE_SCARD_STATE_MASK UINT32_C(0x0000FFFF) +#define VRDE_SCARD_STATE_COUNT_MASK UINT32_C(0xFFFF0000) + +#define VRDE_SCARD_PROTOCOL_UNDEFINED 0x00000000 +#define VRDE_SCARD_PROTOCOL_T0 0x00000001 +#define VRDE_SCARD_PROTOCOL_T1 0x00000002 +#define VRDE_SCARD_PROTOCOL_Tx 0x00000003 +#define VRDE_SCARD_PROTOCOL_RAW 0x00010000 + +#define VRDE_SCARD_PROTOCOL_DEFAULT 0x80000000 +#define VRDE_SCARD_PROTOCOL_OPTIMAL 0x00000000 + +#define VRDE_SCARD_SHARE_EXCLUSIVE 0x00000001 +#define VRDE_SCARD_SHARE_SHARED 0x00000002 +#define VRDE_SCARD_SHARE_DIRECT 0x00000003 + +/* u32Initialization, u32Disposition */ +#define VRDE_SCARD_LEAVE_CARD 0x00000000 +#define VRDE_SCARD_RESET_CARD 0x00000001 +#define VRDE_SCARD_UNPOWER_CARD 0x00000002 +#define VRDE_SCARD_EJECT_CARD 0x00000003 + +/* VRDESCARDSTATUSRSP::u32State */ +#define VRDE_SCARD_UNKNOWN 0x00000000 +#define VRDE_SCARD_ABSENT 0x00000001 +#define VRDE_SCARD_PRESENT 0x00000002 +#define VRDE_SCARD_SWALLOWED 0x00000003 +#define VRDE_SCARD_POWERED 0x00000004 +#define VRDE_SCARD_NEGOTIABLE 0x00000005 +#define VRDE_SCARD_SPECIFICMODE 0x00000006 + + +/* + * IO request data structures. + */ +typedef struct VRDESCARDCONTEXT +{ + uint32_t u32ContextSize; + uint8_t au8Context[16]; +} VRDESCARDCONTEXT; + +typedef struct VRDESCARDHANDLE +{ + VRDESCARDCONTEXT Context; + uint32_t u32HandleSize; + uint8_t au8Handle[16]; +} VRDESCARDHANDLE; + +typedef struct VRDESCARDREADERSTATECALL +{ + char *pszReader; /* UTF8 */ + uint32_t u32CurrentState; /* VRDE_SCARD_STATE_* */ +} VRDESCARDREADERSTATECALL; + +typedef struct VRDESCARDREADERSTATERETURN +{ + uint32_t u32CurrentState; /* VRDE_SCARD_STATE_* */ + uint32_t u32EventState; /* VRDE_SCARD_STATE_* */ + uint32_t u32AtrLength; + uint8_t au8Atr[VRDE_SCARD_MAX_ATR_LENGTH]; +} VRDESCARDREADERSTATERETURN; + +typedef struct VRDESCARDPCI +{ + uint32_t u32Protocol; /* VRDE_SCARD_PROTOCOL_* */ + uint32_t u32PciLength; /* Includes u32Protocol and u32PciLength fields. 8 if no data in au8PciData. */ + uint8_t au8PciData[VRDE_SCARD_MAX_PCI_DATA]; +} VRDESCARDPCI; + +typedef struct VRDESCARDESTABLISHCONTEXTREQ +{ + uint32_t u32ClientId; + uint32_t u32DeviceId; +} VRDESCARDESTABLISHCONTEXTREQ; + +typedef struct VRDESCARDESTABLISHCONTEXTRSP +{ + uint32_t u32ReturnCode; + VRDESCARDCONTEXT Context; +} VRDESCARDESTABLISHCONTEXTRSP; + +typedef struct VRDESCARDLISTREADERSREQ +{ + VRDESCARDCONTEXT Context; +} VRDESCARDLISTREADERSREQ; + +typedef struct VRDESCARDLISTREADERSRSP +{ + uint32_t u32ReturnCode; + uint32_t cReaders; + char *apszNames[VRDE_SCARD_MAX_READERS]; /* UTF8 */ +} VRDESCARDLISTREADERSRSP; + +typedef struct VRDESCARDRELEASECONTEXTREQ +{ + VRDESCARDCONTEXT Context; +} VRDESCARDRELEASECONTEXTREQ; + +typedef struct VRDESCARDRELEASECONTEXTRSP +{ + uint32_t u32ReturnCode; +} VRDESCARDRELEASECONTEXTRSP; + +typedef struct VRDESCARDGETSTATUSCHANGEREQ +{ + VRDESCARDCONTEXT Context; + uint32_t u32Timeout; /* Milliseconds. 0xFFFFFFFF = INFINITE */ + uint32_t cReaders; + VRDESCARDREADERSTATECALL aReaderStates[VRDE_SCARD_MAX_READERS]; +} VRDESCARDGETSTATUSCHANGEREQ; + +typedef struct VRDESCARDGETSTATUSCHANGERSP +{ + uint32_t u32ReturnCode; + uint32_t cReaders; + VRDESCARDREADERSTATERETURN aReaderStates[VRDE_SCARD_MAX_READERS]; +} VRDESCARDGETSTATUSCHANGERSP; + +typedef struct VRDESCARDCANCELREQ +{ + VRDESCARDCONTEXT Context; +} VRDESCARDCANCELREQ; + +typedef struct VRDESCARDCANCELRSP +{ + uint32_t u32ReturnCode; +} VRDESCARDCANCELRSP; + +typedef struct VRDESCARDCONNECTREQ +{ + VRDESCARDCONTEXT Context; + char *pszReader; /* UTF8 */ + uint32_t u32ShareMode; /* VRDE_SCARD_SHARE_* */ + uint32_t u32PreferredProtocols; +} VRDESCARDCONNECTREQ; + +typedef struct VRDESCARDCONNECTRSP +{ + uint32_t u32ReturnCode; + VRDESCARDHANDLE hCard; + uint32_t u32ActiveProtocol; +} VRDESCARDCONNECTRSP; + +typedef struct VRDESCARDRECONNECTREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32ShareMode; + uint32_t u32PreferredProtocols; + uint32_t u32Initialization; +} VRDESCARDRECONNECTREQ; + +typedef struct VRDESCARDRECONNECTRSP +{ + uint32_t u32ReturnCode; + uint32_t u32ActiveProtocol; +} VRDESCARDRECONNECTRSP; + +typedef struct VRDESCARDDISCONNECTREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32Disposition; +} VRDESCARDDISCONNECTREQ; + +typedef struct VRDESCARDDISCONNECTRSP +{ + uint32_t u32ReturnCode; +} VRDESCARDDISCONNECTRSP; + +typedef struct VRDESCARDBEGINTRANSACTIONREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32Disposition; +} VRDESCARDBEGINTRANSACTIONREQ; + +typedef struct VRDESCARDBEGINTRANSACTIONRSP +{ + uint32_t u32ReturnCode; +} VRDESCARDBEGINTRANSACTIONRSP; + +typedef struct VRDESCARDENDTRANSACTIONREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32Disposition; +} VRDESCARDENDTRANSACTIONREQ; + +typedef struct VRDESCARDENDTRANSACTIONRSP +{ + uint32_t u32ReturnCode; +} VRDESCARDENDTRANSACTIONRSP; + +typedef struct VRDESCARDSTATEREQ +{ + VRDESCARDHANDLE hCard; +} VRDESCARDSTATEREQ; + +typedef struct VRDESCARDSTATERSP +{ + uint32_t u32ReturnCode; + uint32_t u32State; + uint32_t u32Protocol; + uint32_t u32AtrLength; + uint8_t au8Atr[VRDE_SCARD_MAX_ATR_LENGTH]; +} VRDESCARDSTATERSP; + +typedef struct VRDESCARDSTATUSREQ +{ + VRDESCARDHANDLE hCard; +} VRDESCARDSTATUSREQ; + +typedef struct VRDESCARDSTATUSRSP +{ + uint32_t u32ReturnCode; + char *szReader; + uint32_t u32State; + uint32_t u32Protocol; + uint32_t u32AtrLength; + uint8_t au8Atr[VRDE_SCARD_MAX_ATR_LENGTH]; +} VRDESCARDSTATUSRSP; + +typedef struct VRDESCARDTRANSMITREQ +{ + VRDESCARDHANDLE hCard; + VRDESCARDPCI ioSendPci; + uint32_t u32SendLength; + uint8_t *pu8SendBuffer; + uint32_t u32RecvLength; +} VRDESCARDTRANSMITREQ; + +typedef struct VRDESCARDTRANSMITRSP +{ + uint32_t u32ReturnCode; + VRDESCARDPCI ioRecvPci; + uint32_t u32RecvLength; + uint8_t *pu8RecvBuffer; +} VRDESCARDTRANSMITRSP; + +typedef struct VRDESCARDCONTROLREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32ControlCode; + uint32_t u32InBufferSize; + uint8_t *pu8InBuffer; + uint32_t u32OutBufferSize; +} VRDESCARDCONTROLREQ; + +typedef struct VRDESCARDCONTROLRSP +{ + uint32_t u32ReturnCode; + uint32_t u32OutBufferSize; + uint8_t *pu8OutBuffer; +} VRDESCARDCONTROLRSP; + +typedef struct VRDESCARDGETATTRIBREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32AttrId; + uint32_t u32AttrLen; +} VRDESCARDGETATTRIBREQ; + +typedef struct VRDESCARDGETATTRIBRSP +{ + uint32_t u32ReturnCode; + uint32_t u32AttrLength; + uint8_t *pu8Attr; +} VRDESCARDGETATTRIBRSP; + +typedef struct VRDESCARDSETATTRIBREQ +{ + VRDESCARDHANDLE hCard; + uint32_t u32AttrId; + uint32_t u32AttrLen; + uint8_t *pu8Attr; +} VRDESCARDSETATTRIBREQ; + +typedef struct VRDESCARDSETATTRIBRSP +{ + uint32_t u32ReturnCode; +} VRDESCARDSETATTRIBRSP; + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDESCard_h */ diff --git a/include/VBox/RemoteDesktop/VRDETSMF.h b/include/VBox/RemoteDesktop/VRDETSMF.h new file mode 100644 index 00000000..40fb9d5b --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDETSMF.h @@ -0,0 +1,154 @@ +/* @file + * VBox Remote Desktop Extension (VRDE) - raw TSMF dynamic channel interface. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDETSMF_h +#define VBOX_INCLUDED_RemoteDesktop_VRDETSMF_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* + * Interface creating a TSMF dynamic channel instances and sending/receving data. + * + * Async callbacks are used for providing feedback, reporting errors, etc. + */ + +#define VRDE_TSMF_INTERFACE_NAME "TSMFRAW" + +/* The VRDE server TSMF interface entry points. Interface version 1. */ +typedef struct VRDETSMFINTERFACE +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* Create a new TSMF channel instance. + * The channel is created only for one client, which is connected to the server. + * The client is the first which supports dynamic RDP channels. + * + * If this method return success then the server will use the VRDE_TSMF_N_CREATE_* + * notification to report the channel handle. + * + * @param hServer The VRDE server instance. + * @param pvChannel A context to be associated with the channel. + * @param u32Flags VRDE_TSMF_F_* + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDETSMFChannelCreate, (HVRDESERVER hServer, + void *pvChannel, + uint32_t u32Flags)); + + /* Close a TSMF channel instance. + * + * @param hServer The VRDE server instance. + * @param u32ChannelHandle Which channel to close. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDETSMFChannelClose, (HVRDESERVER hServer, + uint32_t u32ChannelHandle)); + + /* Send data to the TSMF channel instance. + * + * @param hServer The VRDE server instance. + * @param u32ChannelHandle Channel to send data. + * @param pvData Raw data to be sent, the format depends on which + * u32Flags were specified in Create: TSMF message, + * or channel header + TSMF message. + * @param cbData Size of data. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDETSMFChannelSend, (HVRDESERVER hServer, + uint32_t u32ChannelHandle, + const void *pvData, + uint32_t cbData)); +} VRDETSMFINTERFACE; + +/* TSMF interface callbacks. */ +typedef struct VRDETSMFCALLBACKS +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* Channel event notification. + * + * @param pvContext The callbacks context specified in VRDEGetInterface. + * @param u32Notification The kind of the notification: VRDE_TSMF_N_*. + * @param pvChannel A context which was used in VRDETSMFChannelCreate. + * @param pvParm The notification specific data. + * @param cbParm The size of buffer pointed by pvParm. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(void, VRDETSMFCbNotify, (void *pvContext, + uint32_t u32Notification, + void *pvChannel, + const void *pvParm, + uint32_t cbParm)); +} VRDETSMFCALLBACKS; + + +/* VRDETSMFChannelCreate::u32Flags */ +#define VRDE_TSMF_F_CHANNEL_HEADER 0x00000001 + + +/* VRDETSMFCbNotify::u32Notification */ +#define VRDE_TSMF_N_CREATE_ACCEPTED 1 +#define VRDE_TSMF_N_CREATE_DECLINED 2 +#define VRDE_TSMF_N_DATA 3 /* Data received. */ +#define VRDE_TSMF_N_DISCONNECTED 4 /* The channel is not connected anymore. */ + + +/* + * Notification parameters. + */ + +/* VRDE_TSMF_N_CREATE_ACCEPTED */ +typedef struct VRDETSMFNOTIFYCREATEACCEPTED +{ + uint32_t u32ChannelHandle; +} VRDETSMFNOTIFYCREATEACCEPTED; + +/* VRDE_TSMF_N_EVENT_DATA */ +typedef struct VRDETSMFNOTIFYDATA +{ + const void *pvData; + uint32_t cbData; /* How many bytes available. */ +} VRDETSMFNOTIFYDATA; + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDETSMF_h */ diff --git a/include/VBox/RemoteDesktop/VRDEVideoIn.h b/include/VBox/RemoteDesktop/VRDEVideoIn.h new file mode 100644 index 00000000..07c45579 --- /dev/null +++ b/include/VBox/RemoteDesktop/VRDEVideoIn.h @@ -0,0 +1,1093 @@ +/** @file + * VBox Remote Desktop Extension (VRDE) - Video Input interface. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_RemoteDesktop_VRDEVideoIn_h +#define VBOX_INCLUDED_RemoteDesktop_VRDEVideoIn_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/* Define VRDE_VIDEOIN_WITH_VRDEINTERFACE to include the server VRDE interface parts. */ + +#ifdef VRDE_VIDEOIN_WITH_VRDEINTERFACE +# include +#endif /* VRDE_VIDEOIN_WITH_VRDEINTERFACE */ + +#ifdef AssertCompileSize +# define ASSERTSIZE(type, size) AssertCompileSize(type, size); +#else +# define ASSERTSIZE(type, size) +#endif /* AssertCompileSize */ + +#include + + +/* + * Interface for accessing a video camera device on the client. + * + * Async callbacks are used for providing feedback, reporting errors, etc. + * + * Initial version supports: Camera + Processing Unit + Streaming Control. + * + * There are 2 modes: + * 1) The virtual WebCam is already attached to the guest. + * 2) The virtual WebCam will be attached when the client has it. + * + * Initially the mode 1 is supported. + * + * Mode 1 details: + * The WebCam has some fixed functionality, according to the descriptors, + * which has been already read by the guest. So some of functions will + * not work if the client does not support them. + * + * Mode 2 details: + * Virtual WebCam descriptors are built from the client capabilities. + * + * Similarly to the smartcard, the server will inform the ConsoleVRDE that there is a WebCam. + * ConsoleVRDE creates a VRDEVIDEOIN handle and forwards virtual WebCam requests to it. + * + * Interface with VBox. + * + * Virtual WebCam ConsoleVRDE VRDE + * + * Negotiate <-> + * <- VideoInDeviceNotify(Attached, DeviceId) + * -> GetDeviceDesc + * <- DeviceDesc + * 2 <- CreateCamera + * 2 CameraCreated -> + * + * CameraRequest -> Request -> + * Response <- <- Response <- Response + * Frame <- <- Frame <- Frame + * <- VideoInDeviceNotify(Detached, DeviceId) + * + * Unsupported requests fail. + * The Device Description received from the client may be used to validate WebCam requests + * in the ConsoleVRDE code, for example filter out unsupported requests. + * + */ + +/* All structures in this file are packed. + * Everything is little-endian. + */ +#pragma pack(1) + +/* + * The interface supports generic video input descriptors, capabilities and controls: + * * Descriptors + * + Interface + * - Input, Camera Terminal + * - Processing Unit + * + Video Streaming + * - Input Header + * - Payload Format + * - Video Frame + * - Still Image Frame + * * Video Control requests + * + Interface + * - Power Mode + * + Unit and Terminal + * camera + * - Scanning Mode (interlaced, progressive) + * - Auto-Exposure Mode + * - Auto-Exposure Priority + * - Exposure Time Absolute, Relative + * - Focus Absolute, Relative, Auto + * - Iris Absolute, Relative + * - Zoom Absolute, Relative + * - PanTilt Absolute, Relative + * - Roll Absolute, Relative + * - Privacy + * processing + * - Backlight Compensation + * - Brightness + * - Contrast + * - Gain + * - Power Line Frequency + * - Hue Manual, Auto + * - Saturation + * - Sharpness + * - Gamma + * - White Balance Temperature Manual, Auto + * - White Balance Component Manual, Auto + * - Digital Multiplier + * - Digital Multiplier Limit + * * Video Streaming requests + * + Interface + * - Synch Delay + * - Still Image Trigger + * - Generate Key Frame + * - Update Frame Segment + * - Stream Error Code + * + * + * Notes: + * * still capture uses a method similar to method 2, because the still frame will + * be send instead of video over the channel. + * Also the method 2 can be in principle emulated by both 1 and 3 on the client. + * However the client can initiate a still frame transfer, similar to hardware button trigger. + * * all control changes are async. + * * probe/commit are not used. The server can select a supported format/frame from the list. + * * no color matching. sRGB is the default. + * * most of constants are the same as in USB Video Class spec, but they are not the same and + * should be always converted. + */ + +/* + * The DEVICEDEC describes the device and provides a list of supported formats: + * VRDEVIDEOINDEVICEDESC + * VRDEVIDEOINFORMATDESC[0]; + * VRDEVIDEOINFRAMEDESC[0..N-1] + * VRDEVIDEOINFORMATDESC[1]; + * VRDEVIDEOINFRAMEDESC[0..M-1] + * ... + */ + +typedef struct VRDEVIDEOINDEVICEDESC +{ + uint16_t u16ObjectiveFocalLengthMin; + uint16_t u16ObjectiveFocalLengthMax; + uint16_t u16OcularFocalLength; + uint16_t u16MaxMultiplier; + uint32_t fu32CameraControls; /* VRDE_VIDEOIN_F_CT_CTRL_* */ + uint32_t fu32ProcessingControls; /* VRDE_VIDEOIN_F_PU_CTRL_* */ + uint8_t fu8DeviceCaps; /* VRDE_VIDEOIN_F_DEV_CAP_* */ + uint8_t u8NumFormats; /* Number of following VRDEVIDEOINFORMATDESC structures. */ + uint16_t cbExt; /* Size of the optional extended description. */ + /* An extended description may follow. */ + /* An array of VRDEVIDEOINFORMATDESC follows. */ +} VRDEVIDEOINDEVICEDESC; + +/* VRDEVIDEOINDEVICEDESC::fu32CameraControls */ +#define VRDE_VIDEOIN_F_CT_CTRL_SCANNING_MODE 0x00000001 /* D0: Scanning Mode */ +#define VRDE_VIDEOIN_F_CT_CTRL_AE_MODE 0x00000002 /* D1: Auto-Exposure Mode */ +#define VRDE_VIDEOIN_F_CT_CTRL_AE_PRIORITY 0x00000004 /* D2: Auto-Exposure Priority */ +#define VRDE_VIDEOIN_F_CT_CTRL_EXPOSURE_TIME_ABSOLUTE 0x00000008 /* D3: Exposure Time (Absolute) */ +#define VRDE_VIDEOIN_F_CT_CTRL_EXPOSURE_TIME_RELATIVE 0x00000010 /* D4: Exposure Time (Relative) */ +#define VRDE_VIDEOIN_F_CT_CTRL_FOCUS_ABSOLUTE 0x00000020 /* D5: Focus (Absolute) */ +#define VRDE_VIDEOIN_F_CT_CTRL_FOCUS_RELATIVE 0x00000040 /* D6: Focus (Relative) */ +#define VRDE_VIDEOIN_F_CT_CTRL_IRIS_ABSOLUTE 0x00000080 /* D7: Iris (Absolute) */ +#define VRDE_VIDEOIN_F_CT_CTRL_IRIS_RELATIVE 0x00000100 /* D8: Iris (Relative) */ +#define VRDE_VIDEOIN_F_CT_CTRL_ZOOM_ABSOLUTE 0x00000200 /* D9: Zoom (Absolute) */ +#define VRDE_VIDEOIN_F_CT_CTRL_ZOOM_RELATIVE 0x00000400 /* D10: Zoom (Relative) */ +#define VRDE_VIDEOIN_F_CT_CTRL_PANTILT_ABSOLUTE 0x00000800 /* D11: PanTilt (Absolute) */ +#define VRDE_VIDEOIN_F_CT_CTRL_PANTILT_RELATIVE 0x00001000 /* D12: PanTilt (Relative) */ +#define VRDE_VIDEOIN_F_CT_CTRL_ROLL_ABSOLUTE 0x00002000 /* D13: Roll (Absolute) */ +#define VRDE_VIDEOIN_F_CT_CTRL_ROLL_RELATIVE 0x00004000 /* D14: Roll (Relative) */ +#define VRDE_VIDEOIN_F_CT_CTRL_RESERVED1 0x00008000 /* D15: Reserved */ +#define VRDE_VIDEOIN_F_CT_CTRL_RESERVED2 0x00010000 /* D16: Reserved */ +#define VRDE_VIDEOIN_F_CT_CTRL_FOCUS_AUTO 0x00020000 /* D17: Focus, Auto */ +#define VRDE_VIDEOIN_F_CT_CTRL_PRIVACY 0x00040000 /* D18: Privacy */ + +/* VRDEVIDEOINDEVICEDESC::fu32ProcessingControls */ +#define VRDE_VIDEOIN_F_PU_CTRL_BRIGHTNESS 0x00000001 /* D0: Brightness */ +#define VRDE_VIDEOIN_F_PU_CTRL_CONTRAST 0x00000002 /* D1: Contrast */ +#define VRDE_VIDEOIN_F_PU_CTRL_HUE 0x00000004 /* D2: Hue */ +#define VRDE_VIDEOIN_F_PU_CTRL_SATURATION 0x00000008 /* D3: Saturation */ +#define VRDE_VIDEOIN_F_PU_CTRL_SHARPNESS 0x00000010 /* D4: Sharpness */ +#define VRDE_VIDEOIN_F_PU_CTRL_GAMMA 0x00000020 /* D5: Gamma */ +#define VRDE_VIDEOIN_F_PU_CTRL_WHITE_BALANCE_TEMPERATURE 0x00000040 /* D6: White Balance Temperature */ +#define VRDE_VIDEOIN_F_PU_CTRL_WHITE_BALANCE_COMPONENT 0x00000080 /* D7: White Balance Component */ +#define VRDE_VIDEOIN_F_PU_CTRL_BACKLIGHT_COMPENSATION 0x00000100 /* D8: Backlight Compensation */ +#define VRDE_VIDEOIN_F_PU_CTRL_GAIN 0x00000200 /* D9: Gain */ +#define VRDE_VIDEOIN_F_PU_CTRL_POWER_LINE_FREQUENCY 0x00000400 /* D10: Power Line Frequency */ +#define VRDE_VIDEOIN_F_PU_CTRL_HUE_AUTO 0x00000800 /* D11: Hue, Auto */ +#define VRDE_VIDEOIN_F_PU_CTRL_WHITE_BALANCE_TEMPERATURE_AUTO 0x00001000 /* D12: White Balance Temperature, Auto */ +#define VRDE_VIDEOIN_F_PU_CTRL_WHITE_BALANCE_COMPONENT_AUTO 0x00002000 /* D13: White Balance Component, Auto */ +#define VRDE_VIDEOIN_F_PU_CTRL_DIGITAL_MULTIPLIER 0x00004000 /* D14: Digital Multiplier */ +#define VRDE_VIDEOIN_F_PU_CTRL_DIGITAL_MULTIPLIER_LIMIT 0x00008000 /* D15: Digital Multiplier Limit */ + +/* VRDEVIDEOINDEVICEDESC::fu8DeviceCaps */ +#define VRDE_VIDEOIN_F_DEV_CAP_DYNAMICCHANGE 0x01 /* Whether dynamic format change is supported. */ +#define VRDE_VIDEOIN_F_DEV_CAP_TRIGGER 0x02 /* Whether hardware triggering is supported. */ +#define VRDE_VIDEOIN_F_DEV_CAP_TRIGGER_USAGE 0x04 /* 0 - still image, 1 - generic button event.*/ + +/* VRDEVIDEOINDEVICEDESC extended description. */ +typedef struct VRDEVIDEOINDEVICEEXT +{ + uint32_t fu32Fields; + /* One or more VRDEVIDEOINDEVICEFIELD follow. */ +} VRDEVIDEOINDEVICEEXT; + +typedef struct VRDEVIDEOINDEVICEFIELDHDR +{ + uint16_t cbField; /* Number of bytes reserved for this field. */ +} VRDEVIDEOINDEVICEFIELDHDR; + +/* VRDEVIDEOINDEVICEDESC::fu32Fields */ +#define VRDE_VIDEOIN_F_DEV_EXT_NAME 0x00000001 /* Utf8 device name. */ +#define VRDE_VIDEOIN_F_DEV_EXT_SERIAL 0x00000002 /* Utf8 device serial number. */ + +/* The video format descriptor. */ +typedef struct VRDEVIDEOINFORMATDESC +{ + uint16_t cbFormat; /* Size of the structure including cbFormat and format specific data. */ + uint8_t u8FormatId; /* The unique identifier of the format on the client. */ + uint8_t u8FormatType; /* MJPEG etc. VRDE_VIDEOIN_FORMAT_* */ + uint8_t u8FormatFlags; /* VRDE_VIDEOIN_F_FMT_* */ + uint8_t u8NumFrames; /* Number of following VRDEVIDEOINFRAMEDESC structures. */ + uint16_t u16Reserved; /* Must be set to 0. */ + /* Other format specific data may follow. */ + /* An array of VRDEVIDEOINFRAMEDESC follows. */ +} VRDEVIDEOINFORMATDESC; + +/* VRDEVIDEOINFORMATDESC::u8FormatType */ +#define VRDE_VIDEOIN_FORMAT_UNCOMPRESSED 0x04 +#define VRDE_VIDEOIN_FORMAT_MJPEG 0x06 +#define VRDE_VIDEOIN_FORMAT_MPEG2TS 0x0A +#define VRDE_VIDEOIN_FORMAT_DV 0x0C +#define VRDE_VIDEOIN_FORMAT_FRAME_BASED 0x10 +#define VRDE_VIDEOIN_FORMAT_STREAM_BASED 0x12 + +/* VRDEVIDEOINFORMATDESC::u8FormatFlags. */ +#define VRDE_VIDEOIN_F_FMT_GENERATEKEYFRAME 0x01 /* Supports Generate Key Frame */ +#define VRDE_VIDEOIN_F_FMT_UPDATEFRAMESEGMENT 0x02 /* Supports Update Frame Segment */ +#define VRDE_VIDEOIN_F_FMT_COPYPROTECT 0x04 /* If duplication should be restricted. */ +#define VRDE_VIDEOIN_F_FMT_COMPQUALITY 0x08 /* If the format supports an adjustable compression quality. */ + +typedef struct VRDEVIDEOINFRAMEDESC +{ + uint16_t cbFrame; /* Size of the structure including cbFrame and frame specific data. */ + uint8_t u8FrameId; /* The unique identifier of the frame for the corresponding format on the client. */ + uint8_t u8FrameFlags; + uint16_t u16Width; + uint16_t u16Height; + uint32_t u32NumFrameIntervals; /* The number of supported frame intervals. */ + uint32_t u32MinFrameInterval; /* Shortest frame interval supported (at highest frame rate), in 100ns units. */ + uint32_t u32MaxFrameInterval; /* Longest frame interval supported (at lowest frame rate), in 100ns units. */ + /* Supported frame intervals (in 100ns units) follow if VRDE_VIDEOIN_F_FRM_DISCRETE_INTERVALS is set. + * uint32_t au32FrameIntervals[u32NumFrameIntervals]; + */ + /* Supported min and max bitrate in bits per second follow if VRDE_VIDEOIN_F_FRM_BITRATE is set. + * uint32_t u32MinBitRate; + * uint32_t u32MaxBitRate; + */ + /* Other frame specific data may follow. */ +} VRDEVIDEOINFRAMEDESC; + +/* VRDEVIDEOINFRAMEDESC::u8FrameFlags. */ +#define VRDE_VIDEOIN_F_FRM_STILL 0x01 /* If still images are supported for this frame. */ +#define VRDE_VIDEOIN_F_FRM_DISCRETE_INTERVALS 0x02 /* If the discrete intervals list is included. */ +#define VRDE_VIDEOIN_F_FRM_BITRATE 0x04 /* If the bitrate fields are included. */ +#define VRDE_VIDEOIN_F_FRM_SIZE_OF_FIELDS 0x08 /* If the all optional fields start with 16 bit field size. */ + +/* + * Controls. + * + * The same structures are used for both SET and GET requests. + * Requests are async. A callback is invoked, when the client returns a reply. + * A control change notification also uses these structures. + * + * If a control request can not be fulfilled, then VRDE_VIDEOIN_CTRLHDR_F_FAIL + * will be set and u8Status contains the error code. This replaces the VC_REQUEST_ERROR_CODE_CONTROL. + * + * If the client receives an unsupported control, then the client must ignore it. + * That is the control request must not affect the client in any way. + * The client may send a VRDEVIDEOINCTRLHDR response for the unsupported control with: + * u16ControlSelector = the received value; + * u16RequestType = the received value; + * u16ParmSize = 0; + * u8Flags = VRDE_VIDEOIN_CTRLHDR_F_FAIL; + * u8Status = VRDE_VIDEOIN_CTRLHDR_STATUS_INVALIDCONTROL; + */ + +typedef struct VRDEVIDEOINCTRLHDR +{ + uint16_t u16ControlSelector; /* VRDE_VIDEOIN_CTRLSEL_* */ + uint16_t u16RequestType; /* VRDE_VIDEOIN_CTRLREQ_* */ + uint16_t u16ParmSize; /* The size of the control specific parameters. */ + uint8_t u8Flags; /* VRDE_VIDEOIN_CTRLHDR_F_* */ + uint8_t u8Status; /* VRDE_VIDEOIN_CTRLHDR_STATUS_* */ + /* Control specific data follows. */ +} VRDEVIDEOINCTRLHDR; + +/* Control request types: VRDEVIDEOINCTRLHDR::u16RequestType. */ +#define VRDE_VIDEOIN_CTRLREQ_UNDEFINED 0x00 +#define VRDE_VIDEOIN_CTRLREQ_SET_CUR 0x01 +#define VRDE_VIDEOIN_CTRLREQ_GET_CUR 0x81 +#define VRDE_VIDEOIN_CTRLREQ_GET_MIN 0x82 +#define VRDE_VIDEOIN_CTRLREQ_GET_MAX 0x83 +#define VRDE_VIDEOIN_CTRLREQ_GET_RES 0x84 +#define VRDE_VIDEOIN_CTRLREQ_GET_LEN 0x85 +#define VRDE_VIDEOIN_CTRLREQ_GET_INFO 0x86 +#define VRDE_VIDEOIN_CTRLREQ_GET_DEF 0x87 + +/* VRDEVIDEOINCTRLHDR::u8Flags */ +#define VRDE_VIDEOIN_CTRLHDR_F_NOTIFY 0x01 /* Control change notification, the attribute is derived from u16RequestType and F_FAIL. */ +#define VRDE_VIDEOIN_CTRLHDR_F_FAIL 0x02 /* The operation failed. Error code is in u8Status. */ + +/* VRDEVIDEOINCTRLHDR::u8Status if the VRDE_VIDEOIN_CTRLHDR_F_FAIL is set. */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_SUCCESS 0x00 /**/ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_NOTREADY 0x01 /* Not ready */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_WRONGSTATE 0x02 /* Wrong state */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_POWER 0x03 /* Power */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_OUTOFRANGE 0x04 /* Out of range */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_INVALIDUNIT 0x05 /* Invalid unit */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_INVALIDCONTROL 0x06 /* Invalid control */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_INVALIDREQUEST 0x07 /* Invalid request */ +#define VRDE_VIDEOIN_CTRLHDR_STATUS_UNKNOWN 0xFF /* Unknown */ + +/* Control selectors. 16 bit. High byte is the category. Low byte is the identifier.*/ +#ifdef RT_MAKE_U16 +#define VRDE_VIDEOIN_CTRLSEL_MAKE(Lo, Hi) RT_MAKE_U16(Lo, Hi) +#else +#define VRDE_VIDEOIN_CTRLSEL_MAKE(Lo, Hi) ((uint16_t)( (uint16_t)((uint8_t)(Hi)) << 8 | (uint8_t)(Lo) )) +#endif + +#define VRDE_VIDEOIN_CTRLSEL_VC(a) VRDE_VIDEOIN_CTRLSEL_MAKE(a, 0x01) +#define VRDE_VIDEOIN_CTRLSEL_CT(a) VRDE_VIDEOIN_CTRLSEL_MAKE(a, 0x02) +#define VRDE_VIDEOIN_CTRLSEL_PU(a) VRDE_VIDEOIN_CTRLSEL_MAKE(a, 0x03) +#define VRDE_VIDEOIN_CTRLSEL_VS(a) VRDE_VIDEOIN_CTRLSEL_MAKE(a, 0x04) +#define VRDE_VIDEOIN_CTRLSEL_HW(a) VRDE_VIDEOIN_CTRLSEL_MAKE(a, 0x05) +#define VRDE_VIDEOIN_CTRLSEL_PROT(a) VRDE_VIDEOIN_CTRLSEL_MAKE(a, 0x06) + +#define VRDE_VIDEOIN_CTRLSEL_VC_VIDEO_POWER_MODE_CONTROL VRDE_VIDEOIN_CTRLSEL_VC(0x01) + +#define VRDE_VIDEOIN_CTRLSEL_CT_UNDEFINED VRDE_VIDEOIN_CTRLSEL_CT(0x00) +#define VRDE_VIDEOIN_CTRLSEL_CT_SCANNING_MODE VRDE_VIDEOIN_CTRLSEL_CT(0x01) +#define VRDE_VIDEOIN_CTRLSEL_CT_AE_MODE VRDE_VIDEOIN_CTRLSEL_CT(0x02) +#define VRDE_VIDEOIN_CTRLSEL_CT_AE_PRIORITY VRDE_VIDEOIN_CTRLSEL_CT(0x03) +#define VRDE_VIDEOIN_CTRLSEL_CT_EXPOSURE_TIME_ABSOLUTE VRDE_VIDEOIN_CTRLSEL_CT(0x04) +#define VRDE_VIDEOIN_CTRLSEL_CT_EXPOSURE_TIME_RELATIVE VRDE_VIDEOIN_CTRLSEL_CT(0x05) +#define VRDE_VIDEOIN_CTRLSEL_CT_FOCUS_ABSOLUTE VRDE_VIDEOIN_CTRLSEL_CT(0x06) +#define VRDE_VIDEOIN_CTRLSEL_CT_FOCUS_RELATIVE VRDE_VIDEOIN_CTRLSEL_CT(0x07) +#define VRDE_VIDEOIN_CTRLSEL_CT_FOCUS_AUTO VRDE_VIDEOIN_CTRLSEL_CT(0x08) +#define VRDE_VIDEOIN_CTRLSEL_CT_IRIS_ABSOLUTE VRDE_VIDEOIN_CTRLSEL_CT(0x09) +#define VRDE_VIDEOIN_CTRLSEL_CT_IRIS_RELATIVE VRDE_VIDEOIN_CTRLSEL_CT(0x0A) +#define VRDE_VIDEOIN_CTRLSEL_CT_ZOOM_ABSOLUTE VRDE_VIDEOIN_CTRLSEL_CT(0x0B) +#define VRDE_VIDEOIN_CTRLSEL_CT_ZOOM_RELATIVE VRDE_VIDEOIN_CTRLSEL_CT(0x0C) +#define VRDE_VIDEOIN_CTRLSEL_CT_PANTILT_ABSOLUTE VRDE_VIDEOIN_CTRLSEL_CT(0x0D) +#define VRDE_VIDEOIN_CTRLSEL_CT_PANTILT_RELATIVE VRDE_VIDEOIN_CTRLSEL_CT(0x0E) +#define VRDE_VIDEOIN_CTRLSEL_CT_ROLL_ABSOLUTE VRDE_VIDEOIN_CTRLSEL_CT(0x0F) +#define VRDE_VIDEOIN_CTRLSEL_CT_ROLL_RELATIVE VRDE_VIDEOIN_CTRLSEL_CT(0x10) +#define VRDE_VIDEOIN_CTRLSEL_CT_PRIVACY VRDE_VIDEOIN_CTRLSEL_CT(0x11) + +#define VRDE_VIDEOIN_CTRLSEL_PU_UNDEFINED VRDE_VIDEOIN_CTRLSEL_PU(0x00) +#define VRDE_VIDEOIN_CTRLSEL_PU_BACKLIGHT_COMPENSATION VRDE_VIDEOIN_CTRLSEL_PU(0x01) +#define VRDE_VIDEOIN_CTRLSEL_PU_BRIGHTNESS VRDE_VIDEOIN_CTRLSEL_PU(0x02) +#define VRDE_VIDEOIN_CTRLSEL_PU_CONTRAST VRDE_VIDEOIN_CTRLSEL_PU(0x03) +#define VRDE_VIDEOIN_CTRLSEL_PU_GAIN VRDE_VIDEOIN_CTRLSEL_PU(0x04) +#define VRDE_VIDEOIN_CTRLSEL_PU_POWER_LINE_FREQUENCY VRDE_VIDEOIN_CTRLSEL_PU(0x05) +#define VRDE_VIDEOIN_CTRLSEL_PU_HUE VRDE_VIDEOIN_CTRLSEL_PU(0x06) +#define VRDE_VIDEOIN_CTRLSEL_PU_SATURATION VRDE_VIDEOIN_CTRLSEL_PU(0x07) +#define VRDE_VIDEOIN_CTRLSEL_PU_SHARPNESS VRDE_VIDEOIN_CTRLSEL_PU(0x08) +#define VRDE_VIDEOIN_CTRLSEL_PU_GAMMA VRDE_VIDEOIN_CTRLSEL_PU(0x09) +#define VRDE_VIDEOIN_CTRLSEL_PU_WHITE_BALANCE_TEMPERATURE VRDE_VIDEOIN_CTRLSEL_PU(0x0A) +#define VRDE_VIDEOIN_CTRLSEL_PU_WHITE_BALANCE_TEMPERATURE_AUTO VRDE_VIDEOIN_CTRLSEL_PU(0x0B) +#define VRDE_VIDEOIN_CTRLSEL_PU_WHITE_BALANCE_COMPONENT VRDE_VIDEOIN_CTRLSEL_PU(0x0C) +#define VRDE_VIDEOIN_CTRLSEL_PU_WHITE_BALANCE_COMPONENT_AUTO VRDE_VIDEOIN_CTRLSEL_PU(0x0D) +#define VRDE_VIDEOIN_CTRLSEL_PU_DIGITAL_MULTIPLIER VRDE_VIDEOIN_CTRLSEL_PU(0x0E) +#define VRDE_VIDEOIN_CTRLSEL_PU_DIGITAL_MULTIPLIER_LIMIT VRDE_VIDEOIN_CTRLSEL_PU(0x0F) +#define VRDE_VIDEOIN_CTRLSEL_PU_HUE_AUTO VRDE_VIDEOIN_CTRLSEL_PU(0x10) +#define VRDE_VIDEOIN_CTRLSEL_PU_ANALOG_VIDEO_STANDARD VRDE_VIDEOIN_CTRLSEL_PU(0x11) +#define VRDE_VIDEOIN_CTRLSEL_PU_ANALOG_LOCK_STATUS VRDE_VIDEOIN_CTRLSEL_PU(0x12) + +#define VRDE_VIDEOIN_CTRLSEL_VS_UNDEFINED VRDE_VIDEOIN_CTRLSEL_VS(0x00) +#define VRDE_VIDEOIN_CTRLSEL_VS_SETUP VRDE_VIDEOIN_CTRLSEL_VS(0x01) +#define VRDE_VIDEOIN_CTRLSEL_VS_OFF VRDE_VIDEOIN_CTRLSEL_VS(0x02) +#define VRDE_VIDEOIN_CTRLSEL_VS_ON VRDE_VIDEOIN_CTRLSEL_VS(0x03) +#define VRDE_VIDEOIN_CTRLSEL_VS_STILL_IMAGE_TRIGGER VRDE_VIDEOIN_CTRLSEL_VS(0x05) +#define VRDE_VIDEOIN_CTRLSEL_VS_STREAM_ERROR_CODE VRDE_VIDEOIN_CTRLSEL_VS(0x06) +#define VRDE_VIDEOIN_CTRLSEL_VS_GENERATE_KEY_FRAME VRDE_VIDEOIN_CTRLSEL_VS(0x07) +#define VRDE_VIDEOIN_CTRLSEL_VS_UPDATE_FRAME_SEGMENT VRDE_VIDEOIN_CTRLSEL_VS(0x08) +#define VRDE_VIDEOIN_CTRLSEL_VS_SYNCH_DELAY VRDE_VIDEOIN_CTRLSEL_VS(0x09) + +#define VRDE_VIDEOIN_CTRLSEL_HW_BUTTON VRDE_VIDEOIN_CTRLSEL_HW(0x01) + +#define VRDE_VIDEOIN_CTRLSEL_PROT_PING VRDE_VIDEOIN_CTRLSEL_PROT(0x01) +#define VRDE_VIDEOIN_CTRLSEL_PROT_SAMPLING VRDE_VIDEOIN_CTRLSEL_PROT(0x02) +#define VRDE_VIDEOIN_CTRLSEL_PROT_FRAMES VRDE_VIDEOIN_CTRLSEL_PROT(0x03) + +typedef struct VRDEVIDEOINCTRL_VIDEO_POWER_MODE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8DevicePowerMode; +} VRDEVIDEOINCTRL_VIDEO_POWER_MODE; + +typedef struct VRDEVIDEOINCTRL_CT_SCANNING_MODE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8ScanningMode; +} VRDEVIDEOINCTRL_CT_SCANNING_MODE; + +typedef struct VRDEVIDEOINCTRL_CT_AE_MODE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8AutoExposureMode; +} VRDEVIDEOINCTRL_CT_AE_MODE; + +typedef struct VRDEVIDEOINCTRL_CT_AE_PRIORITY +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8AutoExposurePriority; +} VRDEVIDEOINCTRL_CT_AE_PRIORITY; + +typedef struct VRDEVIDEOINCTRL_CT_EXPOSURE_TIME_ABSOLUTE +{ + VRDEVIDEOINCTRLHDR hdr; + uint32_t u32ExposureTimeAbsolute; +} VRDEVIDEOINCTRL_CT_EXPOSURE_TIME_ABSOLUTE; + +typedef struct VRDEVIDEOINCTRL_CT_EXPOSURE_TIME_RELATIVE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8ExposureTimeRelative; +} VRDEVIDEOINCTRL_CT_EXPOSURE_TIME_RELATIVE; + +typedef struct VRDEVIDEOINCTRL_CT_FOCUS_ABSOLUTE +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16FocusAbsolute; +} VRDEVIDEOINCTRL_CT_FOCUS_ABSOLUTE; + +typedef struct VRDEVIDEOINCTRL_CT_FOCUS_RELATIVE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8FocusRelative; + uint8_t u8Speed; +} VRDEVIDEOINCTRL_CT_FOCUS_RELATIVE; + +typedef struct VRDEVIDEOINCTRL_CT_FOCUS_AUTO +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8FocusAuto; +} VRDEVIDEOINCTRL_CT_FOCUS_AUTO; + +typedef struct VRDEVIDEOINCTRL_CT_IRIS_ABSOLUTE +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16IrisAbsolute; +} VRDEVIDEOINCTRL_CT_IRIS_ABSOLUTE; + +typedef struct VRDEVIDEOINCTRL_CT_IRIS_RELATIVE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8IrisRelative; +} VRDEVIDEOINCTRL_CT_IRIS_RELATIVE; + +typedef struct VRDEVIDEOINCTRL_CT_ZOOM_ABSOLUTE +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16ZoomAbsolute; +} VRDEVIDEOINCTRL_CT_ZOOM_ABSOLUTE; + +typedef struct VRDEVIDEOINCTRL_CT_ZOOM_RELATIVE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8Zoom; + uint8_t u8DigitalZoom; + uint8_t u8Speed; +} VRDEVIDEOINCTRL_CT_ZOOM_RELATIVE; + +typedef struct VRDEVIDEOINCTRL_CT_PANTILT_ABSOLUTE +{ + VRDEVIDEOINCTRLHDR hdr; + uint32_t u32PanAbsolute; + uint32_t u32TiltAbsolute; +} VRDEVIDEOINCTRL_CT_PANTILT_ABSOLUTE; + +typedef struct VRDEVIDEOINCTRL_CT_PANTILT_RELATIVE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8PanRelative; + uint8_t u8PanSpeed; + uint8_t u8TiltRelative; + uint8_t u8TiltSpeed; +} VRDEVIDEOINCTRL_CT_PANTILT_RELATIVE; + +typedef struct VRDEVIDEOINCTRL_CT_ROLL_ABSOLUTE +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16RollAbsolute; +} VRDEVIDEOINCTRL_CT_ROLL_ABSOLUTE; + +typedef struct VRDEVIDEOINCTRL_CT_ROLL_RELATIVE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8RollRelative; + uint8_t u8Speed; +} VRDEVIDEOINCTRL_CT_ROLL_RELATIVE; + +typedef struct VRDEVIDEOINCTRL_CT_PRIVACY_MODE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8Privacy; +} VRDEVIDEOINCTRL_CT_PRIVACY_MODE; + +typedef struct VRDEVIDEOINCTRL_PU_BACKLIGHT_COMPENSATION +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16BacklightCompensation; +} VRDEVIDEOINCTRL_PU_BACKLIGHT_COMPENSATION; + +typedef struct VRDEVIDEOINCTRL_PU_BRIGHTNESS +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Brightness; +} VRDEVIDEOINCTRL_PU_BRIGHTNESS; + +typedef struct VRDEVIDEOINCTRL_PU_CONTRAST +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Contrast; +} VRDEVIDEOINCTRL_PU_CONTRAST; + +typedef struct VRDEVIDEOINCTRL_PU_GAIN +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Gain; +} VRDEVIDEOINCTRL_PU_GAIN; + +typedef struct VRDEVIDEOINCTRL_PU_POWER_LINE_FREQUENCY +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16PowerLineFrequency; +} VRDEVIDEOINCTRL_PU_POWER_LINE_FREQUENCY; + +typedef struct VRDEVIDEOINCTRL_PU_HUE +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Hue; +} VRDEVIDEOINCTRL_PU_HUE; + +typedef struct VRDEVIDEOINCTRL_PU_HUE_AUTO +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8HueAuto; +} VRDEVIDEOINCTRL_PU_HUE_AUTO; + +typedef struct VRDEVIDEOINCTRL_PU_SATURATION +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Saturation; +} VRDEVIDEOINCTRL_PU_SATURATION; + +typedef struct VRDEVIDEOINCTRL_PU_SHARPNESS +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Sharpness; +} VRDEVIDEOINCTRL_PU_SHARPNESS; + +typedef struct VRDEVIDEOINCTRL_PU_GAMMA +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Gamma; +} VRDEVIDEOINCTRL_PU_GAMMA; + +typedef struct VRDEVIDEOINCTRL_PU_WHITE_BALANCE_TEMPERATURE +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16WhiteBalanceTemperature; +} VRDEVIDEOINCTRL_PU_WHITE_BALANCE_TEMPERATURE; + +typedef struct VRDEVIDEOINCTRL_PU_WHITE_BALANCE_TEMPERATURE_AUTO +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8WhiteBalanceTemperatureAuto; +} VRDEVIDEOINCTRL_PU_WHITE_BALANCE_TEMPERATURE_AUTO; + +typedef struct VRDEVIDEOINCTRL_PU_WHITE_BALANCE_COMPONENT +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16WhiteBalanceBlue; + uint16_t u16WhiteBalanceRed; +} VRDEVIDEOINCTRL_PU_WHITE_BALANCE_COMPONENT; + +typedef struct VRDEVIDEOINCTRL_PU_WHITE_BALANCE_COMPONENT_AUTO +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8WhiteBalanceComponentAuto; +} VRDEVIDEOINCTRL_PU_WHITE_BALANCE_COMPONENT_AUTO; + +typedef struct VRDEVIDEOINCTRL_PU_DIGITAL_MULTIPLIER +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16MultiplierStep; +} VRDEVIDEOINCTRL_PU_DIGITAL_MULTIPLIER; + +typedef struct VRDEVIDEOINCTRL_PU_DIGITAL_MULTIPLIER_LIMIT +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16MultiplierLimit; +} VRDEVIDEOINCTRL_PU_DIGITAL_MULTIPLIER_LIMIT; + +typedef struct VRDEVIDEOINCTRL_PU_ANALOG_VIDEO_STANDARD +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8VideoStandard; +} VRDEVIDEOINCTRL_PU_ANALOG_VIDEO_STANDARD; + +typedef struct VRDEVIDEOINCTRL_PU_ANALOG_LOCK_STATUS +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8Status; +} VRDEVIDEOINCTRL_PU_ANALOG_LOCK_STATUS; + +/* Set streaming parameters. The actual streaming will be enabled by VS_ON. */ +#define VRDEVIDEOINCTRL_F_VS_SETUP_FID 0x01 +#define VRDEVIDEOINCTRL_F_VS_SETUP_EOF 0x02 + +typedef struct VRDEVIDEOINCTRL_VS_SETUP +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8FormatId; /* The format id on the client: VRDEVIDEOINFORMATDESC::u8FormatId. */ + uint8_t u8FramingInfo; /* VRDEVIDEOINCTRL_F_VS_SETUP_*. Set by the client. */ + uint16_t u16Width; + uint16_t u16Height; + uint32_t u32FrameInterval; /* Frame interval in 100 ns units, 0 means a still image capture. + * The client may choose a different interval if this value is + * not supported. + */ + uint16_t u16CompQuality; /* 0 .. 10000 = 0 .. 100%. + * Applicable if the format has VRDE_VIDEOIN_F_FMT_COMPQUALITY, + * otherwise this field is ignored. + */ + uint16_t u16Delay; /* Latency in ms from video data capture to presentation on the channel. + * Set by the client, read by the server. + */ + uint32_t u32ClockFrequency; /* @todo just all clocks in 100ns units? */ +} VRDEVIDEOINCTRL_VS_SETUP; + +/* Stop sending video frames. */ +typedef struct VRDEVIDEOINCTRL_VS_OFF +{ + VRDEVIDEOINCTRLHDR hdr; +} VRDEVIDEOINCTRL_VS_OFF; + +/* Start sending video frames with parameters set by VS_SETUP. */ +typedef struct VRDEVIDEOINCTRL_VS_ON +{ + VRDEVIDEOINCTRLHDR hdr; +} VRDEVIDEOINCTRL_VS_ON; + +typedef struct VRDEVIDEOINCTRL_VS_STILL_IMAGE_TRIGGER +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8Trigger; +} VRDEVIDEOINCTRL_VS_STILL_IMAGE_TRIGGER; + +typedef struct VRDEVIDEOINCTRL_VS_STREAM_ERROR_CODE +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8StreamErrorCode; +} VRDEVIDEOINCTRL_VS_STREAM_ERROR_CODE; + +typedef struct VRDEVIDEOINCTRL_VS_GENERATE_KEY_FRAME +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8GenerateKeyFrame; +} VRDEVIDEOINCTRL_VS_GENERATE_KEY_FRAME; + +typedef struct VRDEVIDEOINCTRL_VS_UPDATE_FRAME_SEGMENT +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8StartFrameSegment; + uint8_t u8EndFrameSegment; +} VRDEVIDEOINCTRL_VS_UPDATE_FRAME_SEGMENT; + +typedef struct VRDEVIDEOINCTRL_VS_SYNCH_DELAY +{ + VRDEVIDEOINCTRLHDR hdr; + uint16_t u16Delay; +} VRDEVIDEOINCTRL_VS_SYNCH_DELAY; + +/* A hardware button was pressed/released on the device. */ +typedef struct VRDEVIDEOINCTRL_HW_BUTTON +{ + VRDEVIDEOINCTRLHDR hdr; + uint8_t u8Pressed; +} VRDEVIDEOINCTRL_HW_BUTTON; + +typedef struct VRDEVIDEOINCTRL_PROT_PING +{ + VRDEVIDEOINCTRLHDR hdr; + uint32_t u32Timestamp; /* Set in the request and the same value must be send back in the response. */ +} VRDEVIDEOINCTRL_PROT_PING; + +typedef struct VRDEVIDEOINCTRL_PROT_SAMPLING +{ + VRDEVIDEOINCTRLHDR hdr; + uint32_t fu32SampleStart; /* Which parameters must be sampled VRDEVIDEOINCTRL_F_PROT_SAMPLING_*. */ + uint32_t fu32SampleStop; /* Which parameters to disable VRDEVIDEOINCTRL_F_PROT_SAMPLING_*. + * If both Start and Stop is set, then restart the sampling. + */ + uint32_t u32PeriodMS; /* Sampling period in milliseconds. Applies to all samples in fu32SampleStart. + * Not mandatory, the actual sampling period may be different. + */ +} VRDEVIDEOINCTRL_PROT_SAMPLING; + +#define VRDEVIDEOINCTRL_F_PROT_SAMPLING_FRAMES_SOURCE 0x00000001 /* Periodic VRDEVIDEOINCTRL_PROT_FRAMES samples */ +#define VRDEVIDEOINCTRL_F_PROT_SAMPLING_FRAMES_CLIENT_OUT 0x00000002 /* Periodic VRDEVIDEOINCTRL_PROT_FRAMES samples */ + +typedef struct VRDEVIDEOINCTRL_PROT_FRAMES +{ + VRDEVIDEOINCTRLHDR hdr; /* Note: the message should be sent as VRDE_VIDEOIN_FN_CONTROL_NOTIFY. */ + uint32_t u32Sample; /* Which sample is this, one of VRDEVIDEOINCTRL_F_PROT_SAMPLING_*. */ + uint32_t u32TimestampMS; /* When the period started, milliseconds since the start of sampling. */ + uint32_t u32PeriodMS; /* Actual period during which the frames were counted in milliseconds. + * This may be different from VRDEVIDEOINCTRL_PROT_SAMPLING::u32PeriodMS. + */ + uint32_t u32FramesCount; /* How many frames per u32PeriodMS milliseconds. */ +} VRDEVIDEOINCTRL_PROT_FRAMES; + + +/* + * Payload transfers. How frames are sent to the server: + * the client send a PAYLOAD packet, which has the already set format. + * The server enables the transfers by sending VRDEVIDEOINCTRL_VS_ON. + */ + +/* Payload header */ +typedef struct VRDEVIDEOINPAYLOADHDR +{ + uint8_t u8HeaderLength; /* Entire header. */ + uint8_t u8HeaderInfo; /* VRDE_VIDEOIN_PAYLOAD_F_* */ + uint32_t u32PresentationTime; /* @todo define this */ + uint32_t u32SourceTimeClock; /* @todo At the moment when the frame was sent to the channel. + * Allows the server to measure clock drift. + */ + uint16_t u16Reserved; /* @todo */ +} VRDEVIDEOINPAYLOADHDR; + +/* VRDEVIDEOINPAYLOADHDR::u8HeaderInfo */ +#define VRDE_VIDEOIN_PAYLOAD_F_FID 0x01 /* Frame ID */ +#define VRDE_VIDEOIN_PAYLOAD_F_EOF 0x02 /* End of Frame */ +#define VRDE_VIDEOIN_PAYLOAD_F_PTS 0x04 /* Presentation Time */ +#define VRDE_VIDEOIN_PAYLOAD_F_SCR 0x08 /* Source Clock Reference */ +#define VRDE_VIDEOIN_PAYLOAD_F_RES 0x10 /* Reserved */ +#define VRDE_VIDEOIN_PAYLOAD_F_STI 0x20 /* Still Image */ +#define VRDE_VIDEOIN_PAYLOAD_F_ERR 0x40 /* Error */ +#define VRDE_VIDEOIN_PAYLOAD_F_EOH 0x80 /* End of header */ + + +/* + * The network channel specification. + */ + +/* + * The protocol uses a dynamic RDP channel. + * Everything is little-endian. + */ + +/* The dynamic RDP channel name. */ +#define VRDE_VIDEOIN_CHANNEL "RVIDEOIN" + +/* Major functions. */ +#define VRDE_VIDEOIN_FN_NEGOTIATE 0x0000 /* Version and capabilities check. */ +#define VRDE_VIDEOIN_FN_NOTIFY 0x0001 /* Device attach/detach from the client. */ +#define VRDE_VIDEOIN_FN_DEVICEDESC 0x0002 /* Query device description. */ +#define VRDE_VIDEOIN_FN_CONTROL 0x0003 /* Control the device and start/stop video input. + * This function is used for sending a request and + * the corresponding response. + */ +#define VRDE_VIDEOIN_FN_CONTROL_NOTIFY 0x0004 /* The client reports a control change, etc. + * This function indicated that the message is + * not a response to a CONTROL request. + */ +#define VRDE_VIDEOIN_FN_FRAME 0x0005 /* Frame from the client. */ + +/* Status codes. */ +#define VRDE_VIDEOIN_STATUS_SUCCESS 0 /* Function completed successfully. */ +#define VRDE_VIDEOIN_STATUS_FAILED 1 /* Failed for some reason. */ + +typedef struct VRDEVIDEOINMSGHDR +{ + uint32_t u32Length; /* The length of the message in bytes, including the header. */ + uint32_t u32DeviceId; /* The client's device id. */ + uint32_t u32MessageId; /* Unique id assigned by the server. The client must send a reply with the same id. + * If the client initiates a request, then this must be set to 0, because there is + * currently no client requests, which would require a response from the server. + */ + uint16_t u16FunctionId; /* VRDE_VIDEOIN_FN_* */ + uint16_t u16Status; /* The result of a request. VRDE_VIDEOIN_STATUS_*. */ +} VRDEVIDEOINMSGHDR; +ASSERTSIZE(VRDEVIDEOINMSGHDR, 16) + +/* + * VRDE_VIDEOIN_FN_NEGOTIATE + * + * Sent by the server when the channel is established and the client replies with its capabilities. + */ +#define VRDE_VIDEOIN_NEGOTIATE_VERSION 1 + +/* VRDEVIDEOINMSG_NEGOTIATE::fu32Capabilities */ +#define VRDE_VIDEOIN_NEGOTIATE_CAP_VOID 0x00000000 +#define VRDE_VIDEOIN_NEGOTIATE_CAP_PROT 0x00000001 /* Supports VRDE_VIDEOIN_CTRLSEL_PROT_* controls. */ + +typedef struct VRDEVIDEOINMSG_NEGOTIATE +{ + VRDEVIDEOINMSGHDR hdr; + uint32_t u32Version; /* VRDE_VIDEOIN_NEGOTIATE_VERSION */ + uint32_t fu32Capabilities; /* VRDE_VIDEOIN_NEGOTIATE_CAP_* */ +} VRDEVIDEOINMSG_NEGOTIATE; + +/* + * VRDE_VIDEOIN_FN_NOTIFY + * + * Sent by the client when a webcam is attached or detached. + * The client must send the ATTACH notification for each webcam, which is + * already connected to the client when the VIDEOIN channel is established. + */ +#define VRDE_VIDEOIN_NOTIFY_EVENT_ATTACH 0 +#define VRDE_VIDEOIN_NOTIFY_EVENT_DETACH 1 +#define VRDE_VIDEOIN_NOTIFY_EVENT_NEGOTIATE 2 /* Negotiate again with the client. */ + +typedef struct VRDEVIDEOINMSG_NOTIFY +{ + VRDEVIDEOINMSGHDR hdr; + uint32_t u32NotifyEvent; /* VRDE_VIDEOIN_NOTIFY_EVENT_* */ + /* Event specific data may follow. The underlying protocol provides the length of the message. */ +} VRDEVIDEOINMSG_NOTIFY; + +/* + * VRDE_VIDEOIN_FN_DEVICEDESC + * + * The server queries the description of a device. + */ +typedef struct VRDEVIDEOINMSG_DEVICEDESC_REQ +{ + VRDEVIDEOINMSGHDR hdr; +} VRDEVIDEOINMSG_DEVICEDESC_REQ; + +typedef struct VRDEVIDEOINMSG_DEVICEDESC_RSP +{ + VRDEVIDEOINMSGHDR hdr; + VRDEVIDEOINDEVICEDESC Device; + /* + * VRDEVIDEOINFORMATDESC[0] + * VRDEVIDEOINFRAMEDESC[0] + * ... + * VRDEVIDEOINFRAMEDESC[n] + * VRDEVIDEOINFORMATDESC[1] + * VRDEVIDEOINFRAMEDESC[0] + * ... + * VRDEVIDEOINFRAMEDESC[m] + * ... + */ +} VRDEVIDEOINMSG_DEVICEDESC_RSP; + +/* + * VRDE_VIDEOIN_FN_CONTROL + * VRDE_VIDEOIN_FN_CONTROL_NOTIFY + * + * Either sent by the server or by the client as a notification/response. + * If sent by the client as a notification, then hdr.u32MessageId must be 0. + */ +typedef struct VRDEVIDEOINMSG_CONTROL +{ + VRDEVIDEOINMSGHDR hdr; + VRDEVIDEOINCTRLHDR Control; + /* Control specific data may follow. */ +} VRDEVIDEOINMSG_CONTROL; + +/* + * VRDE_VIDEOIN_FN_FRAME + * + * The client sends a video/still frame in the already specified format. + * hdr.u32MessageId must be 0. + */ +typedef struct VRDEVIDEOINMSG_FRAME +{ + VRDEVIDEOINMSGHDR hdr; + VRDEVIDEOINPAYLOADHDR Payload; + /* The frame data follow. */ +} VRDEVIDEOINMSG_FRAME; + + +#ifdef VRDE_VIDEOIN_WITH_VRDEINTERFACE +/* + * The application interface between VirtualBox and the VRDE server. + */ + +#define VRDE_VIDEOIN_INTERFACE_NAME "VIDEOIN" + +typedef struct VRDEVIDEOINDEVICEHANDLE +{ + uint32_t u32ClientId; + uint32_t u32DeviceId; +} VRDEVIDEOINDEVICEHANDLE; + +/* The VRDE server video input interface entry points. Interface version 1. */ +typedef struct VRDEVIDEOININTERFACE +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* Tell the server that this device will be used and associate a context with the device. + * + * @param hServer The VRDE server instance. + * @param pDeviceHandle The device reported by ATTACH notification. + * @param pvDeviceCtx The caller context associated with the pDeviceHandle. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEVideoInDeviceAttach, (HVRDESERVER hServer, + const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle, + void *pvDeviceCtx)); + + /* This device will be not be used anymore. The device context must not be used by the server too. + * + * @param hServer The VRDE server instance. + * @param pDeviceHandle The device reported by ATTACH notification. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEVideoInDeviceDetach, (HVRDESERVER hServer, + const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle)); + + /* Get a device description. + * + * @param hServer The VRDE server instance. + * @param pvUser The callers context of this request. + * @param pDeviceHandle The device reported by ATTACH notification. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEVideoInGetDeviceDesc, (HVRDESERVER hServer, + void *pvUser, + const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle)); + + /* Submit a set/get control request. + * + * @param hServer The VRDE server instance. + * @param pvUser The callers context of this request. + * @param pDeviceHandle The device reported by ATTACH notification. + * @param pReq The request. + * @param cbReq Size of the request. + * + * @return IPRT status code. + */ + DECLR3CALLBACKMEMBER(int, VRDEVideoInControl, (HVRDESERVER hServer, + void *pvUser, + const VRDEVIDEOINDEVICEHANDLE *pDeviceHandle, + const VRDEVIDEOINCTRLHDR *pReq, + uint32_t cbReq)); + +} VRDEVIDEOININTERFACE; + + +/* + * Notifications. + * Data structures: pvData of VRDEVIDEOINCALLBACKS::VRDECallbackVideoInNotify. + */ +typedef struct VRDEVIDEOINNOTIFYATTACH +{ + VRDEVIDEOINDEVICEHANDLE deviceHandle; + uint32_t u32Version; /* VRDE_VIDEOIN_NEGOTIATE_VERSION */ + uint32_t fu32Capabilities; /* VRDE_VIDEOIN_NEGOTIATE_CAP_* */ +} VRDEVIDEOINNOTIFYATTACH; + +typedef struct VRDEVIDEOINNOTIFYDETACH +{ + VRDEVIDEOINDEVICEHANDLE deviceHandle; +} VRDEVIDEOINNOTIFYDETACH; + +/* Notification codes, */ +#define VRDE_VIDEOIN_NOTIFY_ID_ATTACH 0 +#define VRDE_VIDEOIN_NOTIFY_ID_DETACH 1 + + +/* Video input interface callbacks. */ +typedef struct VRDEVIDEOINCALLBACKS +{ + /* The header. */ + VRDEINTERFACEHDR header; + + /* Notifications. + * + * @param pvCallback The callbacks context specified in VRDEGetInterface. + * @param u32EventId The notification identifier: VRDE_VIDEOIN_NOTIFY_*. + * @param pvData The notification specific data. + * @param cbData The size of buffer pointed by pvData. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackVideoInNotify,(void *pvCallback, + uint32_t u32Id, + const void *pvData, + uint32_t cbData)); + + /* Device description received from the client. + * + * @param pvCallback The callbacks context specified in VRDEGetInterface. + * @param rcRequest The result code of the request. + * @param pDeviceCtx The device context associated with the device in VRDEVideoInGetDeviceDesc. + * @param pvUser The pvUser parameter of VRDEVideoInGetDeviceDesc. + * @param pDeviceDesc The device description. + * @param cbDeviceDesc The size of buffer pointed by pDevice. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackVideoInDeviceDesc,(void *pvCallback, + int rcRequest, + void *pDeviceCtx, + void *pvUser, + const VRDEVIDEOINDEVICEDESC *pDeviceDesc, + uint32_t cbDeviceDesc)); + + /* Control response or notification. + * + * @param pvCallback The callbacks context specified in VRDEGetInterface. + * @param rcRequest The result code of the request. + * @param pDeviceCtx The device context associated with the device in VRDEVideoInGetDeviceDesc. + * @param pvUser The pvUser parameter of VRDEVideoInControl. NULL if this is a notification. + * @param pControl The control information. + * @param cbControl The size of buffer pointed by pControl. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackVideoInControl,(void *pvCallback, + int rcRequest, + void *pDeviceCtx, + void *pvUser, + const VRDEVIDEOINCTRLHDR *pControl, + uint32_t cbControl)); + + /* Frame which was received from the client. + * + * @param pvCallback The callbacks context specified in VRDEGetInterface. + * @param rcRequest The result code of the request. + * @param pDeviceCtx The device context associated with the device in VRDEVideoInGetDeviceDesc. + * @param pFrame The frame data. + * @param cbFrame The size of buffer pointed by pFrame. + */ + DECLR3CALLBACKMEMBER(void, VRDECallbackVideoInFrame,(void *pvCallback, + int rcRequest, + void *pDeviceCtx, + const VRDEVIDEOINPAYLOADHDR *pFrame, + uint32_t cbFrame)); + +} VRDEVIDEOINCALLBACKS; +#endif /* VRDE_VIDEOIN_WITH_VRDEINTERFACE */ + +#pragma pack() + +#endif /* !VBOX_INCLUDED_RemoteDesktop_VRDEVideoIn_h */ diff --git a/include/VBox/SUPDrvMangling.h b/include/VBox/SUPDrvMangling.h new file mode 100644 index 00000000..40934528 --- /dev/null +++ b/include/VBox/SUPDrvMangling.h @@ -0,0 +1,48 @@ +/** @file + * SUPDrv - Mangling of IPRT symbols for host drivers. + * + * This is included via a compiler directive on platforms with a global kernel + * symbol name space (i.e. not Windows, OS/2 and Mac OS X (?)). + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_SUPDrvMangling_h +#define VBOX_INCLUDED_SUPDrvMangling_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#define RT_MANGLER(symbol) VBoxHost_##symbol +#include + +#endif /* !VBOX_INCLUDED_SUPDrvMangling_h */ diff --git a/include/VBox/SUPR0StackWrapper.mac b/include/VBox/SUPR0StackWrapper.mac new file mode 100644 index 00000000..152da635 --- /dev/null +++ b/include/VBox/SUPR0StackWrapper.mac @@ -0,0 +1,180 @@ +; $Id: SUPR0StackWrapper.mac $ +;; @file +; SUP - Support Library, ring-0 stack switching wrappers. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_SUPR0StackWrapper_mac +%define ___VBox_SUPR0StackWrapper_mac + +%include "VBox/asmdefs.mac" + +;; VBox's own Stack +%define SUPR0STACKINFO_MAGIC0 0786f4256h ; VBox +%define SUPR0STACKINFO_MAGIC1 06f207327h ; 's o +%define SUPR0STACKINFO_MAGIC2 053206e77h ; wn S +%define SUPR0STACKINFO_MAGIC3 06b636174h ; tack + +;; +; Stack info located before the start of the stack, at the top of the page. +; +struc SUPR0STACKINFO + .magic0 resd 1 + .magic1 resd 1 + .magic2 resd 1 + .magic3 resd 1 + .pResumeKernelStack resq 1 + .pSelf resq 1 +endstruc + +;; +; Number of parameters in GPRs and the spill area size. +%ifdef RT_ARCH_AMD64 + %ifdef ASM_CALL64_MSC + %define SUPR0_GRP_PARAMS 4 + %define SUPR0_SPILL_AREA 4 + %else + %define SUPR0_GRP_PARAMS 6 + %define SUPR0_SPILL_AREA 0 + %endif +%else + %define SUPR0_GRP_PARAMS 0 + %define SUPR0_SPILL_AREA 0 +%endif + +;; +; Generic stack switching wrapper. +; +; @param %1 The name +; @param %2 Number of arguments. +; +%macro SUPR0StackWrapperGeneric 2 +BEGINCODE +extern NAME(StkBack_ %+ %1) + +BEGINPROC %1 +%ifdef RT_ARCH_AMD64 ; Only for amd64 for now. + ; + ; Check for the stack info. + ; + mov rax, rsp + or rax, 0fffh + sub rax, SUPR0STACKINFO_size - 1 + + ; Check for the magic. + cmp dword [rax + SUPR0STACKINFO.magic0], SUPR0STACKINFO_MAGIC0 + jne .regular + cmp dword [rax + SUPR0STACKINFO.magic1], SUPR0STACKINFO_MAGIC1 + jne .regular + cmp dword [rax + SUPR0STACKINFO.magic2], SUPR0STACKINFO_MAGIC2 + jne .regular + cmp dword [rax + SUPR0STACKINFO.magic3], SUPR0STACKINFO_MAGIC3 + jne .regular + + ; Verify the self pointer. + cmp [rax + SUPR0STACKINFO.pSelf], rax + jne .regular + + ; + ; Perform a stack switch. We set up a RBP frame on the old stack so we + ; can use leave to restore the incoming stack upon return. + ; + push rbp + mov rbp, rsp + + ; The actual switch. + mov r10, 0ffffffffffffffe0h ; shuts up warning on 'and rsp, 0ffffffffffffffe0h' + and r10, [rax + SUPR0STACKINFO.pResumeKernelStack] + mov rsp, r10 + + ; + ; Copy over stack arguments. + ; + ; Note! We always copy 2-3 extra arguments (%2 + 2) just in case someone got + ; the argument count wrong. + ; +%if (%2 + 2) > SUPR0_GRP_PARAMS + 18 + %error too many parameters + %fatal too many parameters +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 16 + push qword [rbp + 98h] + push qword [rbp + 90h] +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 14 + push qword [rbp + 88h] + push qword [rbp + 80h] +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 12 + push qword [rbp + 78h] + push qword [rbp + 70h] +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 10 + push qword [rbp + 68h] + push qword [rbp + 60h] +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 8 + push qword [rbp + 58h] + push qword [rbp + 50h] +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 6 + push qword [rbp + 48h] + push qword [rbp + 40h] +%endif +%if (%2 + 2) > SUPR0_GRP_PARAMS + 4 + push qword [rbp + 38h] + push qword [rbp + 30h] +%endif +%if ((%2 + 2) > SUPR0_GRP_PARAMS + 2) || (SUPR0_SPILL_AREA > 2) + push qword [rbp + 28h] + push qword [rbp + 20h] +%endif +%if ((%2 + 2) > SUPR0_GRP_PARAMS) || (SUPR0_SPILL_AREA > 0) + push qword [rbp + 18h] + push qword [rbp + 10h] +%endif + + call NAME(StkBack_ %+ %1) + + leave + ret + +.regular: +%endif ; RT_ARCH_AMD64 + jmp NAME(StkBack_ %+ %1) +ENDPROC %1 +%endmacro + + +%endif + diff --git a/include/VBox/VBoxAuth.h b/include/VBox/VBoxAuth.h new file mode 100644 index 00000000..c10b1e8e --- /dev/null +++ b/include/VBox/VBoxAuth.h @@ -0,0 +1,209 @@ +/** @file + * VirtualBox External Authentication Library Interface. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxAuth_h +#define VBOX_INCLUDED_VBoxAuth_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** @defgroup grp_vboxauth VirtualBox External Authentication Library Interface + * @{ + */ + +/* The following 2 enums are 32 bits values.*/ +typedef enum AuthResult +{ + AuthResultAccessDenied = 0, + AuthResultAccessGranted = 1, + AuthResultDelegateToGuest = 2, + AuthResultSizeHack = 0x7fffffff +} AuthResult; + +typedef enum AuthGuestJudgement +{ + AuthGuestNotAsked = 0, + AuthGuestAccessDenied = 1, + AuthGuestNoJudgement = 2, + AuthGuestAccessGranted = 3, + AuthGuestNotReacted = 4, + AuthGuestSizeHack = 0x7fffffff +} AuthGuestJudgement; + +/** UUID memory representation. Array of 16 bytes. + * + * @note VirtualBox uses a consistent binary representation of UUIDs on all platforms. For this reason + * the integer fields comprising the UUID are stored as little endian values. If you want to pass such + * UUIDs to code which assumes that the integer fields are big endian (often also called network byte + * order), you need to adjust the contents of the UUID to e.g. achieve the same string representation. + * + * The required changes are: + * - reverse the order of byte 0, 1, 2 and 3 + * - reverse the order of byte 4 and 5 + * - reverse the order of byte 6 and 7. + * + * Using this conversion you will get identical results when converting the binary UUID to the string + * representation. + */ +typedef unsigned char AUTHUUID[16]; +typedef AUTHUUID *PAUTHUUID; + +/** The library entry point calling convention. */ +#ifdef _MSC_VER +# define AUTHCALL __cdecl +#elif defined(__GNUC__) +# define AUTHCALL +#else +# error "Unsupported compiler" +#endif + + +/** + * Authentication library entry point. + * + * @param pUuid Pointer to the UUID of the accessed virtual machine. Can be NULL. + * @param guestJudgement Result of the guest authentication. + * @param pszUser User name passed in by the client (UTF8). + * @param pszPassword Password passed in by the client (UTF8). + * @param pszDomain Domain passed in by the client (UTF8). + * + * Return code: + * + * @retval AuthAccessDenied Client access has been denied. + * @retval AuthAccessGranted Client has the right to use the virtual machine. + * @retval AuthDelegateToGuest Guest operating system must + * authenticate the client and the + * library must be called again with + * the result of the guest + * authentication. + */ +typedef AuthResult AUTHCALL FNAUTHENTRY(PAUTHUUID pUuid, + AuthGuestJudgement guestJudgement, + const char *pszUser, + const char *pszPassword, + const char *pszDomain); +/** Pointer to a FNAUTHENTRY function. */ +typedef FNAUTHENTRY *PFNAUTHENTRY; +/** @deprecated */ +typedef FNAUTHENTRY AUTHENTRY; +/** @deprecated */ +typedef PFNAUTHENTRY PAUTHENTRY; +/** Name of the FNAUTHENTRY entry point. */ +#define AUTHENTRY_NAME "VRDPAuth" + +/** + * Authentication library entry point version 2. + * + * @param pUuid Pointer to the UUID of the accessed virtual machine. Can be NULL. + * @param guestJudgement Result of the guest authentication. + * @param pszUser User name passed in by the client (UTF8). + * @param pszPassword Password passed in by the client (UTF8). + * @param pszDomain Domain passed in by the client (UTF8). + * @param fLogon Boolean flag. Indicates whether the entry point is + * called for a client logon or the client disconnect. + * @param clientId Server side unique identifier of the client. + * + * @retval AuthAccessDenied Client access has been denied. + * @retval AuthAccessGranted Client has the right to use the virtual machine. + * @retval AuthDelegateToGuest Guest operating system must + * authenticate the client and the + * library must be called again with + * the result of the guest authentication. + * + * @note When @a fLogon is 0, only @a pUuid and @a clientId are valid and the + * return code is ignored. + */ +typedef AuthResult AUTHCALL FNAUTHENTRY2(PAUTHUUID pUuid, + AuthGuestJudgement guestJudgement, + const char *pszUser, + const char *pszPassword, + const char *pszDomain, + int fLogon, + unsigned clientId); +/** Pointer to a FNAUTHENTRY2 function. */ +typedef FNAUTHENTRY2 *PFNAUTHENTRY2; +/** @deprecated */ +typedef FNAUTHENTRY2 AUTHENTRY2; +/** @deprecated */ +typedef PFNAUTHENTRY2 PAUTHENTRY2; +/** Name of the FNAUTHENTRY2 entry point. */ +#define AUTHENTRY2_NAME "VRDPAuth2" + +/** + * Authentication library entry point version 3. + * + * @param pszCaller The name of the component which calls the library (UTF8). + * @param pUuid Pointer to the UUID of the accessed virtual machine. Can be NULL. + * @param guestJudgement Result of the guest authentication. + * @param pszUser User name passed in by the client (UTF8). + * @param pszPassword Password passed in by the client (UTF8). + * @param pszDomain Domain passed in by the client (UTF8). + * @param fLogon Boolean flag. Indicates whether the entry point is + * called for a client logon or the client disconnect. + * @param clientId Server side unique identifier of the client. + * + * @retval AuthResultAccessDenied Client access has been denied. + * @retval AuthResultAccessGranted Client has the right to use the + * virtual machine. + * @retval AuthResultDelegateToGuest Guest operating system must + * authenticate the client and the + * library must be called again with + * the result of the guest + * authentication. + * + * @note When @a fLogon is 0, only @a pszCaller, @a pUuid and @a clientId are + * valid and the return code is ignored. + */ +typedef AuthResult AUTHCALL FNAUTHENTRY3(const char *pszCaller, + PAUTHUUID pUuid, + AuthGuestJudgement guestJudgement, + const char *pszUser, + const char *pszPassword, + const char *pszDomain, + int fLogon, + unsigned clientId); +/** Pointer to a FNAUTHENTRY3 function. */ +typedef FNAUTHENTRY3 *PFNAUTHENTRY3; +/** @deprecated */ +typedef FNAUTHENTRY3 AUTHENTRY3; +/** @deprecated */ +typedef PFNAUTHENTRY3 PAUTHENTRY3; + +/** Name of the FNAUTHENTRY3 entry point. */ +#define AUTHENTRY3_NAME "AuthEntry" + +/** @} */ + +#endif /* !VBOX_INCLUDED_VBoxAuth_h */ diff --git a/include/VBox/VBoxCocoa.h b/include/VBox/VBoxCocoa.h new file mode 100644 index 00000000..6409555e --- /dev/null +++ b/include/VBox/VBoxCocoa.h @@ -0,0 +1,89 @@ +/** @file + * VBoxCocoa Helper + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxCocoa_h +#define VBOX_INCLUDED_VBoxCocoa_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** Macro which add a typedef of the given Cocoa class in an appropriate form + * for the current context. This means void* in the C/CPP context and + * NSWhatever* in the ObjC/ObjCPP context. Use + * NativeNSWhateverRef/ConstNativeNSWhateverRef when you reference the Cocoa + * type somewhere. The use of this prevents extensive casting of void* to the + * right type in the Cocoa context. */ +#ifdef __OBJC__ +# define ADD_COCOA_NATIVE_REF(CocoaClass) \ + @class CocoaClass; \ + typedef CocoaClass *Native##CocoaClass##Ref; \ + typedef const CocoaClass *ConstNative##CocoaClass##Ref +#else /* !__OBJC__ */ +# define ADD_COCOA_NATIVE_REF(CocoaClass) \ + typedef void *Native##CocoaClass##Ref; \ + typedef const void *ConstNative##CocoaClass##Ref +#endif /* !__OBJC__ */ + + +/* + * Objective-C++ Helpers. + */ +#if defined(__OBJC__) && defined (__cplusplus) + +/* Global includes */ +# import + +/** Helper class for automatic creation & destroying of a cocoa auto release + * pool. */ +class CocoaAutoreleasePool +{ +public: + inline CocoaAutoreleasePool() + { + mPool = [[NSAutoreleasePool alloc] init]; + } + inline ~CocoaAutoreleasePool() + { + [mPool release]; + } + +private: + NSAutoreleasePool *mPool; +}; + +#endif /* __OBJC__ && __cplusplus */ + +#endif /* !VBOX_INCLUDED_VBoxCocoa_h */ + diff --git a/include/VBox/VBoxCryptoIf.h b/include/VBox/VBoxCryptoIf.h new file mode 100644 index 00000000..8e687d38 --- /dev/null +++ b/include/VBox/VBoxCryptoIf.h @@ -0,0 +1,320 @@ +/** @file + * VirtualBox - Cryptographic support functions Interface. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxCryptoIf_h +#define VBOX_INCLUDED_VBoxCryptoIf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +/** An opaque VBox cryptographic context handle. */ +typedef struct VBOXCRYPTOCTXINT *VBOXCRYPTOCTX; +/**Pointer to an opaque VBox cryptographic context handle. */ +typedef VBOXCRYPTOCTX *PVBOXCRYPTOCTX; + +/** Magic identifying the cryptographic interface (Charles Babbage). */ +#define VBOXCRYPTOIF_MAGIC UINT32_C(0x17911226) + +/** Pointer to const cryptographic interface. */ +typedef const struct VBOXCRYPTOIF *PCVBOXCRYPTOIF; +/** + * The main cryptographic callbacks interface table. + */ +typedef struct VBOXCRYPTOIF +{ + /** Interface magic, set to VBOXCRYPTOIF_MAGIC. */ + uint32_t u32Magic; + /** Interface version. + * This is set to VBOXCRYPTOIF_VERSION. */ + uint32_t u32Version; + /** Description string. */ + const char *pszDesc; + + /** @name Generic crytographic context operations. + * @{ */ + + /** + * Creates a new cryptographic context for encryption. + * + * @returns VBox status code. + * @param pszCipher The identifier of the cipher to use. + * @param pszPassword Password for encrypting the context. + * @param phCryptoCtx Where to store the handle to the crypto context on success. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxCreate, (const char *pszCipher, const char *pszPassword, + PVBOXCRYPTOCTX phCryptoCtx)); + + /** + * Creates a new cryptographic context for decryption from the given base-64 encoded context. + * + * @returns VBox status code. + * @param pszStoredCtx The base-64 encoded context to decrypt with the given password. + * @param pszPassword Password for encrypting the context. + * @param phCryptoCtx Where to store the handle to the crypto context on success. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxLoad, (const char *pszStoredCtx, const char *pszPassword, + PVBOXCRYPTOCTX phCryptoCtx)); + + /** + * Destroys a previously created cryptographic context. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context to destroy. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxDestroy, (VBOXCRYPTOCTX hCryptoCtx)); + + /** + * Returns the given cryptographic context as a base-64 encoded string. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context. + * @param ppszStoredCtx Where to store the base-64 encoded cryptographic context on success. + * Must be freed with RTMemFree() when not required anymore. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxSave, (VBOXCRYPTOCTX hCryptoCtx, char **ppszStoredCtx)); + + /** + * Changes the encryption password for the given context. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context. + * @param pszPassword New password used for encrypting the DEK. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxPasswordChange, (VBOXCRYPTOCTX hCryptoCtx, const char *pszPassword)); + + /** + * Queries the required size of the output buffer for encrypted data. Depends on the cipher. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context. + * @param cbPlainText The size of the data to be encrypted. + * @param pcbEncrypted Where to store the size in bytes of the encrypted data on success. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxQueryEncryptedSize, (VBOXCRYPTOCTX hCryptoCtx, size_t cbPlaintext, + size_t *pcbEncrypted)); + + /** + * Queries the required size of the output buffer for decrypted data. Depends on the cipher. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context. + * @param cbEncrypted The size of the encrypted chunk before decryption. + * @param pcbPlaintext Where to store the size in bytes of the decrypted data on success. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxQueryDecryptedSize, (VBOXCRYPTOCTX hCryptoCtx, size_t cbEncrypted, + size_t *pcbPlaintext)); + + /** + * Encrypts data. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context. + * @param fPartial Only part of data to be encrypted is specified. The encryption + * cipher context will not be closed. Set to false for last piece + * of data, or if data is specified completely. + * Only CTR mode supports partial encryption. + * @param pvIV Pointer to IV. If null it will be generated. + * @param cbIV Size of the IV. + * @param pvPlainText Data to encrypt. + * @param cbPlainText Size of the data in the pvPlainText. + * @param pvAuthData Data used for authenticate the pvPlainText + * @param cbAuthData Size of the pvAuthData + * @param pvEncrypted Buffer to store encrypted data + * @param cbEncrypted Size of the buffer in pvEncrypted + * @param pcbEncrypted Placeholder where the size of the encrypted data returned. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxEncrypt, (VBOXCRYPTOCTX hCryptoCtx, bool fPartial, void const *pvIV, size_t cbIV, + void const *pvPlainText, size_t cbPlainText, + void const *pvAuthData, size_t cbAuthData, + void *pvEncrypted, size_t cbEncrypted, + size_t *pcbEncrypted)); + + /** + * Decrypts data. + * + * @returns VBox status code. + * @param hCryptoCtx Handle of crpytographic context. + * @param fPartial Only part of data to be encrypted is specified. The encryption + * cipher context will not be closed. Set to false for last piece + * of data, or if data is specified completely. + * Only CTR mode supports partial encryption. + * @param pvEncrypted Data to decrypt. + * @param cbEncrypted Size of the data in the pvEncrypted. + * @param pvAuthData Data used for authenticate the pvEncrypted + * @param cbAuthData Size of the pvAuthData + * @param pvPlainText Buffer to store decrypted data + * @param cbPlainText Size of the buffer in pvPlainText + * @param pcbPlainText Placeholder where the size of the decrypted data returned. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoCtxDecrypt, (VBOXCRYPTOCTX hCryptoCtx, bool fPartial, + void const *pvEncrypted, size_t cbEncrypted, + void const *pvAuthData, size_t cbAuthData, + void *pvPlainText, size_t cbPlainText, size_t *pcbPlainText)); + /** @} */ + + /** @name File based cryptographic operations. + * @{ */ + /** + * Creates a new VFS file handle for an encrypted or to be encrypted file handle. + * + * @returns VBox status code. + * @param hVfsFile The input file handle, a new reference is retained upon success. + * @param pszKeyStore The key store containing the DEK used for encryption. + * @param pszPassword Password encrypting the DEK. + * @param phVfsFile Where to store the handle to the VFS file on success. + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoFileFromVfsFile, (RTVFSFILE hVfsFile, const char *pszKeyStore, const char *pszPassword, + PRTVFSFILE phVfsFile)); + + /** + * Opens a new encryption I/O stream. + * + * @returns VBox status code. + * @param hVfsIosDst The encrypted output stream (must be writeable). + * The reference is not consumed, instead another + * one is retained. + * @param pszKeyStore The key store containing the DEK used for encryption. + * @param pszPassword Password encrypting the DEK. + * @param phVfsIosCrypt Where to return the crypting input I/O stream handle + * (you write to this). + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoIoStrmFromVfsIoStrmEncrypt, (RTVFSIOSTREAM hVfsIosDst, const char *pszKeyStore, + const char *pszPassword, PRTVFSIOSTREAM phVfsIosCrypt)); + + /** + * Opens a new decryption I/O stream. + * + * @returns VBox status code. + * @param hVfsIosIn The encrypted input stream (must be readable). + * The reference is not consumed, instead another + * one is retained. + * @param pszKeyStore The key store containing the DEK used for encryption. + * @param pszPassword Password encrypting the DEK. + * @param phVfsIosOut Where to return the handle to the decrypted I/O stream (read). + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoIoStrmFromVfsIoStrmDecrypt, (RTVFSIOSTREAM hVfsIosIn, const char *pszKeyStore, + const char *pszPassword, PRTVFSIOSTREAM phVfsIosOut)); + /** @} */ + + /** @name Keystore related functions. + * @{ */ + /** + * Return the encryption parameters and DEK from the base64 encoded key store data. + * + * @returns VBox status code. + * @param pszEnc The base64 encoded key store data. + * @param pszPassword The password to use for key decryption. + * If the password is NULL only the cipher is returned. + * @param ppbKey Where to store the DEK on success. + * Must be freed with RTMemSaferFree(). + * @param pcbKey Where to store the DEK size in bytes on success. + * @param ppszCipher Where to store the used cipher for the decrypted DEK. + * Must be freed with RTStrFree(). + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoKeyStoreGetDekFromEncoded, (const char *pszEnc, const char *pszPassword, + uint8_t **ppbKey, size_t *pcbKey, char **ppszCipher)); + + /** + * Stores the given DEK in a key store protected by the given password. + * + * @returns VBox status code. + * @param pszPassword The password to protect the DEK. + * @param pbKey The DEK to protect. + * @param cbKey Size of the DEK to protect. + * @param pszCipher The cipher string associated with the DEK. + * @param ppszEnc Where to store the base64 encoded key store data on success. + * Must be freed with RTMemFree(). + */ + DECLR3CALLBACKMEMBER(int, pfnCryptoKeyStoreCreate, (const char *pszPassword, const uint8_t *pbKey, size_t cbKey, + const char *pszCipher, char **ppszEnc)); + /** @} */ + + DECLR3CALLBACKMEMBER(int, pfnReserved1,(void)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved2,(void)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved3,(void)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved4,(void)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved5,(void)); /**< Reserved for minor structure revisions. */ + DECLR3CALLBACKMEMBER(int, pfnReserved6,(void)); /**< Reserved for minor structure revisions. */ + + /** Reserved for minor structure revisions. */ + uint32_t uReserved7; + + /** End of structure marker (VBOXCRYPTOIF_VERSION). */ + uint32_t u32EndMarker; +} VBOXCRYPTOIF; +/** Current version of the VBOXCRYPTOIF structure. */ +#define VBOXCRYPTOIF_VERSION RT_MAKE_U32(0, 1) + + +/** + * The VBoxCrypto entry callback function. + * + * @returns VBox status code. + * @param ppCryptoIf Where to store the pointer to the crypto module interface callback table + * on success. + */ +typedef DECLCALLBACKTYPE(int, FNVBOXCRYPTOENTRY,(PCVBOXCRYPTOIF *ppCryptoIf)); +/** Pointer to a FNVBOXCRYPTOENTRY. */ +typedef FNVBOXCRYPTOENTRY *PFNVBOXCRYPTOENTRY; + +/** The name of the crypto module entry point. */ +#define VBOX_CRYPTO_MOD_ENTRY_POINT "VBoxCryptoEntry" + + +/** + * Checks if cryptographic interface version is compatible. + * + * @returns true if the do, false if they don't. + * @param u32Provider The provider version. + * @param u32User The user version. + */ +#define VBOXCRYPTO_IS_VER_COMPAT(u32Provider, u32User) \ + ( VBOXCRYPTO_IS_MAJOR_VER_EQUAL(u32Provider, u32User) \ + && (int32_t)RT_LOWORD(u32Provider) >= (int32_t)RT_LOWORD(u32User) ) /* stupid casts to shut up gcc */ + +/** + * Check if two cryptographic interface versions have the same major version. + * + * @returns true if the do, false if they don't. + * @param u32Ver1 The first version number. + * @param u32Ver2 The second version number. + */ +#define VBOXCRYPTO_IS_MAJOR_VER_EQUAL(u32Ver1, u32Ver2) (RT_HIWORD(u32Ver1) == RT_HIWORD(u32Ver2)) + +#endif /* !VBOX_INCLUDED_VBoxCryptoIf_h */ + diff --git a/include/VBox/VBoxDrvCfg-win.h b/include/VBox/VBoxDrvCfg-win.h new file mode 100644 index 00000000..5ac12ae1 --- /dev/null +++ b/include/VBox/VBoxDrvCfg-win.h @@ -0,0 +1,91 @@ +/* $Id: VBoxDrvCfg-win.h $ */ +/** @file + * Windows Driver Manipulation API. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxDrvCfg_win_h +#define VBOX_INCLUDED_VBoxDrvCfg_win_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +#if 0 +/* enable this in case we include this in a dll*/ +# ifdef IN_VBOXDRVCFG +# define VBOXDRVCFG_DECL(a_Type) DECLEXPORT(a_Type) +# else +# define VBOXDRVCFG_DECL(a_Type) DECLIMPORT(a_Type) +# endif +#else +/*enable this in case we include this in a static lib*/ +# define VBOXDRVCFG_DECL(a_Type) a_Type VBOXCALL +#endif + +typedef enum +{ + VBOXDRVCFG_LOG_SEVERITY_FLOW = 1, + VBOXDRVCFG_LOG_SEVERITY_REGULAR, + VBOXDRVCFG_LOG_SEVERITY_REL +} VBOXDRVCFG_LOG_SEVERITY_T; + +typedef DECLCALLBACKTYPE(void, FNVBOXDRVCFGLOG,(VBOXDRVCFG_LOG_SEVERITY_T enmSeverity, char *pszMsg, void *pvContext)); +typedef FNVBOXDRVCFGLOG *PFNVBOXDRVCFGLOG; + +VBOXDRVCFG_DECL(void) VBoxDrvCfgLoggerSet(PFNVBOXDRVCFGLOG pfnLog, void *pvLog); + +typedef DECLCALLBACKTYPE(void, FNVBOXDRVCFGPANIC,(void *pvPanic)); +typedef FNVBOXDRVCFGPANIC *PFNVBOXDRVCFGPANIC; +VBOXDRVCFG_DECL(void) VBoxDrvCfgPanicSet(PFNVBOXDRVCFGPANIC pfnPanic, void *pvPanic); + +/* Driver package API*/ +VBOXDRVCFG_DECL(HRESULT) VBoxDrvCfgInfInstall(IN LPCWSTR pwszInfPath); +VBOXDRVCFG_DECL(HRESULT) VBoxDrvCfgInfUninstall(IN LPCWSTR pwszInfPath, IN DWORD fFlags); +VBOXDRVCFG_DECL(HRESULT) VBoxDrvCfgInfUninstallAllSetupDi(IN const GUID * pGuidClass, IN LPCWSTR pwszClassName, + IN LPCWSTR pwszPnPId, IN DWORD fFlags); +VBOXDRVCFG_DECL(HRESULT) VBoxDrvCfgInfUninstallAllF(IN LPCWSTR pwszClassName, IN LPCWSTR pwszPnPId, IN DWORD fFlags); + +/* Service API */ +VBOXDRVCFG_DECL(HRESULT) VBoxDrvCfgSvcStart(LPCWSTR pwszSvcName); + +HRESULT VBoxDrvCfgDrvUpdate(LPCWSTR pszwHwId, LPCWSTR psxwInf, BOOL *pfRebootRequired); + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_VBoxDrvCfg_win_h */ + diff --git a/include/VBox/VBoxGL2D.h b/include/VBox/VBoxGL2D.h new file mode 100644 index 00000000..c0a9a4aa --- /dev/null +++ b/include/VBox/VBoxGL2D.h @@ -0,0 +1,390 @@ +/** @file + * + * VBox frontends: Qt GUI ("VirtualBox"): + * OpenGL support info used for 2D support detection + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxGL2D_h +#define VBOX_INCLUDED_VBoxGL2D_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +typedef char GLchar; + +#ifndef GL_COMPILE_STATUS +# define GL_COMPILE_STATUS 0x8b81 +#endif +#ifndef GL_LINK_STATUS +# define GL_LINK_STATUS 0x8b82 +#endif +#ifndef GL_FRAGMENT_SHADER +# define GL_FRAGMENT_SHADER 0x8b30 +#endif +#ifndef GL_VERTEX_SHADER +# define GL_VERTEX_SHADER 0x8b31 +#endif + +/* GL_ARB_multitexture */ +#ifndef GL_TEXTURE0 +# define GL_TEXTURE0 0x84c0 +#endif +#ifndef GL_TEXTURE1 +# define GL_TEXTURE1 0x84c1 +#endif +#ifndef GL_MAX_TEXTURE_COORDS +# define GL_MAX_TEXTURE_COORDS 0x8871 +#endif +#ifndef GL_MAX_TEXTURE_IMAGE_UNITS +# define GL_MAX_TEXTURE_IMAGE_UNITS 0x8872 +#endif + +#ifndef APIENTRY +# define APIENTRY +#endif + +typedef GLvoid (APIENTRY *PFNVBOXVHWA_ACTIVE_TEXTURE) (GLenum texture); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_MULTI_TEX_COORD2I) (GLenum texture, GLint v0, GLint v1); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_MULTI_TEX_COORD2F) (GLenum texture, GLfloat v0, GLfloat v1); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_MULTI_TEX_COORD2D) (GLenum texture, GLdouble v0, GLdouble v1); + +/* GL_ARB_texture_rectangle */ +#ifndef GL_TEXTURE_RECTANGLE +# define GL_TEXTURE_RECTANGLE 0x84F5 +#endif + +/* GL_ARB_shader_objects */ +/* GL_ARB_fragment_shader */ + +typedef GLuint (APIENTRY *PFNVBOXVHWA_CREATE_SHADER) (GLenum type); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_SHADER_SOURCE) (GLuint shader, GLsizei count, const GLchar **string, const GLint *length); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_COMPILE_SHADER) (GLuint shader); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_DELETE_SHADER) (GLuint shader); + +typedef GLuint (APIENTRY *PFNVBOXVHWA_CREATE_PROGRAM) (); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_ATTACH_SHADER) (GLuint program, GLuint shader); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_DETACH_SHADER) (GLuint program, GLuint shader); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_LINK_PROGRAM) (GLuint program); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_USE_PROGRAM) (GLuint program); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_DELETE_PROGRAM) (GLuint program); + +typedef GLboolean (APIENTRY *PFNVBOXVHWA_IS_SHADER) (GLuint shader); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GET_SHADERIV) (GLuint shader, GLenum pname, GLint *params); +typedef GLboolean (APIENTRY *PFNVBOXVHWA_IS_PROGRAM) (GLuint program); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GET_PROGRAMIV) (GLuint program, GLenum pname, GLint *params); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GET_ATTACHED_SHADERS) (GLuint program, GLsizei maxCount, GLsizei *count, GLuint *shaders); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GET_SHADER_INFO_LOG) (GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GET_PROGRAM_INFO_LOG) (GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog); +typedef GLint (APIENTRY *PFNVBOXVHWA_GET_UNIFORM_LOCATION) (GLint programObj, const GLchar *name); + +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM1F)(GLint location, GLfloat v0); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM2F)(GLint location, GLfloat v0, GLfloat v1); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM3F)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM4F)(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3); + +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM1I)(GLint location, GLint v0); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM2I)(GLint location, GLint v0, GLint v1); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM3I)(GLint location, GLint v0, GLint v1, GLint v2); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_UNIFORM4I)(GLint location, GLint v0, GLint v1, GLint v2, GLint v3); + +/* GL_ARB_pixel_buffer_object*/ +#ifndef Q_WS_MAC +/* apears to be defined on mac */ +typedef ptrdiff_t GLsizeiptr; +#endif + +#ifndef GL_READ_ONLY +# define GL_READ_ONLY 0x88B8 +#endif +#ifndef GL_WRITE_ONLY +# define GL_WRITE_ONLY 0x88B9 +#endif +#ifndef GL_READ_WRITE +# define GL_READ_WRITE 0x88BA +#endif +#ifndef GL_STREAM_DRAW +# define GL_STREAM_DRAW 0x88E0 +#endif +#ifndef GL_STREAM_READ +# define GL_STREAM_READ 0x88E1 +#endif +#ifndef GL_STREAM_COPY +# define GL_STREAM_COPY 0x88E2 +#endif +#ifndef GL_DYNAMIC_DRAW +# define GL_DYNAMIC_DRAW 0x88E8 +#endif + +#ifndef GL_PIXEL_PACK_BUFFER +# define GL_PIXEL_PACK_BUFFER 0x88EB +#endif +#ifndef GL_PIXEL_UNPACK_BUFFER +# define GL_PIXEL_UNPACK_BUFFER 0x88EC +#endif +#ifndef GL_PIXEL_PACK_BUFFER_BINDING +# define GL_PIXEL_PACK_BUFFER_BINDING 0x88ED +#endif +#ifndef GL_PIXEL_UNPACK_BUFFER_BINDING +# define GL_PIXEL_UNPACK_BUFFER_BINDING 0x88EF +#endif + +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GEN_BUFFERS)(GLsizei n, GLuint *buffers); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_DELETE_BUFFERS)(GLsizei n, const GLuint *buffers); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_BIND_BUFFER)(GLenum target, GLuint buffer); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_BUFFER_DATA)(GLenum target, GLsizeiptr size, const GLvoid *data, GLenum usage); +typedef GLvoid* (APIENTRY *PFNVBOXVHWA_MAP_BUFFER)(GLenum target, GLenum access); +typedef GLboolean (APIENTRY *PFNVBOXVHWA_UNMAP_BUFFER)(GLenum target); + +/* GL_EXT_framebuffer_object */ +#ifndef GL_FRAMEBUFFER +# define GL_FRAMEBUFFER 0x8D40 +#endif +#ifndef GL_COLOR_ATTACHMENT0 +# define GL_COLOR_ATTACHMENT0 0x8CE0 +#endif + +typedef GLboolean (APIENTRY *PFNVBOXVHWA_IS_FRAMEBUFFER)(GLuint framebuffer); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_BIND_FRAMEBUFFER)(GLenum target, GLuint framebuffer); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_DELETE_FRAMEBUFFERS)(GLsizei n, const GLuint *framebuffers); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GEN_FRAMEBUFFERS)(GLsizei n, GLuint *framebuffers); +typedef GLenum (APIENTRY *PFNVBOXVHWA_CHECK_FRAMEBUFFER_STATUS)(GLenum target); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_FRAMEBUFFER_TEXTURE1D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_FRAMEBUFFER_TEXTURE2D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_FRAMEBUFFER_TEXTURE3D)(GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level, GLint zoffset); +typedef GLvoid (APIENTRY *PFNVBOXVHWA_GET_FRAMEBUFFER_ATTACHMENT_PARAMETRIV)(GLenum target, GLenum attachment, GLenum pname, GLint *params); + + +/*****************/ + +/* functions */ + +/* @todo: move those to VBoxGLInfo class instance members ??? */ +extern PFNVBOXVHWA_ACTIVE_TEXTURE vboxglActiveTexture; +extern PFNVBOXVHWA_MULTI_TEX_COORD2I vboxglMultiTexCoord2i; +extern PFNVBOXVHWA_MULTI_TEX_COORD2D vboxglMultiTexCoord2d; +extern PFNVBOXVHWA_MULTI_TEX_COORD2F vboxglMultiTexCoord2f; + + +extern PFNVBOXVHWA_CREATE_SHADER vboxglCreateShader; +extern PFNVBOXVHWA_SHADER_SOURCE vboxglShaderSource; +extern PFNVBOXVHWA_COMPILE_SHADER vboxglCompileShader; +extern PFNVBOXVHWA_DELETE_SHADER vboxglDeleteShader; + +extern PFNVBOXVHWA_CREATE_PROGRAM vboxglCreateProgram; +extern PFNVBOXVHWA_ATTACH_SHADER vboxglAttachShader; +extern PFNVBOXVHWA_DETACH_SHADER vboxglDetachShader; +extern PFNVBOXVHWA_LINK_PROGRAM vboxglLinkProgram; +extern PFNVBOXVHWA_USE_PROGRAM vboxglUseProgram; +extern PFNVBOXVHWA_DELETE_PROGRAM vboxglDeleteProgram; + +extern PFNVBOXVHWA_IS_SHADER vboxglIsShader; +extern PFNVBOXVHWA_GET_SHADERIV vboxglGetShaderiv; +extern PFNVBOXVHWA_IS_PROGRAM vboxglIsProgram; +extern PFNVBOXVHWA_GET_PROGRAMIV vboxglGetProgramiv; +extern PFNVBOXVHWA_GET_ATTACHED_SHADERS vboxglGetAttachedShaders; +extern PFNVBOXVHWA_GET_SHADER_INFO_LOG vboxglGetShaderInfoLog; +extern PFNVBOXVHWA_GET_PROGRAM_INFO_LOG vboxglGetProgramInfoLog; + +extern PFNVBOXVHWA_GET_UNIFORM_LOCATION vboxglGetUniformLocation; + +extern PFNVBOXVHWA_UNIFORM1F vboxglUniform1f; +extern PFNVBOXVHWA_UNIFORM2F vboxglUniform2f; +extern PFNVBOXVHWA_UNIFORM3F vboxglUniform3f; +extern PFNVBOXVHWA_UNIFORM4F vboxglUniform4f; + +extern PFNVBOXVHWA_UNIFORM1I vboxglUniform1i; +extern PFNVBOXVHWA_UNIFORM2I vboxglUniform2i; +extern PFNVBOXVHWA_UNIFORM3I vboxglUniform3i; +extern PFNVBOXVHWA_UNIFORM4I vboxglUniform4i; + +extern PFNVBOXVHWA_GEN_BUFFERS vboxglGenBuffers; +extern PFNVBOXVHWA_DELETE_BUFFERS vboxglDeleteBuffers; +extern PFNVBOXVHWA_BIND_BUFFER vboxglBindBuffer; +extern PFNVBOXVHWA_BUFFER_DATA vboxglBufferData; +extern PFNVBOXVHWA_MAP_BUFFER vboxglMapBuffer; +extern PFNVBOXVHWA_UNMAP_BUFFER vboxglUnmapBuffer; + +extern PFNVBOXVHWA_IS_FRAMEBUFFER vboxglIsFramebuffer; +extern PFNVBOXVHWA_BIND_FRAMEBUFFER vboxglBindFramebuffer; +extern PFNVBOXVHWA_DELETE_FRAMEBUFFERS vboxglDeleteFramebuffers; +extern PFNVBOXVHWA_GEN_FRAMEBUFFERS vboxglGenFramebuffers; +extern PFNVBOXVHWA_CHECK_FRAMEBUFFER_STATUS vboxglCheckFramebufferStatus; +extern PFNVBOXVHWA_FRAMEBUFFER_TEXTURE1D vboxglFramebufferTexture1D; +extern PFNVBOXVHWA_FRAMEBUFFER_TEXTURE2D vboxglFramebufferTexture2D; +extern PFNVBOXVHWA_FRAMEBUFFER_TEXTURE3D vboxglFramebufferTexture3D; +extern PFNVBOXVHWA_GET_FRAMEBUFFER_ATTACHMENT_PARAMETRIV vboxglGetFramebufferAttachmentParameteriv; + + +/* + * Glossing over qt 5 vs 6 differences. + * + * Note! We could use the qt6 classes in 5, but we probably don't have the + * necessary modules in our current qt builds. + */ +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +class QOpenGLWidget; +class QOpenGLContext; +# define MY_QOpenGLWidget QOpenGLWidget +# define MY_QOpenGLContext QOpenGLContext +#else +class QGLWidget; +class QGLContext; +# define MY_QOpenGLWidget QGLWidget +# define MY_QOpenGLContext QGLContext +#endif + + +class VBoxGLInfo +{ +public: + VBoxGLInfo() : + mGLVersion(0), + mFragmentShaderSupported(false), + mTextureRectangleSupported(false), + mTextureNP2Supported(false), + mPBOSupported(false), + mFBOSupported(false), + mMultiTexNumSupported(1), /* 1 would mean it is not supported */ + m_GL_ARB_multitexture(false), + m_GL_ARB_shader_objects(false), + m_GL_ARB_fragment_shader(false), + m_GL_ARB_pixel_buffer_object(false), + m_GL_ARB_texture_rectangle(false), + m_GL_EXT_texture_rectangle(false), + m_GL_NV_texture_rectangle(false), + m_GL_ARB_texture_non_power_of_two(false), + m_GL_EXT_framebuffer_object(false), + mInitialized(false) + {} + + void init(const MY_QOpenGLContext *pContext); + + bool isInitialized() const { return mInitialized; } + + int getGLVersion() const { return mGLVersion; } + bool isFragmentShaderSupported() const { return mFragmentShaderSupported; } + bool isTextureRectangleSupported() const { return mTextureRectangleSupported; } + bool isTextureNP2Supported() const { return mTextureNP2Supported; } + bool isPBOSupported() const { return mPBOSupported; } + /* some ATI drivers do not seem to support non-zero offsets when dealing with PBOs + * @todo: add a check for that, always unsupported currently */ + bool isPBOOffsetSupported() const { return false; } + bool isFBOSupported() const { return mFBOSupported; } + /* 1 would mean it is not supported */ + int getMultiTexNumSupported() const { return mMultiTexNumSupported; } + + static int parseVersion(const GLubyte * ver); +private: + void initExtSupport(const MY_QOpenGLContext &context); + + int mGLVersion; + bool mFragmentShaderSupported; + bool mTextureRectangleSupported; + bool mTextureNP2Supported; + bool mPBOSupported; + bool mFBOSupported; + int mMultiTexNumSupported; /* 1 would mean it is not supported */ + + bool m_GL_ARB_multitexture; + bool m_GL_ARB_shader_objects; + bool m_GL_ARB_fragment_shader; + bool m_GL_ARB_pixel_buffer_object; + bool m_GL_ARB_texture_rectangle; + bool m_GL_EXT_texture_rectangle; + bool m_GL_NV_texture_rectangle; + bool m_GL_ARB_texture_non_power_of_two; + bool m_GL_EXT_framebuffer_object; + + bool mInitialized; +}; + +class VBoxGLTmpContext +{ +public: + VBoxGLTmpContext(); + ~VBoxGLTmpContext(); + + const MY_QOpenGLContext *makeCurrent(); +private: + MY_QOpenGLWidget *mWidget; +}; + + +#define VBOXQGL_MAKEFOURCC(ch0, ch1, ch2, ch3) \ + ((uint32_t)(uint8_t)(ch0) | ((uint32_t)(uint8_t)(ch1) << 8) | \ + ((uint32_t)(uint8_t)(ch2) << 16) | ((uint32_t)(uint8_t)(ch3) << 24 )) + +#define FOURCC_AYUV VBOXQGL_MAKEFOURCC('A', 'Y', 'U', 'V') +#define FOURCC_UYVY VBOXQGL_MAKEFOURCC('U', 'Y', 'V', 'Y') +#define FOURCC_YUY2 VBOXQGL_MAKEFOURCC('Y', 'U', 'Y', '2') +#define FOURCC_YV12 VBOXQGL_MAKEFOURCC('Y', 'V', '1', '2') +#define VBOXVHWA_NUMFOURCC 4 + +class VBoxVHWAInfo +{ +public: + VBoxVHWAInfo() : + mFourccSupportedCount(0), + mInitialized(false) + {} + + VBoxVHWAInfo(const VBoxGLInfo & glInfo) : + mglInfo(glInfo), + mFourccSupportedCount(0), + mInitialized(false) + {} + + void init(const MY_QOpenGLContext *pContext); + + bool isInitialized() const { return mInitialized; } + + const VBoxGLInfo & getGlInfo() const { return mglInfo; } + + bool isVHWASupported() const; + + int getFourccSupportedCount() const { return mFourccSupportedCount; } + const uint32_t * getFourccSupportedList() const { return mFourccSupportedList; } + + static bool checkVHWASupport(); +private: + VBoxGLInfo mglInfo; + uint32_t mFourccSupportedList[VBOXVHWA_NUMFOURCC]; + int mFourccSupportedCount; + + bool mInitialized; +}; + +#endif /* !VBOX_INCLUDED_VBoxGL2D_h */ diff --git a/include/VBox/VBoxGuest.h b/include/VBox/VBoxGuest.h new file mode 100644 index 00000000..ddd78327 --- /dev/null +++ b/include/VBox/VBoxGuest.h @@ -0,0 +1,1012 @@ +/** @file + * VBoxGuest - VirtualBox Guest Additions Driver Interface. (ADD,DEV) + * + * @note This file is used by 16-bit compilers too (OpenWatcom). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VBoxGuest_h +#define VBOX_INCLUDED_VBoxGuest_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + + +/** @defgroup grp_vboxguest VirtualBox Guest Additions Device Driver + * + * Also know as VBoxGuest. + * + * @{ + */ + +/** @defgroup grp_vboxguest_ioc VirtualBox Guest Additions Driver Interface + * + * @note This is considered internal in ring-3, please use the VbglR3 functions. + * + * - I/O controls for user and/or kernel mode starts at 0. + * - IDC specific requests descends from 63. + * - Bits 7 and 6 are currently reserved for future hacks. + * + * @remarks When creating new IOCtl interfaces keep in mind that not all OSes supports + * reporting back the output size. (This got messed up a little bit in VBoxDrv.) + * + * The request size is also a little bit tricky as it's passed as part of the + * request code on unix. The size field is 14 bits on Linux, 12 bits on *BSD, + * 13 bits Darwin, and 8-bits on Solaris. All the BSDs and Darwin kernels + * will make use of the size field, while Linux and Solaris will not. We're of + * course using the size to validate and/or map/lock the request, so it has + * to be valid. + * + * For Solaris we will have to do something special though, 255 isn't + * sufficient for all we need. A 4KB restriction (BSD) is probably not + * too problematic (yet) as a general one. + * + * More info can be found in SUPDRVIOC.h and related sources. + * + * @remarks If adding interfaces that only has input or only has output, some new macros + * needs to be created so the most efficient IOCtl data buffering method can be + * used. + * + * @{ + */ +#if !defined(IN_RC) && !defined(IN_RING0_AGNOSTIC) + +/** Fictive start address of the hypervisor physical memory for MmMapIoSpace. */ +#define VBOXGUEST_HYPERVISOR_PHYSICAL_START UINT32_C(0xf8000000) + +#ifdef RT_OS_DARWIN +/** Cookie used to fend off some unwanted clients to the IOService. */ +# define VBOXGUEST_DARWIN_IOSERVICE_COOKIE UINT32_C(0x56426f78) /* 'VBox' */ +#endif + + +#if defined(RT_OS_WINDOWS) +# ifndef CTL_CODE +# include +# endif + /* Automatic buffering, size not encoded. */ +# define VBGL_IOCTL_CODE_SIZE(Function, Size) CTL_CODE(FILE_DEVICE_UNKNOWN, 2048 + (Function), METHOD_BUFFERED, FILE_WRITE_ACCESS) +# define VBGL_IOCTL_CODE_BIG(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, 2048 + (Function), METHOD_BUFFERED, FILE_WRITE_ACCESS) +# define VBGL_IOCTL_CODE_FAST(Function) CTL_CODE(FILE_DEVICE_UNKNOWN, 2048 + (Function), METHOD_NEITHER, FILE_WRITE_ACCESS) +# define VBGL_IOCTL_CODE_STRIPPED(a_uIOCtl) (a_uIOCtl) +# define VBOXGUEST_DEVICE_NAME "\\\\.\\VBoxGuest" +/** The support service name. */ +# define VBOXGUEST_SERVICE_NAME "VBoxGuest" +/** Global name for Win2k+ */ +# define VBOXGUEST_DEVICE_NAME_GLOBAL "\\\\.\\Global\\VBoxGuest" +/** Win32 driver name */ +# define VBOXGUEST_DEVICE_NAME_NT L"\\Device\\VBoxGuest" +/** Device name. */ +# define VBOXGUEST_DEVICE_NAME_DOS L"\\DosDevices\\VBoxGuest" + +#elif defined(RT_OS_OS2) + /* No automatic buffering, size not encoded. */ +# define VBGL_IOCTL_CATEGORY 0xc2 +# define VBGL_IOCTL_CODE_SIZE(Function, Size) ((unsigned char)(Function)) +# define VBGL_IOCTL_CODE_BIG(Function) ((unsigned char)(Function)) +# define VBGL_IOCTL_CATEGORY_FAST 0xc3 /**< Also defined in VBoxGuestA-os2.asm. */ +# define VBGL_IOCTL_CODE_FAST(Function) ((unsigned char)(Function)) +# define VBGL_IOCTL_CODE_STRIPPED(a_uIOCtl) (a_uIOCtl) +# define VBOXGUEST_DEVICE_NAME "\\Dev\\VBoxGst$" +/** Short device name for AttachDD. + * @note Case sensitive. Must match what VBoxGuestA-os2.asm says! */ +# define VBOXGUEST_DEVICE_NAME_SHORT "vboxgst$" + +#elif defined(RT_OS_SOLARIS) + /* No automatic buffering, size limited to 255 bytes => use VBGLBIGREQ for everything. */ +# include +# define VBGL_IOCTL_CODE_SIZE(Function, Size) ((uintptr_t)(_IOWRN('V', (Function), sizeof(VBGLREQHDR)))) +# define VBGL_IOCTL_CODE_BIG(Function) _IOWRN('V', (Function), sizeof(VBGLREQHDR)) +# define VBGL_IOCTL_CODE_FAST(Function) _IO( 'F', (Function)) +# define VBGL_IOCTL_CODE_STRIPPED(a_uIOCtl) (a_uIOCtl) +# define VBGL_IOCTL_IS_FAST(a_uIOCtl) ( ((a_uIOCtl) & 0x0000ff00) == ('F' << 8) ) + +#elif defined(RT_OS_LINUX) + /* No automatic buffering, size limited to 16KB. */ +# include +# define VBGL_IOCTL_CODE_SIZE(Function, Size) _IOC(_IOC_READ | _IOC_WRITE, 'V', (Function), (Size)) +# define VBGL_IOCTL_CODE_BIG(Function) _IO('V', (Function)) +# define VBGL_IOCTL_CODE_FAST(Function) _IO('F', (Function)) +# define VBGL_IOCTL_CODE_STRIPPED(a_uIOCtl) _IOC_NR((a_uIOCtl)) +# define VBOXGUEST_USER_DEVICE_NAME "/dev/vboxuser" + +#elif defined(RT_OS_HAIKU) + /* No automatic buffering, size not encoded. */ + /** @todo do something better */ +# define VBGL_IOCTL_CODE_SIZE(Function, Size) (0x56420000 | (Function)) +# define VBGL_IOCTL_CODE_BIG(Function) (0x56420000 | (Function)) +# define VBGL_IOCTL_CODE_FAST(Function) (0x56420000 | (Function)) +# define VBGL_IOCTL_CODE_STRIPPED(a_uIOCtl) (a_uIOCtl) +# define VBOXGUEST_DEVICE_NAME "/dev/misc/vboxguest" + +#else /* BSD Like */ + /* Automatic buffering, size limited to 4KB on *BSD and 8KB on Darwin - commands the limit, 4KB. */ +# include +# define VBGL_IOCTL_CODE_SIZE(Function, Size) _IOC(IOC_INOUT, 'V', (Function), (Size)) +# define VBGL_IOCTL_CODE_BIG(Function) _IO('V', (Function)) +# define VBGL_IOCTL_CODE_FAST(Function) _IO('F', (Function)) +# define VBGL_IOCTL_CODE_STRIPPED(a_uIOCtl) ((a_uIOCtl) & ~(_IOC(0,0,0,IOCPARM_MASK))) +# define VBGL_IOCTL_IS_FAST(a_uIOCtl) ( IOCGROUP(a_uIOCtl) == 'F' ) +# if defined(RT_OS_DARWIN) +# define VBOXGUEST_DEVICE_NAME "/dev/vboxguest" +# define VBOXGUEST_USER_DEVICE_NAME "/dev/vboxguestu" +# endif + +#endif + +/** @todo It would be nice if we could have two defines without paths. */ + +/** @def VBOXGUEST_DEVICE_NAME + * The support device name. */ +#ifndef VBOXGUEST_DEVICE_NAME /* PORTME */ +# define VBOXGUEST_DEVICE_NAME "/dev/vboxguest" +#endif + +/** @def VBOXGUEST_USER_DEVICE_NAME + * The support device name of the user accessible device node. */ +#ifndef VBOXGUEST_USER_DEVICE_NAME +# define VBOXGUEST_USER_DEVICE_NAME VBOXGUEST_DEVICE_NAME +#endif + + +/** + * The VBoxGuest I/O control version. + * + * As usual, the high word contains the major version and changes to it + * signifies incompatible changes. + * + * The lower word is the minor version number, it is increased when new + * functions are added or existing changed in a backwards compatible manner. + */ +#define VBGL_IOC_VERSION UINT32_C(0x00010000) + + + +/** @name VBGL_IOCTL_DRIVER_INFO + * Adjust and get driver information. + * + * @note May switch the session to a backwards compatible interface version if + * uClientVersion indicates older client code. + * + * @{ + */ +#define VBGL_IOCTL_DRIVER_VERSION_INFO VBGL_IOCTL_CODE_SIZE(0, VBGL_IOCTL_DRIVER_VERSION_INFO_SIZE) +#define VBGL_IOCTL_DRIVER_VERSION_INFO_SIZE sizeof(VBGLIOCDRIVERVERSIONINFO) +#define VBGL_IOCTL_DRIVER_VERSION_INFO_SIZE_IN RT_UOFFSET_AFTER(VBGLIOCDRIVERVERSIONINFO, u.In) +#define VBGL_IOCTL_DRIVER_VERSION_INFO_SIZE_OUT sizeof(VBGLIOCDRIVERVERSIONINFO) +typedef struct VBGLIOCDRIVERVERSIONINFO +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** The requested interface version number (VBGL_IOC_VERSION). */ + uint32_t uReqVersion; + /** The minimum interface version number + * (typically the major version part of VBGL_IOC_VERSION). */ + uint32_t uMinVersion; + /** Reserved, MBZ. */ + uint32_t uReserved1; + /** Reserved, MBZ. */ + uint32_t uReserved2; + } In; + struct + { + /** Interface version for this session (typically VBGL_IOC_VERSION). */ + uint32_t uSessionVersion; + /** The version of the IDC interface (VBGL_IOC_VERSION). */ + uint32_t uDriverVersion; + /** The SVN revision of the driver. + * This will be set to 0 if not compiled into the driver. */ + uint32_t uDriverRevision; + /** Reserved \#1 (will be returned as zero until defined). */ + uint32_t uReserved1; + /** Reserved \#2 (will be returned as zero until defined). */ + uint32_t uReserved2; + } Out; + } u; +} VBGLIOCDRIVERVERSIONINFO, RT_FAR *PVBGLIOCDRIVERVERSIONINFO; +AssertCompileSize(VBGLIOCDRIVERVERSIONINFO, 24 + 20); +#if !defined(__GNUC__) /* Some GCC versions can't handle the complicated RT_UOFFSET_AFTER macro, it seems. */ \ + && (!defined(RT_OS_OS2) || (!defined(__IBMC__) && !defined(__IBMCPP__) && (!defined(__WATCOMC__) || !defined(__cplusplus)))) +AssertCompile(VBGL_IOCTL_DRIVER_VERSION_INFO_SIZE_IN == 24 + 16); +#endif +/** @} */ + + +/** @name VBGL_IOCTL_GET_PORT_INFO + * Query VMMDev I/O port region and MMIO mapping address. + * @remarks Ring-0 only. + * @{ + */ +#define VBGL_IOCTL_GET_VMMDEV_IO_INFO VBGL_IOCTL_CODE_SIZE(1, VBGL_IOCTL_GET_VMMDEV_IO_INFO_SIZE) +#define VBGL_IOCTL_GET_VMMDEV_IO_INFO_SIZE sizeof(VBGLIOCGETVMMDEVIOINFO) +#define VBGL_IOCTL_GET_VMMDEV_IO_INFO_SIZE_IN sizeof(VBGLREQHDR) +#define VBGL_IOCTL_GET_VMMDEV_IO_INFO_SIZE_OUT sizeof(VBGLIOCGETVMMDEVIOINFO) +typedef struct VBGLIOCGETVMMDEVIOINFO +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** The MMIO mapping. NULL if no MMIO region. */ + struct VMMDevMemory volatile RT_FAR *pvVmmDevMapping; + /** The I/O port address. */ + RTIOPORT IoPort; + /** Padding, ignore. */ + RTIOPORT auPadding[HC_ARCH_BITS == 64 ? 3 : 1]; + } Out; + } u; +} VBGLIOCGETVMMDEVIOINFO, RT_FAR *PVBGLIOCGETVMMDEVIOINFO; +AssertCompileSize(VBGLIOCGETVMMDEVIOINFO, 24 + (HC_ARCH_BITS == 64 ? 16 : 8)); +/** @} */ + + +/** @name VBGL_IOCTL_VMMDEV_REQUEST + * IOCTL to VBoxGuest to perform a VMM Device request less than 1KB in size. + * @{ + */ +#define VBGL_IOCTL_VMMDEV_REQUEST(a_cb) VBGL_IOCTL_CODE_SIZE(2, (a_cb)) +/** @} */ + + +/** @name VBGL_IOCTL_VMMDEV_REQUEST_BIG + * IOCTL to VBoxGuest to perform a VMM Device request that can 1KB or larger. + * @{ + */ +#define VBGL_IOCTL_VMMDEV_REQUEST_BIG VBGL_IOCTL_CODE_BIG(3) +/** @} */ + +#ifdef VBOX_WITH_HGCM + +/** @name VBGL_IOCTL_HGCM_CONNECT + * Connect to a HGCM service. + * @{ */ +# define VBGL_IOCTL_HGCM_CONNECT VBGL_IOCTL_CODE_SIZE(4, VBGL_IOCTL_HGCM_CONNECT_SIZE) +# define VBGL_IOCTL_HGCM_CONNECT_SIZE sizeof(VBGLIOCHGCMCONNECT) +# define VBGL_IOCTL_HGCM_CONNECT_SIZE_IN sizeof(VBGLIOCHGCMCONNECT) +# define VBGL_IOCTL_HGCM_CONNECT_SIZE_OUT RT_UOFFSET_AFTER(VBGLIOCHGCMCONNECT, u.Out) +typedef struct VBGLIOCHGCMCONNECT +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + HGCMServiceLocation Loc; + } In; + struct + { + uint32_t idClient; + } Out; + } u; +} VBGLIOCHGCMCONNECT, RT_FAR *PVBGLIOCHGCMCONNECT; +AssertCompileSize(VBGLIOCHGCMCONNECT, 24 + 132); +#if !defined(__GNUC__) /* Some GCC versions can't handle the complicated RT_UOFFSET_AFTER macro, it seems. */ \ + && (!defined(RT_OS_OS2) || (!defined(__IBMC__) && !defined(__IBMCPP__) && (!defined(__WATCOMC__) || !defined(__cplusplus)))) +AssertCompile(VBGL_IOCTL_HGCM_CONNECT_SIZE_OUT == 24 + 4); +#endif +/** @} */ + + +/** @name VBGL_IOCTL_HGCM_DISCONNECT + * Disconnect from a HGCM service. + * @{ */ +# define VBGL_IOCTL_HGCM_DISCONNECT VBGL_IOCTL_CODE_SIZE(5, VBGL_IOCTL_HGCM_DISCONNECT_SIZE) +# define VBGL_IOCTL_HGCM_DISCONNECT_SIZE sizeof(VBGLIOCHGCMDISCONNECT) +# define VBGL_IOCTL_HGCM_DISCONNECT_SIZE_IN sizeof(VBGLIOCHGCMDISCONNECT) +# define VBGL_IOCTL_HGCM_DISCONNECT_SIZE_OUT sizeof(VBGLREQHDR) +/** @note This is also used by a VbglR0 API. */ +typedef struct VBGLIOCHGCMDISCONNECT +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + uint32_t idClient; + } In; + } u; +} VBGLIOCHGCMDISCONNECT, RT_FAR *PVBGLIOCHGCMDISCONNECT; +AssertCompileSize(VBGLIOCHGCMDISCONNECT, 24 + 4); +/** @} */ + + +/** @name VBGL_IOCTL_HGCM_CALL, VBGL_IOCTL_HGCM_CALL_WITH_USER_DATA + * + * Make a call to a HGCM service. There are several variations here. + * + * The VBGL_IOCTL_HGCM_CALL_WITH_USER_DATA variation is for other drivers (like + * the graphics ones) passing on requests from user land that contains user + * data. These calls are always interruptible. + * + * @{ */ +# define VBGL_IOCTL_HGCM_CALL_32(a_cb) VBGL_IOCTL_CODE_SIZE(6, (a_cb)) +# define VBGL_IOCTL_HGCM_CALL_64(a_cb) VBGL_IOCTL_CODE_SIZE(7, (a_cb)) +# if ARCH_BITS == 64 +# define VBGL_IOCTL_HGCM_CALL(a_cb) VBGL_IOCTL_HGCM_CALL_64(a_cb) +# else +# define VBGL_IOCTL_HGCM_CALL(a_cb) VBGL_IOCTL_HGCM_CALL_32(a_cb) +# endif +# define VBGL_IOCTL_HGCM_CALL_WITH_USER_DATA(a_cb) VBGL_IOCTL_CODE_SIZE(8, (a_cb)) +/** @} */ + + +/** @name VBGL_IOCTL_IDC_HGCM_FAST_CALL + * + * Variant of VBGL_IOCTL_HGCM_CALL for drivers that submits the request as-is to + * the host and handles the waiting, the caller does all the rest. + * + * @note ring-0 only. + * @note Size is not encoded in the I/O control code. + * @{ + */ +#define VBGL_IOCTL_IDC_HGCM_FAST_CALL VBGL_IOCTL_CODE_SIZE(61, sizeof(VBGLIOCIDCHGCMFASTCALL)) +#define VBGL_IOCTL_IDC_HGCM_FAST_CALL_SIZE(a_cb) (a_cb) +#define VBGL_IOCTL_IDC_HGCM_FAST_CALL_SIZE_IN(a_cb) (a_cb) +#define VBGL_IOCTL_IDC_HGCM_FAST_CALL_SIZE_OUT(a_cb) (a_cb) +#pragma pack(4) /* Want it to fit nicely with the 44 byte VMMDevHGCMCall and optimally align 64-bit parameters structures. */ +typedef struct VBGLIOCIDCHGCMFASTCALL +{ + /** The header. */ + VBGLREQHDR Hdr; + /** The physical address of the following VMMDevHGCMCall structure. */ + RTGCPHYS32 GCPhysReq; + /** Set if interruptible. */ + bool fInterruptible; + /** Reserved. */ + uint8_t abReserved0[3]; + uint64_t uTimestamp[2]; + uint8_t abReserved1[4]; + /* After this structure follows a VMMDevHGCMCall strcuture (44 bytes), then + zero or more HGCMFunctionParameter structures (12 or 16 bytes), and finally + page lists and embedded buffers. */ +} VBGLIOCIDCHGCMFASTCALL, RT_FAR *PVBGLIOCIDCHGCMFASTCALL; +#pragma pack() +AssertCompileSize(VBGLIOCIDCHGCMFASTCALL, /* 24 + 4 + 1 + 3 + 2*8 + 4 = 0x34 (52) = */ 0x34); + +/** + * Macro for initializing VBGLIOCIDCHGCMFASTCALL and the following + * VMMDevHGCMCall structures. + * + * @param a_pHdr The request header to initialize. + * @param a_HdrPhys The 32-bit physical address corresponding to @a a_pHdr. + * @param a_pCall Pointer to the VMMDevHGCMCall structure. + * @param a_idClient The HGCM client ID. + * @param a_uFunction The HGCM function number. + * @param a_cParms The number of parameters following @a a_pCall. + * @param a_cbReq The size of the whole request. + */ +#define VBGLIOCIDCHGCMFASTCALL_INIT(a_pHdr, a_HdrPhys, a_pCall, a_idClient, a_uFunction, a_cParms, a_cbReq) \ + do { \ + Assert((uintptr_t)(a_pHdr) + sizeof(VBGLIOCIDCHGCMFASTCALL) == (uintptr_t)(a_pCall)); \ + VBGLREQHDR_INIT_EX(&(a_pHdr)->Hdr, a_cbReq, a_cbReq); \ + pReq->Hdr.GCPhysReq = (a_HdrPhys) + sizeof(VBGLIOCIDCHGCMFASTCALL); \ + pReq->Hdr.fInterruptible = false; \ + \ + (a_pCall)->header.header.size = (a_cbReq) - sizeof(VBGLIOCIDCHGCMFASTCALL); \ + (a_pCall)->header.header.version = VBGLREQHDR_VERSION; \ + (a_pCall)->header.header.requestType= (ARCH_BITS == 64 ? VMMDevReq_HGCMCall64 : VMMDevReq_HGCMCall32); \ + (a_pCall)->header.header.rc = VERR_INTERNAL_ERROR; \ + (a_pCall)->header.header.reserved1 = 0; \ + (a_pCall)->header.header.fRequestor = VMMDEV_REQUESTOR_KERNEL | VMMDEV_REQUESTOR_USR_DRV_OTHER \ + | VMMDEV_REQUESTOR_CON_DONT_KNOW | VMMDEV_REQUESTOR_TRUST_NOT_GIVEN; \ + (a_pCall)->header.fu32Flags = 0; \ + (a_pCall)->header.result = VERR_INTERNAL_ERROR; \ + (a_pCall)->u32ClientID = (a_idClient); \ + (a_pCall)->u32Function = (a_uFunction); \ + (a_pCall)->cParms = (a_cParms); \ + } while (0) + + +/** @} */ + +#endif /* VBOX_WITH_HGCM */ + + +/** @name VBGL_IOCTL_LOG + * IOCTL to VBoxGuest to perform backdoor logging. + * @{ */ +#define VBOXGUEST_IOCTL_LOG(Size) +#define VBGL_IOCTL_LOG(a_cchMsg) VBGL_IOCTL_CODE_BIG(9) +#define VBGL_IOCTL_LOG_SIZE(a_cchMsg) (sizeof(VBGLREQHDR) + (a_cchMsg) + 1) +#define VBGL_IOCTL_LOG_SIZE_IN(a_cchMsg) (sizeof(VBGLREQHDR) + (a_cchMsg) + 1) +#define VBGL_IOCTL_LOG_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCLOG +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** The log message. + * The length is determined from the input size and zero termination. */ + char szMsg[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + } In; + } u; +} VBGLIOCLOG, RT_FAR *PVBGLIOCLOG; +/** @} */ + + +/** @name VBGL_IOCTL_WAIT_FOR_EVENTS + * Wait for a VMMDev host event notification. + * @{ + */ +#define VBGL_IOCTL_WAIT_FOR_EVENTS VBGL_IOCTL_CODE_SIZE(10, VBGL_IOCTL_WAIT_FOR_EVENTS_SIZE) +#define VBGL_IOCTL_WAIT_FOR_EVENTS_SIZE sizeof(VBGLIOCWAITFOREVENTS) +#define VBGL_IOCTL_WAIT_FOR_EVENTS_SIZE_IN sizeof(VBGLIOCWAITFOREVENTS) +#define VBGL_IOCTL_WAIT_FOR_EVENTS_SIZE_OUT RT_UOFFSET_AFTER(VBGLIOCWAITFOREVENTS, u.Out) +typedef struct VBGLIOCWAITFOREVENTS +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Timeout in milliseconds. */ + uint32_t cMsTimeOut; + /** Events to wait for. */ + uint32_t fEvents; + } In; + struct + { + /** Events that occurred. */ + uint32_t fEvents; + } Out; + } u; +} VBGLIOCWAITFOREVENTS, RT_FAR *PVBGLIOCWAITFOREVENTS; +AssertCompileSize(VBGLIOCWAITFOREVENTS, 24 + 8); +/** @} */ + + +/** @name VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS + * IOCTL to VBoxGuest to interrupt (cancel) any pending + * VBGL_IOCTL_WAIT_FOR_EVENTS and return. + * + * Handled inside the guest additions and not seen by the host at all. + * After calling this, VBGL_IOCTL_WAIT_FOR_EVENTS should no longer be called in + * the same session. At the time of writing this is not enforced; at the time + * of reading it may be. + * @see VBGL_IOCTL_WAIT_FOR_EVENTS + * + * @{ + */ +#define VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS VBGL_IOCTL_CODE_SIZE(11, VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS_SIZE) +#define VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS_SIZE sizeof(VBGLREQHDR) +#define VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS_SIZE_IN sizeof(VBGLREQHDR) +#define VBGL_IOCTL_INTERRUPT_ALL_WAIT_FOR_EVENTS_SIZE_OUT sizeof(VBGLREQHDR) +/** @} */ + + +/** @name VBGL_IOCTL_CHANGE_FILTER_MASK + * IOCTL to VBoxGuest to control the event filter mask. + * @{ */ +#define VBGL_IOCTL_CHANGE_FILTER_MASK VBGL_IOCTL_CODE_SIZE(12, VBGL_IOCTL_CHANGE_FILTER_MASK_SIZE) +#define VBGL_IOCTL_CHANGE_FILTER_MASK_SIZE sizeof(VBGLIOCCHANGEFILTERMASK) +#define VBGL_IOCTL_CHANGE_FILTER_MASK_SIZE_IN sizeof(VBGLIOCCHANGEFILTERMASK) +#define VBGL_IOCTL_CHANGE_FILTER_MASK_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCCHANGEFILTERMASK +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Flags to set. */ + uint32_t fOrMask; + /** Flags to remove. */ + uint32_t fNotMask; + } In; + } u; +} VBGLIOCCHANGEFILTERMASK, RT_FAR *PVBGLIOCCHANGEFILTERMASK; +AssertCompileSize(VBGLIOCCHANGEFILTERMASK, 24 + 8); +/** @} */ + + +/** @name VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES + * IOCTL to for acquiring and releasing guest capabilities. + * + * This is used for multiple purposes: + * 1. By doing @a acquire r3 client application (e.g. VBoxTray) claims it will + * use the given session for performing operations like @a seamless or + * @a auto-resize, thus, if the application terminates, the driver will + * automatically cleanup the caps reported to host, so that host knows guest + * does not support them anymore + * 2. In a multy-user environment this will not allow r3 applications (like + * VBoxTray) running in different user sessions simultaneously to interfere + * with each other. An r3 client application (like VBoxTray) is responsible + * for Acquiring/Releasing caps properly as needed. + * + * + * VERR_RESOURCE_BUSY is returned if any capabilities in the fOrMask are + * currently acquired by some other VBoxGuest session. + * + * @todo Rename to VBGL_IOCTL_ACQUIRE_GUEST_CAPS + * @{ + */ +#define VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES VBGL_IOCTL_CODE_SIZE(13, VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES_SIZE) +#define VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES_SIZE sizeof(VBGLIOCACQUIREGUESTCAPS) +#define VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES_SIZE_IN sizeof(VBGLIOCACQUIREGUESTCAPS) +#define VBGL_IOCTL_ACQUIRE_GUEST_CAPABILITIES_SIZE_OUT sizeof(VBGLREQHDR) + +/** Default operation (full acquire/release). */ +#define VBGL_IOC_AGC_FLAGS_DEFAULT UINT32_C(0x00000000) +/** Configures VBoxGuest to use the specified caps in Acquire mode, w/o making + * any caps acquisition/release. This is only possible to set acquire mode for + * caps, but not clear it, so fNotMask is ignored when this flag is set. */ +#define VBGL_IOC_AGC_FLAGS_CONFIG_ACQUIRE_MODE UINT32_C(0x00000001) +/** Valid flag mask. */ +#define VBGL_IOC_AGC_FLAGS_VALID_MASK UINT32_C(0x00000001) + +typedef struct VBGLIOCACQUIREGUESTCAPS +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Acquire flags (VBGL_IOC_AGC_FLAGS_XXX). */ + uint32_t fFlags; + /** Guest capabilities to acquire (VMMDEV_GUEST_SUPPORTS_XXX). */ + uint32_t fOrMask; + /** Guest capabilities to release (VMMDEV_GUEST_SUPPORTS_XXX). */ + uint32_t fNotMask; + } In; + } u; +} VBGLIOCACQUIREGUESTCAPS, RT_FAR *PVBGLIOCACQUIREGUESTCAPS; +AssertCompileSize(VBGLIOCACQUIREGUESTCAPS, 24 + 12); +/** @} */ + + +/** @name VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES + * IOCTL to VBoxGuest to set guest capabilities. + * @{ */ +#define VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES VBGL_IOCTL_CODE_SIZE(14, VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES_SIZE) +#define VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES_SIZE sizeof(VBGLIOCSETGUESTCAPS) +#define VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES_SIZE_IN sizeof(VBGLIOCSETGUESTCAPS) +#define VBGL_IOCTL_CHANGE_GUEST_CAPABILITIES_SIZE_OUT sizeof(VBGLIOCSETGUESTCAPS) +typedef struct VBGLIOCSETGUESTCAPS +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** The capabilities to set (VMMDEV_GUEST_SUPPORTS_XXX). */ + uint32_t fOrMask; + /** The capabilities to drop (VMMDEV_GUEST_SUPPORTS_XXX). */ + uint32_t fNotMask; + } In; + struct + { + /** The capabilities held by the session after the call (VMMDEV_GUEST_SUPPORTS_XXX). */ + uint32_t fSessionCaps; + /** The capabilities for all the sessions after the call (VMMDEV_GUEST_SUPPORTS_XXX). */ + uint32_t fGlobalCaps; + } Out; + } u; +} VBGLIOCSETGUESTCAPS, RT_FAR *PVBGLIOCSETGUESTCAPS; +AssertCompileSize(VBGLIOCSETGUESTCAPS, 24 + 8); +typedef VBGLIOCSETGUESTCAPS VBoxGuestSetCapabilitiesInfo; +/** @} */ + + +/** @name VBGL_IOCTL_SET_MOUSE_STATUS + * IOCTL to VBoxGuest to update the mouse status features. + * @{ */ +#define VBGL_IOCTL_SET_MOUSE_STATUS VBGL_IOCTL_CODE_SIZE(15, VBGL_IOCTL_SET_MOUSE_STATUS_SIZE) +#define VBGL_IOCTL_SET_MOUSE_STATUS_SIZE sizeof(VBGLIOCSETMOUSESTATUS) +#define VBGL_IOCTL_SET_MOUSE_STATUS_SIZE_IN sizeof(VBGLIOCSETMOUSESTATUS) +#define VBGL_IOCTL_SET_MOUSE_STATUS_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCSETMOUSESTATUS +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Mouse status flags (VMMDEV_MOUSE_XXX). */ + uint32_t fStatus; + } In; + } u; +} VBGLIOCSETMOUSESTATUS, RT_FAR *PVBGLIOCSETMOUSESTATUS; +/** @} */ + + +/** @name VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK + * + * IOCTL to for setting the mouse driver callback. + * @note The callback will be called in interrupt context with the VBoxGuest + * device event spinlock held. + * @note ring-0 only. + * + * @{ */ +#define VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK VBGL_IOCTL_CODE_SIZE(16, VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK_SIZE) +#define VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK_SIZE sizeof(VBGLIOCSETMOUSENOTIFYCALLBACK) +#define VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK_SIZE_IN sizeof(VBGLIOCSETMOUSENOTIFYCALLBACK) +#define VBGL_IOCTL_SET_MOUSE_NOTIFY_CALLBACK_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCSETMOUSENOTIFYCALLBACK +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Mouse notification callback function. */ + PFNVBOXGUESTMOUSENOTIFY pfnNotify; + /** The callback argument. */ + void RT_FAR *pvUser; + } In; + } u; +} VBGLIOCSETMOUSENOTIFYCALLBACK, RT_FAR *PVBGLIOCSETMOUSENOTIFYCALLBACK; +/** @} */ + + +/** @name VBGL_IOCTL_CHECK_BALLOON + * IOCTL to VBoxGuest to check memory ballooning. + * + * The guest kernel module / device driver will ask the host for the current size of + * the balloon and adjust the size. Or it will set fHandledInR0 = false and R3 is + * responsible for allocating memory and calling R0 (VBGL_IOCTL_CHANGE_BALLOON). + * @{ */ +#define VBGL_IOCTL_CHECK_BALLOON VBGL_IOCTL_CODE_SIZE(17, VBGL_IOCTL_CHECK_BALLOON_SIZE) +#define VBGL_IOCTL_CHECK_BALLOON_SIZE sizeof(VBGLIOCCHECKBALLOON) +#define VBGL_IOCTL_CHECK_BALLOON_SIZE_IN sizeof(VBGLREQHDR) +#define VBGL_IOCTL_CHECK_BALLOON_SIZE_OUT sizeof(VBGLIOCCHECKBALLOON) +typedef struct VBGLIOCCHECKBALLOON +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** The size of the balloon in chunks of 1MB. */ + uint32_t cBalloonChunks; + /** false = handled in R0, no further action required. + * true = allocate balloon memory in R3. */ + bool fHandleInR3; + /** Explicit padding, please ignore. */ + bool afPadding[3]; + } Out; + } u; +} VBGLIOCCHECKBALLOON, RT_FAR *PVBGLIOCCHECKBALLOON; +AssertCompileSize(VBGLIOCCHECKBALLOON, 24 + 8); +typedef VBGLIOCCHECKBALLOON VBoxGuestCheckBalloonInfo; +/** @} */ + + +/** @name VBGL_IOCTL_CHANGE_BALLOON + * IOCTL to VBoxGuest to supply or revoke one chunk for ballooning. + * + * The guest kernel module / device driver will lock down supplied memory or + * unlock reclaimed memory and then forward the physical addresses of the + * changed balloon chunk to the host. + * + * @{ */ +#define VBGL_IOCTL_CHANGE_BALLOON VBGL_IOCTL_CODE_SIZE(18, VBGL_IOCTL_CHANGE_BALLOON_SIZE) +#define VBGL_IOCTL_CHANGE_BALLOON_SIZE sizeof(VBGLIOCCHANGEBALLOON) +#define VBGL_IOCTL_CHANGE_BALLOON_SIZE_IN sizeof(VBGLIOCCHANGEBALLOON) +#define VBGL_IOCTL_CHANGE_BALLOON_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCCHANGEBALLOON +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Address of the chunk (user space address). */ + RTR3PTR pvChunk; + /** Explicit alignment padding, MBZ. */ + uint8_t abPadding[ARCH_BITS == 64 ? 0 + 7 : 4 + 7]; + /** true = inflate, false = deflate. */ + bool fInflate; + } In; + } u; +} VBGLIOCCHANGEBALLOON, RT_FAR *PVBGLIOCCHANGEBALLOON; +AssertCompileSize(VBGLIOCCHANGEBALLOON, 24+16); +/** @} */ + + +/** @name VBGL_IOCTL_WRITE_CORE_DUMP + * IOCTL to VBoxGuest to write guest core. + * @{ */ +#define VBGL_IOCTL_WRITE_CORE_DUMP VBGL_IOCTL_CODE_SIZE(19, VBGL_IOCTL_WRITE_CORE_DUMP_SIZE) +#define VBGL_IOCTL_WRITE_CORE_DUMP_SIZE sizeof(VBGLIOCWRITECOREDUMP) +#define VBGL_IOCTL_WRITE_CORE_DUMP_SIZE_IN sizeof(VBGLIOCWRITECOREDUMP) +#define VBGL_IOCTL_WRITE_CORE_DUMP_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCWRITECOREDUMP +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** Flags (reserved, MBZ). */ + uint32_t fFlags; + } In; + } u; +} VBGLIOCWRITECOREDUMP, RT_FAR *PVBGLIOCWRITECOREDUMP; +AssertCompileSize(VBGLIOCWRITECOREDUMP, 24 + 4); +typedef VBGLIOCWRITECOREDUMP VBoxGuestWriteCoreDump; +/** @} */ + + +#ifdef VBOX_WITH_DPC_LATENCY_CHECKER +/** @name VBGL_IOCTL_DPC_LATENCY_CHECKER + * IOCTL to VBoxGuest to perform DPC latency tests, printing the result in + * the release log on the host. Takes no data, returns no data. + * @{ */ +# define VBGL_IOCTL_DPC_LATENCY_CHECKER VBGL_IOCTL_CODE_SIZE(20, VBGL_IOCTL_DPC_LATENCY_CHECKER_SIZE) +# define VBGL_IOCTL_DPC_LATENCY_CHECKER_SIZE sizeof(VBGLREQHDR) +# define VBGL_IOCTL_DPC_LATENCY_CHECKER_SIZE_IN sizeof(VBGLREQHDR) +# define VBGL_IOCTL_DPC_LATENCY_CHECKER_SIZE_OUT sizeof(VBGLREQHDR) +/** @} */ +#endif + + +#ifdef RT_OS_OS2 +/** + * The data buffer layout for the IDC entry point (AttachDD). + * + * @remark This is defined in multiple 16-bit headers / sources. + * Some places it's called VBGOS2IDC to short things a bit. + */ +typedef struct VBGLOS2ATTACHDD +{ + /** VBGL_IOC_VERSION. */ + uint32_t u32Version; + /** Opaque session handle. */ + uint32_t u32Session; + + /** + * The 32-bit service entry point. + * + * @returns VBox status code. + * @param u32Session The session handle (PVBOXGUESTSESSION). + * @param iFunction The requested function. + * @param pReqHdr The input/output data buffer. The caller + * ensures that this cannot be swapped out, or that + * it's acceptable to take a page in fault in the + * current context. If the request doesn't take + * input or produces output, apssing NULL is okay. + * @param cbReq The size of the data buffer. + */ +# if ARCH_BITS == 32 || defined(DOXYGEN_RUNNING) + DECLCALLBACKMEMBER(int, pfnServiceEP,(uint32_t u32Session, unsigned iFunction, PVBGLREQHDR pReqHdr, size_t cbReq)); +# else + uint32_t pfnServiceEP; +#endif + + /** The 16-bit service entry point for C code (cdecl). + * + * It's the same as the 32-bit entry point, but the types has + * changed to 16-bit equivalents. + * + * @code + * int far cdecl + * VBoxGuestOs2IDCService16(uint32_t u32Session, uint16_t iFunction, + * PVBGLREQHDR fpvData, uint16_t cbData); + * @endcode + */ +# if ARCH_BITS == 16 || defined(DOXYGEN_RUNNING) + DECLCALLBACKMEMBER(int, fpfnServiceEP,(uint32_t u32Session, uint16_t iFunction, PVBGLREQHDR fpvData, uint16_t cbData)); +# else + RTFAR16 fpfnServiceEP; +# endif + + /** The 16-bit service entry point for Assembly code (register). + * + * This is just a wrapper around fpfnServiceEP to simplify calls + * from 16-bit assembly code. + * + * @returns (e)ax: VBox status code; cx: The amount of data returned. + * + * @param u32Session eax - The above session handle. + * @param iFunction dl - The requested function. + * @param pvData es:bx - The input/output data buffer. + * @param cbData cx - The size of the data buffer. + */ + RTFAR16 fpfnServiceAsmEP; +} VBGLOS2ATTACHDD; +/** Pointer to VBOXGUESTOS2IDCCONNECT buffer. */ +typedef VBGLOS2ATTACHDD RT_FAR *PVBGLOS2ATTACHDD; + +/** + * Prototype for the 16-bit callback returned by AttachDD on OS/2. + * @param pAttachInfo Pointer to structure to fill in. + */ +# if defined(__IBMC__) || defined(__IBMCPP__) +typedef void (* __cdecl RT_FAR_CODE PFNVBGLOS2ATTACHDD)(PVBGLOS2ATTACHDD pAttachInfo); +# else +typedef void (__cdecl RT_FAR_CODE *PFNVBGLOS2ATTACHDD)(PVBGLOS2ATTACHDD pAttachInfo); +# endif +#endif /* RT_OS_OS2 */ + + +/** @name VBGL_IOCL_IDC_CONNECT + * IDC client connect request. + * + * On platforms other than Windows and OS/2, this will also create a kernel + * session for the caller. + * + * @note ring-0 only. + * @{ + */ +#define VBGL_IOCTL_IDC_CONNECT VBGL_IOCTL_CODE_SIZE(63, VBGL_IOCTL_IDC_CONNECT_SIZE) +#define VBGL_IOCTL_IDC_CONNECT_SIZE sizeof(VBGLIOCIDCCONNECT) +#define VBGL_IOCTL_IDC_CONNECT_SIZE_IN RT_UOFFSET_AFTER(VBGLIOCIDCCONNECT, u.In) +#define VBGL_IOCTL_IDC_CONNECT_SIZE_OUT sizeof(VBGLIOCIDCCONNECT) +typedef struct VBGLIOCIDCCONNECT +{ + /** The header. */ + VBGLREQHDR Hdr; + /** The payload union. */ + union + { + struct + { + /** VBGL_IOCTL_IDC_CONNECT_MAGIC_COOKIE. */ + uint32_t u32MagicCookie; + /** The desired version of the I/O control interface (VBGL_IOC_VERSION). */ + uint32_t uReqVersion; + /** The minimum version of the I/O control interface (VBGL_IOC_VERSION). */ + uint32_t uMinVersion; + /** Reserved, MBZ. */ + uint32_t uReserved; + } In; + struct + { + /** The session handle (opaque). */ +#if ARCH_BITS >= 32 + void RT_FAR *pvSession; +#else + uint32_t pvSession; +#endif + /** The version of the I/O control interface for this session + * (typically VBGL_IOC_VERSION). */ + uint32_t uSessionVersion; + /** The I/O control interface version for of the driver (VBGL_IOC_VERSION). */ + uint32_t uDriverVersion; + /** The SVN revision of the driver. + * This will be set to 0 if not compiled into the driver. */ + uint32_t uDriverRevision; + /** Reserved \#1 (will be returned as zero until defined). */ + uint32_t uReserved1; + /** Reserved \#2 (will be returned as NULL until defined). */ + void RT_FAR *pvReserved2; + } Out; + } u; +} VBGLIOCIDCCONNECT, RT_FAR *PVBGLIOCIDCCONNECT; +AssertCompileSize(VBGLIOCIDCCONNECT, 24 + 16 + (ARCH_BITS == 64 ? 8 : 4) * 2); +#if !defined(__GNUC__) /* Some GCC versions can't handle the complicated RT_UOFFSET_AFTER macro, it seems. */ \ + && (!defined(RT_OS_OS2) || (!defined(__IBMC__) && !defined(__IBMCPP__) && (!defined(__WATCOMC__) || !defined(__cplusplus)))) +AssertCompile(VBGL_IOCTL_IDC_CONNECT_SIZE_IN == 24 + 16); +#endif +#define VBGL_IOCTL_IDC_CONNECT_MAGIC_COOKIE UINT32_C(0x55aa4d5a) /**< Magic value for doing an IDC connect. */ +/** @} */ + + +/** @name VBGL_IOCL_IDC_DISCONNECT + * IDC client disconnect request. + * + * This will destroy the kernel session associated with the IDC connection. + * + * @note ring-0 only. + * @{ + */ +#define VBGL_IOCTL_IDC_DISCONNECT VBGL_IOCTL_CODE_SIZE(62, VBGL_IOCTL_IDC_DISCONNECT_SIZE) +#define VBGL_IOCTL_IDC_DISCONNECT_SIZE sizeof(VBGLIOCIDCDISCONNECT) +#define VBGL_IOCTL_IDC_DISCONNECT_SIZE_IN sizeof(VBGLIOCIDCDISCONNECT) +#define VBGL_IOCTL_IDC_DISCONNECT_SIZE_OUT sizeof(VBGLREQHDR) +typedef struct VBGLIOCIDCDISCONNECT +{ + /** The header. */ + VBGLREQHDR Hdr; + union + { + struct + { + /** The session handle for platforms where this is needed. */ +#if ARCH_BITS >= 32 + void RT_FAR *pvSession; +#else + uint32_t pvSession; +#endif + } In; + } u; +} VBGLIOCIDCDISCONNECT, RT_FAR *PVBGLIOCIDCDISCONNECT; +AssertCompileSize(VBGLIOCIDCDISCONNECT, 24 + (ARCH_BITS == 64 ? 8 : 4)); +/** @} */ + + +#if !defined(RT_OS_WINDOWS) && !defined(RT_OS_OS2) +RT_C_DECLS_BEGIN +/** + * The VBoxGuest IDC entry point. + * + * @returns VBox status code. + * @param pvSession The session. + * @param uReq The request code. + * @param pReqHdr The request. + * @param cbReq The request size. + */ +int VBOXCALL VBoxGuestIDC(void RT_FAR *pvSession, uintptr_t uReq, PVBGLREQHDR pReqHdr, size_t cbReq); +RT_C_DECLS_END +#endif + + +#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) + +/* Private IOCtls between user space and the kernel video driver. DRM private + * IOCtls always have the type 'd' and a number between 0x40 and 0x99 (0x9F?) */ + +# define VBOX_DRM_IOCTL(a) (0x40 + DRM_VBOX_ ## a) + +/** Stop using HGSMI in the kernel driver until it is re-enabled, so that a + * user-space driver can use it. It must be re-enabled before the kernel + * driver can be used again in a sensible way. */ +/** @note These IOCtls was removed from the code, but are left here as + * templates as we may need similar ones in future. */ +# define DRM_VBOX_DISABLE_HGSMI 0 +# define DRM_IOCTL_VBOX_DISABLE_HGSMI VBOX_DRM_IOCTL(DISABLE_HGSMI) +# define VBOXVIDEO_IOCTL_DISABLE_HGSMI _IO('d', DRM_IOCTL_VBOX_DISABLE_HGSMI) +/** Enable HGSMI in the kernel driver after it was previously disabled. */ +# define DRM_VBOX_ENABLE_HGSMI 1 +# define DRM_IOCTL_VBOX_ENABLE_HGSMI VBOX_DRM_IOCTL(ENABLE_HGSMI) +# define VBOXVIDEO_IOCTL_ENABLE_HGSMI _IO('d', DRM_IOCTL_VBOX_ENABLE_HGSMI) + +#endif /* RT_OS_LINUX || RT_OS_SOLARIS || RT_OS_FREEBSD */ + +#endif /* !defined(IN_RC) && !defined(IN_RING0_AGNOSTIC) && !defined(IPRT_NO_CRT) */ + +/** @} */ + +/** @} */ +#endif /* !VBOX_INCLUDED_VBoxGuest_h */ + diff --git a/include/VBox/VBoxGuestCoreTypes.h b/include/VBox/VBoxGuestCoreTypes.h new file mode 100644 index 00000000..0d820aab --- /dev/null +++ b/include/VBox/VBoxGuestCoreTypes.h @@ -0,0 +1,238 @@ +/** @file + * VBoxGuest - VirtualBox Guest Additions, Core Types. + * + * This contains types that are used both in the VBoxGuest I/O control interface + * and the VBoxGuestLib. The goal is to avoid having to include VBoxGuest.h + * everwhere VBoxGuestLib.h is used. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VBoxGuestCoreTypes_h +#define VBOX_INCLUDED_VBoxGuestCoreTypes_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +/** @addtogroup grp_vboxguest + * @{ */ + +/** + * Common in/out header. + * + * This is a copy/mirror of VMMDevRequestHeader to prevent duplicating data and + * needing to verify things multiple times. For that reason this differs a bit + * from SUPREQHDR. + * + * @sa VMMDevRequestHeader + */ +typedef struct VBGLREQHDR +{ + /** IN: The request input size, and output size if cbOut is zero. + * @sa VMMDevRequestHeader::size */ + uint32_t cbIn; + /** IN: Structure version (VBGLREQHDR_VERSION) + * @sa VMMDevRequestHeader::version */ + uint32_t uVersion; + /** IN: The VMMDev request type, set to VBGLREQHDR_TYPE_DEFAULT unless this is a + * kind of VMMDev request. + * @sa VMMDevRequestType, VMMDevRequestHeader::requestType */ + uint32_t uType; + /** OUT: The VBox status code of the operation, out direction only. */ + int32_t rc; + /** IN: The output size. This is optional - set to zero to use cbIn as the + * output size. */ + uint32_t cbOut; + /** Reserved / filled in by kernel, MBZ. + * @sa VMMDevRequestHeader::fRequestor */ + uint32_t uReserved; +} VBGLREQHDR; +AssertCompileSize(VBGLREQHDR, 24); +/** Pointer to a IOC header. */ +typedef VBGLREQHDR RT_FAR *PVBGLREQHDR; + +/** Version of VMMDevRequestHeader structure. */ +#define VBGLREQHDR_VERSION UINT32_C(0x10001) +/** Default request type. Use this for non-VMMDev requests. */ +#define VBGLREQHDR_TYPE_DEFAULT UINT32_C(0) + +/** Initialize a VBGLREQHDR structure for a fixed size I/O control call. + * @param a_pHdr Pointer to the header to initialize. + * @param a_IOCtl The base I/O control name, no VBGL_IOCTL_ prefix. We + * have to skip the prefix to avoid it getting expanded + * before we append _SIZE_IN and _SIZE_OUT to it. + */ +#define VBGLREQHDR_INIT(a_pHdr, a_IOCtl) \ + VBGLREQHDR_INIT_EX(a_pHdr, RT_CONCAT3(VBGL_IOCTL_,a_IOCtl,_SIZE_IN), RT_CONCAT3(VBGL_IOCTL_,a_IOCtl,_SIZE_OUT)) +/** Initialize a VBGLREQHDR structure, extended version. */ +#define VBGLREQHDR_INIT_EX(a_pHdr, a_cbIn, a_cbOut) \ + do { \ + (a_pHdr)->cbIn = (uint32_t)(a_cbIn); \ + (a_pHdr)->uVersion = VBGLREQHDR_VERSION; \ + (a_pHdr)->uType = VBGLREQHDR_TYPE_DEFAULT; \ + (a_pHdr)->rc = VERR_INTERNAL_ERROR; \ + (a_pHdr)->cbOut = (uint32_t)(a_cbOut); \ + (a_pHdr)->uReserved = 0; \ + } while (0) +/** Initialize a VBGLREQHDR structure for a VMMDev request. + * Same as VMMDEV_REQ_HDR_INIT(). */ +#define VBGLREQHDR_INIT_VMMDEV(a_pHdr, a_cb, a_enmType) \ + do { \ + (a_pHdr)->cbIn = (a_cb); \ + (a_pHdr)->uVersion = VBGLREQHDR_VERSION; \ + (a_pHdr)->uType = (a_enmType); \ + (a_pHdr)->rc = VERR_INTERNAL_ERROR; \ + (a_pHdr)->cbOut = 0; \ + (a_pHdr)->uReserved = 0; \ + } while (0) + + +/** + * For VBGL_IOCTL_HGCM_CALL and VBGL_IOCTL_HGCM_CALL_WITH_USER_DATA. + * + * @note This is used by alot of HGCM call structures. + */ +typedef struct VBGLIOCHGCMCALL +{ + /** Common header. */ + VBGLREQHDR Hdr; + /** Input: The id of the caller. */ + uint32_t u32ClientID; + /** Input: Function number. */ + uint32_t u32Function; + /** Input: How long to wait (milliseconds) for completion before cancelling the + * call. This is ignored if not a VBGL_IOCTL_HGCM_CALL_TIMED or + * VBGL_IOCTL_HGCM_CALL_TIMED_32 request. */ + uint32_t cMsTimeout; + /** Input: Whether a timed call is interruptible (ring-0 only). This is ignored + * if not a VBGL_IOCTL_HGCM_CALL_TIMED or VBGL_IOCTL_HGCM_CALL_TIMED_32 + * request, or if made from user land. */ + bool fInterruptible; + /** Explicit padding, MBZ. */ + uint8_t bReserved; + /** Input: How many parameters following this structure. + * + * The parameters are either HGCMFunctionParameter64 or HGCMFunctionParameter32, + * depending on whether we're receiving a 64-bit or 32-bit request. + * + * The current maximum is 61 parameters (given a 1KB max request size, + * and a 64-bit parameter size of 16 bytes). + * + * @note This information is duplicated by Hdr.cbIn, but it's currently too much + * work to eliminate this. */ + uint16_t cParms; + /* Parameters follow in form HGCMFunctionParameter aParms[cParms] */ +} VBGLIOCHGCMCALL, RT_FAR *PVBGLIOCHGCMCALL; +AssertCompileSize(VBGLIOCHGCMCALL, 24 + 16); +typedef VBGLIOCHGCMCALL const RT_FAR *PCVBGLIOCHGCMCALL; + +/** + * Initialize a HGCM header (VBGLIOCHGCMCALL) for a non-timed call. + * + * @param a_pHdr The header to initalize. + * @param a_idClient The client connection ID to call thru. + * @param a_idFunction The function we're calling + * @param a_cParameters Number of parameters. + */ +# define VBGL_HGCM_HDR_INIT(a_pHdr, a_idClient, a_idFunction, a_cParameters) \ + do { \ + VBGLREQHDR_INIT_EX(&(a_pHdr)->Hdr, \ + sizeof(VBGLIOCHGCMCALL) + (a_cParameters) * sizeof(HGCMFunctionParameter), \ + sizeof(VBGLIOCHGCMCALL) + (a_cParameters) * sizeof(HGCMFunctionParameter)); \ + (a_pHdr)->u32ClientID = (a_idClient); \ + (a_pHdr)->u32Function = (a_idFunction); \ + (a_pHdr)->cMsTimeout = RT_INDEFINITE_WAIT; \ + (a_pHdr)->fInterruptible = true; \ + (a_pHdr)->bReserved = 0; \ + (a_pHdr)->cParms = (a_cParameters); \ + } while (0) + +/** + * Initialize a HGCM header (VBGLIOCHGCMCALL) for a non-timed call, custom size. + * + * This is usually only needed when appending page lists to the call. + * + * @param a_pHdr The header to initalize. + * @param a_idClient The client connection ID to call thru. + * @param a_idFunction The function we're calling + * @param a_cParameters Number of parameters. + * @param a_cbReq The request size. + */ +# define VBGL_HGCM_HDR_INIT_EX(a_pHdr, a_idClient, a_idFunction, a_cParameters, a_cbReq) \ + do { \ + Assert((a_cbReq) >= sizeof(VBGLIOCHGCMCALL) + (a_cParameters) * sizeof(HGCMFunctionParameter)); \ + VBGLREQHDR_INIT_EX(&(a_pHdr)->Hdr, (a_cbReq), (a_cbReq)); \ + (a_pHdr)->u32ClientID = (a_idClient); \ + (a_pHdr)->u32Function = (a_idFunction); \ + (a_pHdr)->cMsTimeout = RT_INDEFINITE_WAIT; \ + (a_pHdr)->fInterruptible = true; \ + (a_pHdr)->bReserved = 0; \ + (a_pHdr)->cParms = (a_cParameters); \ + } while (0) + +/** + * Initialize a HGCM header (VBGLIOCHGCMCALL), with timeout (interruptible). + * + * @param a_pHdr The header to initalize. + * @param a_idClient The client connection ID to call thru. + * @param a_idFunction The function we're calling + * @param a_cParameters Number of parameters. + * @param a_cMsTimeout The timeout in milliseconds. + */ +# define VBGL_HGCM_HDR_INIT_TIMED(a_pHdr, a_idClient, a_idFunction, a_cParameters, a_cMsTimeout) \ + do { \ + VBGLREQHDR_INIT_EX(&(a_pHdr)->Hdr, \ + sizeof(VBGLIOCHGCMCALL) + (a_cParameters) * sizeof(HGCMFunctionParameter), \ + sizeof(VBGLIOCHGCMCALL) + (a_cParameters) * sizeof(HGCMFunctionParameter)); \ + (a_pHdr)->u32ClientID = (a_idClient); \ + (a_pHdr)->u32Function = (a_idFunction); \ + (a_pHdr)->cMsTimeout = (a_cMsTimeout); \ + (a_pHdr)->fInterruptible = true; \ + (a_pHdr)->bReserved = 0; \ + (a_pHdr)->cParms = (a_cParameters); \ + } while (0) + +/** Get the pointer to the first HGCM parameter. */ +# define VBGL_HGCM_GET_CALL_PARMS(a_pInfo) ( (HGCMFunctionParameter *)((uint8_t *)(a_pInfo) + sizeof(VBGLIOCHGCMCALL)) ) +/** Get the pointer to the first HGCM parameter in a 32-bit request. */ +# define VBGL_HGCM_GET_CALL_PARMS32(a_pInfo) ( (HGCMFunctionParameter32 *)((uint8_t *)(a_pInfo) + sizeof(VBGLIOCHGCMCALL)) ) + + +/** + * Mouse event noticification callback function. + * @param pvUser Argument given when setting the callback. + */ +typedef DECLCALLBACKTYPE(void, FNVBOXGUESTMOUSENOTIFY,(void *pvUser)); +/** Pointer to a mouse event notification callback function. */ +typedef FNVBOXGUESTMOUSENOTIFY *PFNVBOXGUESTMOUSENOTIFY; /**< @todo fix type prefix */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_VBoxGuestCoreTypes_h */ + diff --git a/include/VBox/VBoxGuestLib.h b/include/VBox/VBoxGuestLib.h new file mode 100644 index 00000000..10a92428 --- /dev/null +++ b/include/VBox/VBoxGuestLib.h @@ -0,0 +1,1405 @@ +/** @file + * VBoxGuestLib - VirtualBox Guest Additions Library. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VBoxGuestLib_h +#define VBOX_INCLUDED_VBoxGuestLib_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +# ifdef VBOX_WITH_DRAG_AND_DROP +# include +# include +# endif +# ifdef VBOX_WITH_SHARED_CLIPBOARD +# include +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +# include +# endif +# endif /* VBOX_WITH_SHARED_CLIPBOARD */ + +/** @defgroup grp_vboxguest_lib VirtualBox Guest Additions Library + * @ingroup grp_vboxguest + * @{ + */ + +/** @page pg_guest_lib VirtualBox Guest Library + * + * This is a library for abstracting the additions driver interface. There are + * multiple versions of the library depending on the context. The main + * distinction is between kernel and user mode where the interfaces are very + * different. + * + * + * @section sec_guest_lib_ring0 Ring-0 + * + * In ring-0 there are two version: + * - VBOX_LIB_VBGL_R0_BASE / VBoxGuestR0LibBase for the VBoxGuest main driver, + * who is responsible for managing the VMMDev virtual hardware. + * - VBOX_LIB_VBGL_R0 / VBoxGuestR0Lib for other (client) guest drivers. + * + * + * The library source code and the header have a define VBGL_VBOXGUEST, which is + * defined for VBoxGuest and undefined for other drivers. Drivers must choose + * right library in their makefiles and set VBGL_VBOXGUEST accordingly. + * + * The libraries consists of: + * - common code to be used by both VBoxGuest and other drivers; + * - VBoxGuest specific code; + * - code for other drivers which communicate with VBoxGuest via an IOCTL. + * + * + * @section sec_guest_lib_ring3 Ring-3 + * + * There are more variants of the library here: + * - VBOX_LIB_VBGL_R3 / VBoxGuestR3Lib for programs. + * - VBOX_LIB_VBGL_R3_XFREE86 / VBoxGuestR3LibXFree86 for old style XFree + * drivers which uses special loader and or symbol resolving strategy. + * - VBOX_LIB_VBGL_R3_SHARED / VBoxGuestR3LibShared for shared objects / DLLs / + * Dylibs. + * + */ + +RT_C_DECLS_BEGIN + +/** HGCM client ID. + * @todo Promote to VBox/types.h */ +typedef uint32_t HGCMCLIENTID; + + +/** @defgroup grp_vboxguest_lib_r0 Ring-0 interface. + * @{ + */ +#ifdef IN_RING0 +/** @def DECLR0VBGL + * Declare a VBGL ring-0 API with the right calling convention and visibilitiy. + * @param type Return type. */ +# ifdef RT_OS_DARWIN /** @todo probably apply to all, but don't want a forest fire on our hands right now. */ +# define DECLR0VBGL(type) DECLHIDDEN(DECL_NOTHROW(type)) VBOXCALL +# else +# define DECLR0VBGL(type) DECL_NOTHROW(type) VBOXCALL +# endif +# define DECLVBGL(type) DECLR0VBGL(type) + + +/** + * The library initialization function to be used by the main VBoxGuest driver. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0InitPrimary(RTIOPORT portVMMDev, VMMDevMemory *pVMMDevMemory, uint32_t *pfFeatures); + +/** + * The library termination function to be used by the main VBoxGuest driver. + * + * @author bird (2017-08-23) + */ +DECLR0VBGL(void) VbglR0TerminatePrimary(void); + +/** + * The library initialization function to be used by all drivers + * other than the main VBoxGuest system driver. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0InitClient(void); + +/** + * The library termination function. + */ +DECLR0VBGL(void) VbglR0TerminateClient(void); + +/** + * Query the host feature mask. + * + * @returns VBox status code. + * @param pfHostFeatures Where to return the host feature mask, + * VMMDEV_HVF_XXX. + * @note Client only. May fail we're unable to connect VBoxGuest. + */ +DECLR0VBGL(int) VbglR0QueryHostFeatures(uint32_t *pfHostFeatures); + + +/** @name The IDC Client Interface + * @{ + */ + +/** + * Inter-Driver Communication Handle. + */ +typedef union VBGLIDCHANDLE +{ + /** Padding for opaque usage. + * Must be greater or equal in size than the private struct. */ + void *apvPadding[4]; +#ifdef VBGLIDCHANDLEPRIVATE_DECLARED + /** The private view. */ + struct VBGLIDCHANDLEPRIVATE s; +#endif +} VBGLIDCHANDLE; +/** Pointer to a handle. */ +typedef VBGLIDCHANDLE *PVBGLIDCHANDLE; + +DECLR0VBGL(int) VbglR0IdcOpen(PVBGLIDCHANDLE pHandle, uint32_t uReqVersion, uint32_t uMinVersion, + uint32_t *puSessionVersion, uint32_t *puDriverVersion, uint32_t *puDriverRevision); +struct VBGLREQHDR; +DECLR0VBGL(int) VbglR0IdcCallRaw(PVBGLIDCHANDLE pHandle, uintptr_t uReq, struct VBGLREQHDR *pReqHdr, uint32_t cbReq); +DECLR0VBGL(int) VbglR0IdcCall(PVBGLIDCHANDLE pHandle, uintptr_t uReq, struct VBGLREQHDR *pReqHdr, uint32_t cbReq); +DECLR0VBGL(int) VbglR0IdcClose(PVBGLIDCHANDLE pHandle); + +/** @} */ + + +/** @name Generic request functions. + * @{ + */ + +/** + * Allocate memory for generic request and initialize the request header. + * + * @returns VBox status code. + * @param ppReq Where to return the pointer to the allocated memory. + * @param cbReq Size of memory block required for the request. + * @param enmReqType the generic request type. + */ +# if defined(VBOX_INCLUDED_VMMDev_h) || defined(DOXYGEN_RUNNING) +DECLR0VBGL(int) VbglR0GRAlloc(struct VMMDevRequestHeader **ppReq, size_t cbReq, VMMDevRequestType enmReqType); +# else +DECLR0VBGL(int) VbglR0GRAlloc(struct VMMDevRequestHeader **ppReq, size_t cbReq, int32_t enmReqType); +# endif + +/** + * Perform the generic request. + * + * @param pReq pointer the request structure. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0GRPerform(struct VMMDevRequestHeader *pReq); + +/** + * Free the generic request memory. + * + * @param pReq pointer the request structure. + * + * @return VBox status code. + */ +DECLR0VBGL(void) VbglR0GRFree(struct VMMDevRequestHeader *pReq); + +/** + * Verify the generic request header. + * + * @param pReq pointer the request header structure. + * @param cbReq size of the request memory block. It should be equal to the request size + * for fixed size requests. It can be greater than the request size for + * variable size requests. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglGR0Verify(const struct VMMDevRequestHeader *pReq, size_t cbReq); + +/** @} */ + +# ifdef VBOX_WITH_HGCM +struct VBGLIOCHGCMCALL; +struct VBGLIOCIDCHGCMFASTCALL; + +# ifdef VBGL_VBOXGUEST + +/** + * Callback function called from HGCM helpers when a wait for request + * completion IRQ is required. + * + * @returns VINF_SUCCESS, VERR_INTERRUPT or VERR_TIMEOUT. + * @param pvData VBoxGuest pointer to be passed to callback. + * @param u32Data VBoxGuest 32 bit value to be passed to callback. + */ +typedef DECLCALLBACKTYPE(int, FNVBGLHGCMCALLBACK,(VMMDevHGCMRequestHeader *pHeader, void *pvData, uint32_t u32Data)); +/** Pointer to a FNVBGLHGCMCALLBACK. */ +typedef FNVBGLHGCMCALLBACK *PFNVBGLHGCMCALLBACK; + +/** + * Perform a connect request. + * + * That is locate required service and obtain a client identifier for future + * access. + * + * @note This function can NOT handle cancelled requests! + * + * @param pLoc The service to connect to. + * @param fRequestor VMMDEV_REQUESTOR_XXX. + * @param pidClient Where to return the client ID on success. + * @param pfnAsyncCallback Required pointer to function that is calledwhen + * host returns VINF_HGCM_ASYNC_EXECUTE. VBoxGuest + * implements waiting for an IRQ in this function. + * @param pvAsyncData An arbitrary VBoxGuest pointer to be passed to callback. + * @param u32AsyncData An arbitrary VBoxGuest 32 bit value to be passed to callback. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMInternalConnect(HGCMServiceLocation const *pLoc, uint32_t fRequestor, HGCMCLIENTID *pidClient, + PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData); + + +/** + * Perform a disconnect request. + * + * That is tell the host that the client will not call the service anymore. + * + * @note This function can NOT handle cancelled requests! + * + * @param idClient The client ID to disconnect. + * @param fRequestor VMMDEV_REQUESTOR_XXX. + * @param pfnAsyncCallback Required pointer to function that is called when + * host returns VINF_HGCM_ASYNC_EXECUTE. VBoxGuest + * implements waiting for an IRQ in this function. + * @param pvAsyncData An arbitrary VBoxGuest pointer to be passed to callback. + * @param u32AsyncData An arbitrary VBoxGuest 32 bit value to be passed to + * callback. + * + * @return VBox status code. + */ + +DECLR0VBGL(int) VbglR0HGCMInternalDisconnect(HGCMCLIENTID idClient, uint32_t fRequestor, + PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData); + +/** Call a HGCM service. + * + * @note This function can deal with cancelled requests. + * + * @param pCallInfo The request data. + * @param fFlags Flags, see VBGLR0_HGCMCALL_F_XXX. + * @param fRequestor VMMDEV_REQUESTOR_XXX. + * @param pfnAsyncCallback Required pointer to function that is called when + * host returns VINF_HGCM_ASYNC_EXECUTE. VBoxGuest + * implements waiting for an IRQ in this function. + * @param pvAsyncData An arbitrary VBoxGuest pointer to be passed to callback. + * @param u32AsyncData An arbitrary VBoxGuest 32 bit value to be passed to callback. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMInternalCall(struct VBGLIOCHGCMCALL *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags, uint32_t fRequestor, + PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData); + +/** Call a HGCM service. (32 bits packet structure in a 64 bits guest) + * + * @note This function can deal with cancelled requests. + * + * @param pCallInfo The request data. + * @param fFlags Flags, see VBGLR0_HGCMCALL_F_XXX. + * @param fRequestor VMMDEV_REQUESTOR_XXX. + * @param pfnAsyncCallback Required pointer to function that is called when + * host returns VINF_HGCM_ASYNC_EXECUTE. VBoxGuest + * implements waiting for an IRQ in this function. + * @param pvAsyncData An arbitrary VBoxGuest pointer to be passed to callback. + * @param u32AsyncData An arbitrary VBoxGuest 32 bit value to be passed to callback. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMInternalCall32(struct VBGLIOCHGCMCALL *pCallInfo, uint32_t cbCallInfo, uint32_t fFlags, uint32_t fRequestor, + PFNVBGLHGCMCALLBACK pfnAsyncCallback, void *pvAsyncData, uint32_t u32AsyncData); + +/** @name VbglR0HGCMInternalCall flags + * @{ */ +/** User mode request. + * Indicates that only user mode addresses are permitted as parameters. */ +#define VBGLR0_HGCMCALL_F_USER UINT32_C(0) +/** Kernel mode request. + * Indicates that kernel mode addresses are permitted as parameters. Whether or + * not user mode addresses are permitted is, unfortunately, OS specific. The + * following OSes allows user mode addresses: Windows, TODO. + */ +#define VBGLR0_HGCMCALL_F_KERNEL UINT32_C(1) +/** Mode mask. */ +#define VBGLR0_HGCMCALL_F_MODE_MASK UINT32_C(1) +/** @} */ + +# else /* !VBGL_VBOXGUEST */ + +#ifndef VBGL_VBOXGUEST +/** @internal */ +typedef struct VBGLHGCMHANDLEDATA +{ + uint32_t fAllocated; + VBGLIDCHANDLE IdcHandle; +} VBGLHGCMHANDLEDATA; +#else +struct VBGLHGCMHANDLEDATA; +#endif + +typedef struct VBGLHGCMHANDLEDATA *VBGLHGCMHANDLE; + +/** @name HGCM functions + * @{ + */ + +/** + * Initializes HGCM in the R0 guest library. Must be called before any HGCM + * connections are made. Is called by VbglInitClient(). + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMInit(void); + +/** + * Terminates HGCM in the R0 guest library. Is called by VbglTerminate(). + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMTerminate(void); + +/** + * Connect to a service. + * + * @param pHandle Pointer to variable that will hold a handle to be used + * further in VbglHGCMCall and VbglHGCMClose. + * @param pszServiceName The service to connect to. + * @param pidClient Where to return the client ID for the connection. + * + * @return VBox status code. + * + * @todo consider baking the client Id into the handle. + */ +DECLR0VBGL(int) VbglR0HGCMConnect(VBGLHGCMHANDLE *pHandle, const char *pszServiceName, HGCMCLIENTID *pidClient); + +/** + * Connect to a service. + * + * @param handle Handle of the connection. + * @param idClient The ID of the client connection. + * + * @return VBox status code. + * + * @todo consider baking the client Id into the handle. + */ +DECLR0VBGL(int) VbglR0HGCMDisconnect(VBGLHGCMHANDLE handle, HGCMCLIENTID idClient); + +/** + * Call to a service, returning only the I/O control status code. + * + * @param handle Handle of the connection. + * @param pData Call request information structure, including function parameters. + * @param cbData Length in bytes of data. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMCallRaw(VBGLHGCMHANDLE handle, struct VBGLIOCHGCMCALL *pData, uint32_t cbData); + +/** + * Call to a service, returning the HGCM status code. + * + * @param handle Handle of the connection. + * @param pData Call request information structure, including function parameters. + * @param cbData Length in bytes of data. + * + * @return VBox status code. Either the I/O control status code if that failed, + * or the HGCM status code (pData->Hdr.rc). + */ +DECLR0VBGL(int) VbglR0HGCMCall(VBGLHGCMHANDLE handle, struct VBGLIOCHGCMCALL *pData, uint32_t cbData); + +/** + * Call to a service with user-mode data received by the calling driver from the User-Mode process. + * The call must be done in the context of a calling process. + * + * @param handle Handle of the connection. + * @param pData Call request information structure, including function parameters. + * @param cbData Length in bytes of data. + * + * @return VBox status code. + */ +DECLR0VBGL(int) VbglR0HGCMCallUserDataRaw(VBGLHGCMHANDLE handle, struct VBGLIOCHGCMCALL *pData, uint32_t cbData); + +/** + * Call to a service, w/o any repacking and buffer locking in VBoxGuest, + * returning the only request related status code (not HGCM). + * + * The driver only submits the request and waits for completion, nothing else. + * + * @param hHandle The connection handle. + * @param pCallReq The call request. Will be passed directly to the host. + * @param cbCallReq The size of the whole call request. + * + * @return VBox status code. + * + * @remarks The result of the HGCM call is found in + * @a pCallReq->HgcmCallReq.header.result on a successful return. The + * @a pCallReq->Hdr.rc and @a pCallReq->HgcmCallReq.header.header.rc + * fields are the same as the return value and can safely be ignored. + */ +DECLR0VBGL(int) VbglR0HGCMFastCall(VBGLHGCMHANDLE hHandle, struct VBGLIOCIDCHGCMFASTCALL *pCallReq, uint32_t cbCallReq); + +/** @} */ + +/** @name Undocumented helpers for talking to the Chromium OpenGL Host Service + * @{ */ +typedef VBGLHGCMHANDLE VBGLCRCTLHANDLE; +DECLR0VBGL(int) VbglR0CrCtlCreate(VBGLCRCTLHANDLE *phCtl); +DECLR0VBGL(int) VbglR0CrCtlDestroy(VBGLCRCTLHANDLE hCtl); +DECLR0VBGL(int) VbglR0CrCtlConConnect(VBGLCRCTLHANDLE hCtl, HGCMCLIENTID *pidClient); +DECLR0VBGL(int) VbglR0CrCtlConDisconnect(VBGLCRCTLHANDLE hCtl, HGCMCLIENTID idClient); +struct VBGLIOCHGCMCALL; +DECLR0VBGL(int) VbglR0CrCtlConCallRaw(VBGLCRCTLHANDLE hCtl, struct VBGLIOCHGCMCALL *pCallInfo, int cbCallInfo); +DECLR0VBGL(int) VbglR0CrCtlConCall(VBGLCRCTLHANDLE hCtl, struct VBGLIOCHGCMCALL *pCallInfo, int cbCallInfo); +DECLR0VBGL(int) VbglR0CrCtlConCallUserDataRaw(VBGLCRCTLHANDLE hCtl, struct VBGLIOCHGCMCALL *pCallInfo, int cbCallInfo); +/** @} */ + +# endif /* !VBGL_VBOXGUEST */ + +# endif /* VBOX_WITH_HGCM */ + + +/** + * Initialize the heap. + * + * @returns VBox status code. + */ +DECLR0VBGL(int) VbglR0PhysHeapInit(void); + +/** + * Shutdown the heap. + */ +DECLR0VBGL(void) VbglR0PhysHeapTerminate(void); + +/** + * Allocate a memory block. + * + * @returns Virtual address of the allocated memory block. + * @param cb Number of bytes to allocate. + */ +DECLR0VBGL(void *) VbglR0PhysHeapAlloc(uint32_t cb); + +/** + * Get physical address of memory block pointed by the virtual address. + * + * @note WARNING! + * The function does not acquire the Heap mutex! + * When calling the function make sure that the pointer is a valid one and + * is not being deallocated. This function can NOT be used for verifying + * if the given pointer is a valid one allocated from the heap. + * + * @param pv Virtual address of memory block. + * @returns Physical address of the memory block. Zero is returned if @a pv + * isn't valid. + */ +DECLR0VBGL(uint32_t) VbglR0PhysHeapGetPhysAddr(void *pv); + +# ifdef IN_TESTCASE +DECLVBGL(size_t) VbglR0PhysHeapGetFreeSize(void); +# endif + +/** + * Free a memory block. + * + * @param pv Virtual address of memory block. + */ +DECLR0VBGL(void) VbglR0PhysHeapFree(void *pv); + +DECLR0VBGL(int) VbglR0QueryVMMDevMemory(struct VMMDevMemory **ppVMMDevMemory); +DECLR0VBGL(bool) VbglR0CanUsePhysPageList(void); + +# ifndef VBOX_GUEST +/** @name Mouse + * @{ */ +DECLR0VBGL(int) VbglR0SetMouseNotifyCallback(PFNVBOXGUESTMOUSENOTIFY pfnNotify, void *pvUser); +DECLR0VBGL(int) VbglR0GetMouseStatus(uint32_t *pfFeatures, uint32_t *px, uint32_t *py); +DECLR0VBGL(int) VbglR0SetMouseStatus(uint32_t fFeatures); +/** @} */ +# endif /* VBOX_GUEST */ + +#endif /* IN_RING0 */ + +/** @} */ + + +/** @defgroup grp_vboxguest_lib_r3 Ring-3 interface. + * @{ + */ +#ifdef IN_RING3 + +/** @def VBGLR3DECL + * Ring 3 VBGL declaration. + * @param type The return type of the function declaration. + */ +# define VBGLR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL + +/** @name General-purpose functions + * @{ */ +VBGLR3DECL(int) VbglR3Init(void); +VBGLR3DECL(int) VbglR3InitUser(void); +VBGLR3DECL(void) VbglR3Term(void); +# ifdef IPRT_INCLUDED_time_h +VBGLR3DECL(int) VbglR3GetHostTime(PRTTIMESPEC pTime); +# endif +VBGLR3DECL(int) VbglR3InterruptEventWaits(void); +VBGLR3DECL(int) VbglR3WriteLog(const char *pch, size_t cch); +VBGLR3DECL(int) VbglR3CtlFilterMask(uint32_t fOr, uint32_t fNot); +VBGLR3DECL(int) VbglR3Daemonize(bool fNoChDir, bool fNoClose, bool fRespawn, unsigned *pcRespawn); +VBGLR3DECL(int) VbglR3PidFile(const char *pszPath, PRTFILE phFile); +VBGLR3DECL(void) VbglR3ClosePidFile(const char *pszPath, RTFILE hFile); +VBGLR3DECL(int) VbglR3SetGuestCaps(uint32_t fOr, uint32_t fNot); +VBGLR3DECL(int) VbglR3AcquireGuestCaps(uint32_t fOr, uint32_t fNot, bool fConfig); +VBGLR3DECL(int) VbglR3WaitEvent(uint32_t fMask, uint32_t cMillies, uint32_t *pfEvents); + +VBGLR3DECL(int) VbglR3ReportAdditionsStatus(VBoxGuestFacilityType Facility, VBoxGuestFacilityStatus StatusCurrent, + uint32_t fFlags); +VBGLR3DECL(int) VbglR3GetAdditionsVersion(char **ppszVer, char **ppszVerEx, char **ppszRev); +VBGLR3DECL(int) VbglR3GetAdditionsInstallationPath(char **ppszPath); +VBGLR3DECL(int) VbglR3GetSessionId(uint64_t *pu64IdSession); + +/** @} */ + +# ifdef VBOX_WITH_SHARED_CLIPBOARD +/** @name Shared Clipboard + * @{ */ + +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +/** + * Structure for maintaining a VbglR3 Shared Clipboard transfer context. + */ +typedef struct VBGLR3SHCLTRANSFERCMDCTX +{ + /** Default chunk size (in bytes). + * This is set by VbglR3ClipboardConnectEx(). */ + uint32_t cbChunkSize; + /** Max chunk size (in bytes). + * This is set by VbglR3ClipboardConnectEx(). */ + uint32_t cbMaxChunkSize; + /** Optional callbacks to invoke. */ + SHCLTRANSFERCALLBACKTABLE Callbacks; +} VBGLR3SHCLTRANSFERCTX; +/** Pointer to a Shared Clipboard transfer context. */ +typedef VBGLR3SHCLTRANSFERCMDCTX *PVBGLR3SHCLTRANSFERCMDCTX; +# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + +/** + * The context required for either retrieving or sending a HGCM shared clipboard + * commands from or to the host. + * + * @todo This struct could be handy if we want to implement a second + * communication channel, e.g. via TCP/IP. Use a union for the HGCM stuff then. + */ +typedef struct VBGLR3SHCLCMDCTX +{ + /** HGCM client ID to use for communication. + * This is set by VbglR3ClipboardConnectEx(). */ + uint32_t idClient; + /** This is @c false if both VBOX_SHCL_HF_0_CONTEXT_ID and + * VBOX_SHCL_GF_0_CONTEXT_ID are set, otherwise @c true and only the old + * protocol (< 6.1) should be used. + * This is set by VbglR3ClipboardConnectEx(). */ + bool fUseLegacyProtocol; + /** Host feature flags (VBOX_SHCL_HF_XXX). + * This is set by VbglR3ClipboardConnectEx(). */ + uint64_t fHostFeatures; + /** The guest feature flags reported to the host (VBOX_SHCL_GF_XXX). + * This is set by VbglR3ClipboardConnectEx(). */ + uint64_t fGuestFeatures; + /** The context ID - input or/and output depending on the operation. */ + uint64_t idContext; + /** OUT: Number of parameters retrieved. + * This is set by ??. */ + uint32_t cParmsRecived; +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + /** Data related to Shared Clipboard file transfers. */ + VBGLR3SHCLTRANSFERCMDCTX Transfers; +# endif +} VBGLR3SHCLCMDCTX; +/** Pointer to a shared clipboard context for Vbgl. */ +typedef VBGLR3SHCLCMDCTX *PVBGLR3SHCLCMDCTX; + +/** + * Enumeration specifying a Shared Clipboard event type. + * @todo r=bird: Surely, this isn't necessary?! + */ +typedef enum _VBGLR3CLIPBOARDEVENTTYPE +{ + /** No event needed / defined. */ + VBGLR3CLIPBOARDEVENTTYPE_NONE = 0, + /** Host reports available clipboard formats to the guest. */ + VBGLR3CLIPBOARDEVENTTYPE_REPORT_FORMATS, + /** Host wants to read Shared Clipboard data from the guest. */ + VBGLR3CLIPBOARDEVENTTYPE_READ_DATA, + /** Terminates the Shared Clipboard service. */ + VBGLR3CLIPBOARDEVENTTYPE_QUIT, +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + /** Reports a transfer status to the guest. */ + VBGLR3CLIPBOARDEVENTTYPE_TRANSFER_STATUS, +# endif + /** Blow the type up to 32-bit. */ + VBGLR3CLIPBOARDEVENTTYPE_32BIT_HACK = 0x7fffffff +} VBGLR3CLIPBOARDEVENTTYPE; + +/** + * Structure for keeping a Shared Clipboard VbglR3 event. + */ +typedef struct _VBGLR3CLIPBOARDEVENT +{ + /** The event type the union contains. */ + VBGLR3CLIPBOARDEVENTTYPE enmType; + /** Command context bound to this event. */ + VBGLR3SHCLCMDCTX cmdCtx; + union + { + /** Reports available formats from the host. */ + SHCLFORMATS fReportedFormats; + /** Reports that data needs to be read from the guest. */ + SHCLFORMAT fReadData; +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS + /** Reports a transfer status to the guest. */ + struct + { + /** ID of the trnasfer. */ + SHCLTRANSFERID uID; + /** Transfer direction. */ + SHCLTRANSFERDIR enmDir; + /** Additional reproting information. */ + SHCLTRANSFERREPORT Report; + } TransferStatus; +# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ + } u; +} VBGLR3CLIPBOARDEVENT, *PVBGLR3CLIPBOARDEVENT; +typedef const PVBGLR3CLIPBOARDEVENT CPVBGLR3CLIPBOARDEVENT; + +/** @todo r=bird: I'm not sure it is appropriate for the VbglR3 to use types + * from VBox/GuestHost/SharedClipboard*.h, doesn't seem clean to me. */ + +VBGLR3DECL(int) VbglR3ClipboardConnect(HGCMCLIENTID *pidClient); +VBGLR3DECL(int) VbglR3ClipboardDisconnect(HGCMCLIENTID idClient); +VBGLR3DECL(int) VbglR3ClipboardGetHostMsgOld(HGCMCLIENTID idClient, uint32_t *pMsg, uint32_t *pfFormats); +VBGLR3DECL(int) VbglR3ClipboardReadData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb, uint32_t *pcb); +VBGLR3DECL(int) VbglR3ClipboardReadDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT uFormat, void *pvData, uint32_t cbData, uint32_t *pcbRead); +VBGLR3DECL(int) VbglR3ClipboardWriteData(HGCMCLIENTID idClient, uint32_t fFormat, void *pv, uint32_t cb); +VBGLR3DECL(int) VbglR3ClipboardWriteDataEx(PVBGLR3SHCLCMDCTX pCtx, SHCLFORMAT fFormat, void *pvData, uint32_t cbData); +VBGLR3DECL(int) VbglR3ClipboardReportFormats(HGCMCLIENTID idClient, uint32_t fFormats); + +VBGLR3DECL(int) VbglR3ClipboardConnectEx(PVBGLR3SHCLCMDCTX pCtx, uint64_t fGuestFeatures); +VBGLR3DECL(int) VbglR3ClipboardDisconnectEx(PVBGLR3SHCLCMDCTX pCtx); + +VBGLR3DECL(int) VbglR3ClipboardReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures); +VBGLR3DECL(int) VbglR3ClipboardQueryFeatures(uint32_t idClient, uint64_t *pfHostFeatures); +VBGLR3DECL(int) VbglR3ClipboardMsgPeekWait(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pidMsg, uint32_t *pcParameters, uint64_t *pidRestoreCheck); +VBGLR3DECL(int) VbglR3ClipboardEventGetNext(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PVBGLR3CLIPBOARDEVENT pEvent); +VBGLR3DECL(void) VbglR3ClipboardEventFree(PVBGLR3CLIPBOARDEVENT pEvent); + +VBGLR3DECL(int) VbglR3ClipboardWriteError(HGCMCLIENTID idClient, int rcErr); + +# ifdef VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS +VBGLR3DECL(void) VbglR3ClipboardTransferSetCallbacks(PSHCLTRANSFERCALLBACKTABLE pCallbacks); +VBGLR3DECL(int) VbglR3ClipboardEventGetNextEx(uint32_t idMsg, uint32_t cParms, PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFERCTX pTransferCtx, PVBGLR3CLIPBOARDEVENT pEvent); + +VBGLR3DECL(int) VbglR3ClipboardTransferStatusReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLTRANSFER pTransfer, SHCLTRANSFERSTATUS uStatus); + +VBGLR3DECL(int) VbglR3ClipboardRootListRead(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLIST *ppRootList); + +VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReq(PVBGLR3SHCLCMDCTX pCtx, uint32_t *pfRoots); +VBGLR3DECL(int) VbglR3ClipboardRootListHdrReadReply(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLIST pRootList); +VBGLR3DECL(int) VbglR3ClipboardRootsWrite(PVBGLR3SHCLCMDCTX pCtx, PSHCLROOTLISTHDR pRoots); + +VBGLR3DECL(int) VbglR3ClipboardListOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms, PSHCLLISTHANDLE phList); +VBGLR3DECL(int) VbglR3ClipboardListOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTOPENPARMS pOpenParms); +VBGLR3DECL(int) VbglR3ClipboardListOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLLISTHANDLE hList); + +VBGLR3DECL(int) VbglR3ClipboardListCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList); +VBGLR3DECL(int) VbglR3ClipboardListCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLLISTHANDLE phList); + +VBGLR3DECL(int) VbglR3ClipboardListHdrWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTHDR pListHdr); +VBGLR3DECL(int) VbglR3ClipboardListEntryWrite(PVBGLR3SHCLCMDCTX pCtx, SHCLLISTHANDLE hList, PSHCLLISTENTRY pListEntry); + +VBGLR3DECL(int) VbglR3ClipboardObjOpenRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms); +VBGLR3DECL(int) VbglR3ClipboardObjOpenReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj); +VBGLR3DECL(int) VbglR3ClipboardObjOpenSend(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJOPENCREATEPARMS pCreateParms, + PSHCLOBJHANDLE phObj); + +VBGLR3DECL(int) VbglR3ClipboardObjCloseRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj); +VBGLR3DECL(int) VbglR3ClipboardObjCloseReply(PVBGLR3SHCLCMDCTX pCtx, int rcReply, SHCLOBJHANDLE hObj); +VBGLR3DECL(int) VbglR3ClipboardObjCloseSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj); + +VBGLR3DECL(int) VbglR3ClipboardObjReadRecv(PVBGLR3SHCLCMDCTX pCtx, PSHCLOBJHANDLE phObj, uint32_t pcbToRead, + uint32_t *pfFlags); +VBGLR3DECL(int) VbglR3ClipboardObjReadSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, + uint32_t *pcbRead); +VBGLR3DECL(int) VbglR3ClipboardObjWriteSend(PVBGLR3SHCLCMDCTX pCtx, SHCLOBJHANDLE hObj, void *pvBuf, uint32_t cbBuf, + uint32_t *pcbWritten); +# endif /* VBOX_WITH_SHARED_CLIPBOARD_TRANSFERS */ +/** @} */ +# endif /* VBOX_WITH_SHARED_CLIPBOARD */ + +/** @name Seamless mode + * @{ */ +VBGLR3DECL(int) VbglR3SeamlessSetCap(bool fState); +VBGLR3DECL(int) VbglR3SeamlessWaitEvent(VMMDevSeamlessMode *pMode); +VBGLR3DECL(int) VbglR3SeamlessSendRects(uint32_t cRects, PRTRECT pRects); +VBGLR3DECL(int) VbglR3SeamlessSendMonitorPositions(uint32_t cPositions, PRTPOINT pPositions); +VBGLR3DECL(int) VbglR3SeamlessGetLastEvent(VMMDevSeamlessMode *pMode); + +/** @} */ + +/** @name Mouse + * @{ */ +VBGLR3DECL(int) VbglR3GetMouseStatus(uint32_t *pfFeatures, uint32_t *px, uint32_t *py); +VBGLR3DECL(int) VbglR3SetMouseStatus(uint32_t fFeatures); +/** @} */ + +/** @name Video + * @{ */ +VBGLR3DECL(int) VbglR3VideoAccelEnable(bool fEnable); +VBGLR3DECL(int) VbglR3VideoAccelFlush(void); +VBGLR3DECL(int) VbglR3SetPointerShape(uint32_t fFlags, uint32_t xHot, uint32_t yHot, uint32_t cx, uint32_t cy, + const void *pvImg, size_t cbImg); +VBGLR3DECL(int) VbglR3SetPointerShapeReq(struct VMMDevReqMousePointer *pReq); +/** @} */ + +/** @name Display + * @{ */ +/** The folder for the video mode hint unix domain socket on Unix-like guests. + * @note This can be safely changed as all users are rebuilt in lock-step. */ +#define VBGLR3HOSTDISPSOCKETPATH "/tmp/.VBoxService" +/** The path to the video mode hint unix domain socket on Unix-like guests. */ +#define VBGLR3HOSTDISPSOCKET VBGLR3VIDEOMODEHINTSOCKETPATH "/VideoModeHint" + +/** The folder for saving video mode hints to between sessions. */ +#define VBGLR3HOSTDISPSAVEDMODEPATH "/var/lib/VBoxGuestAdditions" +/** The path to the file for saving video mode hints to between sessions. */ +#define VBGLR3HOSTDISPSAVEDMODE VBGLR3HOSTDISPSAVEDMODEPATH "/SavedVideoModes" + +VBGLR3DECL(int) VbglR3GetDisplayChangeRequest(uint32_t *pcx, uint32_t *pcy, uint32_t *pcBits, uint32_t *piDisplay, + uint32_t *pdx, uint32_t *pdy, bool *pfEnabled, bool *pfChangeOrigin, bool fAck); +VBGLR3DECL(int) VbglR3GetDisplayChangeRequestMulti(uint32_t cDisplaysIn, uint32_t *pcDisplaysOut, + VMMDevDisplayDef *paDisplays, bool fAck); +VBGLR3DECL(bool) VbglR3HostLikesVideoMode(uint32_t cx, uint32_t cy, uint32_t cBits); +VBGLR3DECL(int) VbglR3VideoModeGetHighestSavedScreen(unsigned *pcScreen); +VBGLR3DECL(int) VbglR3SaveVideoMode(unsigned cScreen, unsigned cx, unsigned cy, unsigned cBits, + unsigned x, unsigned y, bool fEnabled); +VBGLR3DECL(int) VbglR3RetrieveVideoMode(unsigned cScreen, unsigned *pcx, unsigned *pcy, unsigned *pcBits, + unsigned *px, unsigned *py, bool *pfEnabled); +/** @} */ + +/** @name VRDP + * @{ */ +VBGLR3DECL(int) VbglR3VrdpGetChangeRequest(bool *pfActive, uint32_t *puExperienceLevel); +/** @} */ + +/** @name VM Statistics + * @{ */ +VBGLR3DECL(int) VbglR3StatQueryInterval(uint32_t *pu32Interval); +# if defined(VBOX_INCLUDED_VMMDev_h) || defined(DOXYGEN_RUNNING) +VBGLR3DECL(int) VbglR3StatReport(VMMDevReportGuestStats *pReq); +# endif +/** @} */ + +/** @name Memory ballooning + * @{ */ +VBGLR3DECL(int) VbglR3MemBalloonRefresh(uint32_t *pcChunks, bool *pfHandleInR3); +VBGLR3DECL(int) VbglR3MemBalloonChange(void *pv, bool fInflate); +/** @} */ + +/** @name Core Dump + * @{ */ +VBGLR3DECL(int) VbglR3WriteCoreDump(void); + +/** @} */ + +/** @name DRM client handling + * @{ */ +/** Guest property names pattern which is used by Guest Additions DRM services. */ +# define VBGLR3DRMPROPPTR "/VirtualBox/GuestAdd/DRM*" +/** Guest property that defines if the DRM IPC server access should be restricted to a specific user group. */ +# define VBGLR3DRMIPCPROPRESTRICT "/VirtualBox/GuestAdd/DRMIpcRestricted" + +VBGLR3DECL(bool) VbglR3DrmClientIsNeeded(void); +VBGLR3DECL(bool) VbglR3DrmRestrictedIpcAccessIsNeeded(void); +VBGLR3DECL(bool) VbglR3DrmClientIsRunning(void); +VBGLR3DECL(int) VbglR3DrmClientStart(void); +VBGLR3DECL(int) VbglR3DrmLegacyClientStart(void); +VBGLR3DECL(int) VbglR3DrmLegacyX11AgentStart(void); +/** @} */ + +# ifdef VBOX_WITH_GUEST_PROPS +/** @name Guest properties + * @{ */ +/** @todo Docs. */ +typedef struct VBGLR3GUESTPROPENUM VBGLR3GUESTPROPENUM; +/** @todo Docs. */ +typedef VBGLR3GUESTPROPENUM *PVBGLR3GUESTPROPENUM; +VBGLR3DECL(int) VbglR3GuestPropConnect(uint32_t *pidClient); +VBGLR3DECL(int) VbglR3GuestPropDisconnect(HGCMCLIENTID idClient); +VBGLR3DECL(bool) VbglR3GuestPropExist(uint32_t idClient, const char *pszPropName); +VBGLR3DECL(int) VbglR3GuestPropWrite(HGCMCLIENTID idClient, const char *pszName, const char *pszValue, const char *pszFlags); +VBGLR3DECL(int) VbglR3GuestPropWriteValue(HGCMCLIENTID idClient, const char *pszName, const char *pszValue); +VBGLR3DECL(int) VbglR3GuestPropWriteValueV(HGCMCLIENTID idClient, const char *pszName, + const char *pszValueFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); +VBGLR3DECL(int) VbglR3GuestPropWriteValueF(HGCMCLIENTID idClient, const char *pszName, + const char *pszValueFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VBGLR3DECL(int) VbglR3GuestPropRead(HGCMCLIENTID idClient, const char *pszName, void *pvBuf, uint32_t cbBuf, char **ppszValue, + uint64_t *pu64Timestamp, char **ppszFlags, uint32_t *pcbBufActual); +VBGLR3DECL(int) VbglR3GuestPropReadEx(uint32_t u32ClientId, + const char *pszPropName, char **ppszValue, char **ppszFlags, uint64_t *puTimestamp); +VBGLR3DECL(int) VbglR3GuestPropReadValue(uint32_t ClientId, const char *pszName, char *pszValue, uint32_t cchValue, + uint32_t *pcchValueActual); +VBGLR3DECL(int) VbglR3GuestPropReadValueAlloc(HGCMCLIENTID idClient, const char *pszName, char **ppszValue); +VBGLR3DECL(void) VbglR3GuestPropReadValueFree(char *pszValue); +VBGLR3DECL(int) VbglR3GuestPropEnumRaw(HGCMCLIENTID idClient, const char *paszPatterns, char *pcBuf, uint32_t cbBuf, + uint32_t *pcbBufActual); +VBGLR3DECL(int) VbglR3GuestPropEnum(HGCMCLIENTID idClient, char const * const *ppaszPatterns, uint32_t cPatterns, + PVBGLR3GUESTPROPENUM *ppHandle, char const **ppszName, char const **ppszValue, + uint64_t *pu64Timestamp, char const **ppszFlags); +VBGLR3DECL(int) VbglR3GuestPropEnumNext(PVBGLR3GUESTPROPENUM pHandle, char const **ppszName, char const **ppszValue, + uint64_t *pu64Timestamp, char const **ppszFlags); +VBGLR3DECL(void) VbglR3GuestPropEnumFree(PVBGLR3GUESTPROPENUM pHandle); +VBGLR3DECL(int) VbglR3GuestPropDelete(HGCMCLIENTID idClient, const char *pszName); +VBGLR3DECL(int) VbglR3GuestPropDelSet(HGCMCLIENTID idClient, char const * const *papszPatterns, uint32_t cPatterns); +VBGLR3DECL(int) VbglR3GuestPropWait(HGCMCLIENTID idClient, const char *pszPatterns, void *pvBuf, uint32_t cbBuf, + uint64_t u64Timestamp, uint32_t cMillies, char ** ppszName, char **ppszValue, + uint64_t *pu64Timestamp, char **ppszFlags, uint32_t *pcbBufActual, bool *pfWasDeleted); +/** @} */ + +/** @name Guest user handling / reporting. + * @{ */ +VBGLR3DECL(int) VbglR3GuestUserReportState(const char *pszUser, const char *pszDomain, VBoxGuestUserState enmState, + uint8_t *pbDetails, uint32_t cbDetails); +/** @} */ + +/** @name Host version handling + * @{ */ +VBGLR3DECL(int) VbglR3HostVersionCheckForUpdate(HGCMCLIENTID idClient, bool *pfUpdate, char **ppszHostVersion, + char **ppszGuestVersion); +VBGLR3DECL(int) VbglR3HostVersionLastCheckedLoad(HGCMCLIENTID idClient, char **ppszVer); +VBGLR3DECL(int) VbglR3HostVersionLastCheckedStore(HGCMCLIENTID idClient, const char *pszVer); +/** @} */ +# endif /* VBOX_WITH_GUEST_PROPS defined */ + +# ifdef VBOX_WITH_SHARED_FOLDERS +/** @name Shared folders + * @{ */ +/** + * Structure containing mapping information for a shared folder. + */ +typedef struct VBGLR3SHAREDFOLDERMAPPING +{ + /** Mapping status. */ + uint32_t u32Status; + /** Root handle. */ + uint32_t u32Root; +} VBGLR3SHAREDFOLDERMAPPING; +/** Pointer to a shared folder mapping information structure. */ +typedef VBGLR3SHAREDFOLDERMAPPING *PVBGLR3SHAREDFOLDERMAPPING; +/** Pointer to a const shared folder mapping information structure. */ +typedef VBGLR3SHAREDFOLDERMAPPING const *PCVBGLR3SHAREDFOLDERMAPPING; + +VBGLR3DECL(int) VbglR3SharedFolderConnect(uint32_t *pidClient); +VBGLR3DECL(int) VbglR3SharedFolderDisconnect(HGCMCLIENTID idClient); +VBGLR3DECL(bool) VbglR3SharedFolderExists(HGCMCLIENTID idClient, const char *pszShareName); +VBGLR3DECL(int) VbglR3SharedFolderGetMappings(HGCMCLIENTID idClient, bool fAutoMountOnly, + PVBGLR3SHAREDFOLDERMAPPING *ppaMappings, uint32_t *pcMappings); +VBGLR3DECL(void) VbglR3SharedFolderFreeMappings(PVBGLR3SHAREDFOLDERMAPPING paMappings); +VBGLR3DECL(int) VbglR3SharedFolderGetName(HGCMCLIENTID idClient,uint32_t u32Root, char **ppszName); /**< @todo r=bird: GET functions return the value, not a status code!*/ +VBGLR3DECL(int) VbglR3SharedFolderQueryFolderInfo(HGCMCLIENTID idClient, uint32_t idRoot, uint64_t fQueryFlags, + char **ppszName, char **ppszMountPoint, + uint64_t *pfFlags, uint32_t *puRootIdVersion); +VBGLR3DECL(int) VbglR3SharedFolderWaitForMappingsChanges(HGCMCLIENTID idClient, uint32_t uPrevVersion, uint32_t *puCurVersion); +VBGLR3DECL(int) VbglR3SharedFolderCancelMappingsChangesWaits(HGCMCLIENTID idClient); + +VBGLR3DECL(int) VbglR3SharedFolderGetMountPrefix(char **ppszPrefix); /**< @todo r=bird: GET functions return the value, not a status code! */ +VBGLR3DECL(int) VbglR3SharedFolderGetMountDir(char **ppszDir); /**< @todo r=bird: GET functions return the value, not a status code! */ +/** @} */ +# endif /* VBOX_WITH_SHARED_FOLDERS defined */ + +# ifdef VBOX_WITH_GUEST_CONTROL +/** @name Guest control + * @{ */ + +/** + * Structure containing the context required for + * either retrieving or sending a HGCM guest control + * commands from or to the host. + * + * @note Do not change parameter order without also adapting all structure + * initializers. + */ +typedef struct VBGLR3GUESTCTRLCMDCTX +{ + /** @todo This struct could be handy if we want to implement + * a second communication channel, e.g. via TCP/IP. + * Use a union for the HGCM stuff then. */ + + /** IN: HGCM client ID to use for communication. */ + uint32_t uClientID; + /** IN/OUT: Context ID to retrieve or to use. */ + uint32_t uContextID; + /** IN: Protocol version to use. */ + uint32_t uProtocol; + /** OUT: Number of parameters retrieved. */ + uint32_t uNumParms; +} VBGLR3GUESTCTRLCMDCTX, *PVBGLR3GUESTCTRLCMDCTX; + +/** + * Structure holding information for starting a guest + * session. + */ +typedef struct VBGLR3GUESTCTRLSESSIONSTARTUPINFO +{ + /** The session's protocol version to use. */ + uint32_t uProtocol; + /** The session's ID. */ + uint32_t uSessionID; + /** User name (account) to start the guest session under. */ + char *pszUser; + /** Size (in bytes) of allocated pszUser. */ + uint32_t cbUser; + /** Password of specified user name (account). */ + char *pszPassword; + /** Size (in bytes) of allocated pszPassword. */ + uint32_t cbPassword; + /** Domain of the user account. */ + char *pszDomain; + /** Size (in bytes) of allocated pszDomain. */ + uint32_t cbDomain; + /** Session creation flags. + * @sa VBOXSERVICECTRLSESSIONSTARTUPFLAG_* flags. */ + uint32_t fFlags; +} VBGLR3GUESTCTRLSESSIONSTARTUPINFO; +/** Pointer to a guest session startup info. */ +typedef VBGLR3GUESTCTRLSESSIONSTARTUPINFO *PVBGLR3GUESTCTRLSESSIONSTARTUPINFO; + +/** + * Structure holding information for starting a guest + * process. + */ +typedef struct VBGLR3GUESTCTRLPROCSTARTUPINFO +{ + /** Full qualified path of process to start (without arguments). + * Note: This is *not* argv[0]! */ + char *pszCmd; + /** Size (in bytes) of allocated pszCmd. */ + uint32_t cbCmd; + /** Process execution flags. @sa */ + uint32_t fFlags; + /** Command line arguments. */ + char *pszArgs; + /** Size (in bytes) of allocated pszArgs. */ + uint32_t cbArgs; + /** Number of arguments specified in pszArgs. */ + uint32_t cArgs; + /** String of environment variables ("FOO=BAR") to pass to the process + * to start. */ + char *pszEnv; + /** Size (in bytes) of environment variables block. */ + uint32_t cbEnv; + /** Number of environment variables specified in pszEnv. */ + uint32_t cEnvVars; + /** User name (account) to start the process under. */ + char *pszUser; + /** Size (in bytes) of allocated pszUser. */ + uint32_t cbUser; + /** Password of specified user name (account). */ + char *pszPassword; + /** Size (in bytes) of allocated pszPassword. */ + uint32_t cbPassword; + /** Domain to be used for authenticating the specified user name (account). */ + char *pszDomain; + /** Size (in bytes) of allocated pszDomain. */ + uint32_t cbDomain; + /** Time limit (in ms) of the process' life time. */ + uint32_t uTimeLimitMS; + /** Process priority. */ + uint32_t uPriority; + /** Process affinity block. At the moment we support + * up to 4 blocks, that is, 4 * 64 = 256 CPUs total. */ + uint64_t uAffinity[4]; + /** Number of used process affinity blocks. */ + uint32_t cAffinity; +} VBGLR3GUESTCTRLPROCSTARTUPINFO; +/** Pointer to a guest process startup info. */ +typedef VBGLR3GUESTCTRLPROCSTARTUPINFO *PVBGLR3GUESTCTRLPROCSTARTUPINFO; + +/* General message handling on the guest. */ +VBGLR3DECL(int) VbglR3GuestCtrlConnect(uint32_t *pidClient); +VBGLR3DECL(int) VbglR3GuestCtrlDisconnect(uint32_t idClient); +VBGLR3DECL(bool) VbglR3GuestCtrlSupportsOptimizations(uint32_t idClient); +VBGLR3DECL(int) VbglR3GuestCtrlMakeMeMaster(uint32_t idClient); +VBGLR3DECL(int) VbglR3GuestCtrlReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures); +VBGLR3DECL(int) VbglR3GuestCtrlQueryFeatures(uint32_t idClient, uint64_t *pfHostFeatures); +VBGLR3DECL(int) VbglR3GuestCtrlMsgFilterSet(uint32_t uClientId, uint32_t uValue, uint32_t uMaskAdd, uint32_t uMaskRemove); +VBGLR3DECL(int) VbglR3GuestCtrlMsgReply(PVBGLR3GUESTCTRLCMDCTX pCtx, int rc); +VBGLR3DECL(int) VbglR3GuestCtrlMsgReplyEx(PVBGLR3GUESTCTRLCMDCTX pCtx, int rc, uint32_t uType, + void *pvPayload, uint32_t cbPayload); +VBGLR3DECL(int) VbglR3GuestCtrlMsgSkip(uint32_t idClient, int rcSkip, uint32_t idMsg); +VBGLR3DECL(int) VbglR3GuestCtrlMsgSkipOld(uint32_t uClientId); +VBGLR3DECL(int) VbglR3GuestCtrlMsgPeekWait(uint32_t idClient, uint32_t *pidMsg, uint32_t *pcParameters, uint64_t *pidRestoreCheck); +VBGLR3DECL(int) VbglR3GuestCtrlCancelPendingWaits(HGCMCLIENTID idClient); +/* Guest session handling. */ +VBGLR3DECL(int) VbglR3GuestCtrlSessionStartupInfoInit(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo); +VBGLR3DECL(int) VbglR3GuestCtrlSessionStartupInfoInitEx(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo, size_t cbUser, size_t cbPassword, size_t cbDomain); +VBGLR3DECL(void) VbglR3GuestCtrlSessionStartupInfoDestroy(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo); +VBGLR3DECL(void) VbglR3GuestCtrlSessionStartupInfoFree(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo); +VBGLR3DECL(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO) VbglR3GuestCtrlSessionStartupInfoDup(PVBGLR3GUESTCTRLSESSIONSTARTUPINFO pStartupInfo); +VBGLR3DECL(int) VbglR3GuestCtrlSessionPrepare(uint32_t idClient, uint32_t idSession, void const *pvKey, uint32_t cbKey); +VBGLR3DECL(int) VbglR3GuestCtrlSessionAccept(uint32_t idClient, uint32_t idSession, void const *pvKey, uint32_t cbKey); +VBGLR3DECL(int) VbglR3GuestCtrlSessionCancelPrepared(uint32_t idClient, uint32_t idSession); +VBGLR3DECL(int) VbglR3GuestCtrlSessionHasChanged(uint32_t idClient, uint64_t idNewControlSession); +VBGLR3DECL(int) VbglR3GuestCtrlSessionClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t fFlags); +VBGLR3DECL(int) VbglR3GuestCtrlSessionNotify(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uType, int32_t iResult); +VBGLR3DECL(int) VbglR3GuestCtrlSessionGetOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, PVBGLR3GUESTCTRLSESSIONSTARTUPINFO *ppStartupInfo); +VBGLR3DECL(int) VbglR3GuestCtrlSessionGetClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *pfFlags, uint32_t *pidSession); +/* Guest path handling. */ +VBGLR3DECL(int) VbglR3GuestCtrlPathGetRename(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszSource, uint32_t cbSource, char *pszDest, + uint32_t cbDest, uint32_t *pfFlags); +VBGLR3DECL(int) VbglR3GuestCtrlPathGetUserDocuments(PVBGLR3GUESTCTRLCMDCTX pCtx); +VBGLR3DECL(int) VbglR3GuestCtrlPathGetUserHome(PVBGLR3GUESTCTRLCMDCTX pCtx); +VBGLR3DECL(int) VbglR3GuestCtrlGetShutdown(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *pfAction); +/* Guest process execution. */ +VBGLR3DECL(int) VbglR3GuestCtrlProcStartupInfoInit(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo); +VBGLR3DECL(int) VbglR3GuestCtrlProcStartupInfoInitEx(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo, size_t cbCmd, size_t cbUser, size_t cbPassword, size_t cbDomain, size_t cbArgs, size_t cbEnv); +VBGLR3DECL(void) VbglR3GuestCtrlProcStartupInfoDestroy(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo); +VBGLR3DECL(void) VbglR3GuestCtrlProcStartupInfoFree(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo); +VBGLR3DECL(PVBGLR3GUESTCTRLPROCSTARTUPINFO) VbglR3GuestCtrlProcStartupInfoDup(PVBGLR3GUESTCTRLPROCSTARTUPINFO pStartupInfo); +VBGLR3DECL(int) VbglR3GuestCtrlProcGetStart(PVBGLR3GUESTCTRLCMDCTX pCtx, PVBGLR3GUESTCTRLPROCSTARTUPINFO *ppStartupInfo); +VBGLR3DECL(int) VbglR3GuestCtrlProcGetTerminate(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puPID); +VBGLR3DECL(int) VbglR3GuestCtrlProcGetInput(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puPID, uint32_t *pfFlags, void *pvData, + uint32_t cbData, uint32_t *pcbSize); +VBGLR3DECL(int) VbglR3GuestCtrlProcGetOutput(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puPID, uint32_t *puHandle, uint32_t *pfFlags); +VBGLR3DECL(int) VbglR3GuestCtrlProcGetWaitFor(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puPID, uint32_t *puWaitFlags, + uint32_t *puTimeoutMS); +/* Guest native directory handling. */ +VBGLR3DECL(int) VbglR3GuestCtrlDirGetRemove(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszPath, uint32_t cbPath, uint32_t *pfFlags); +/* Guest native file handling. */ +VBGLR3DECL(int) VbglR3GuestCtrlFileGetOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, char *pszFileName, uint32_t cbFileName, char *pszOpenMode, + uint32_t cbOpenMode, char *pszDisposition, uint32_t cbDisposition, char *pszSharing, + uint32_t cbSharing, uint32_t *puCreationMode, uint64_t *puOffset); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetRead(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, uint32_t *puToRead); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetReadAt(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, + uint32_t *puToRead, uint64_t *poffRead); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetWrite(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, + void *pvData, uint32_t cbData, uint32_t *pcbActual); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetWriteAt(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, void *pvData, uint32_t cbData, + uint32_t *pcbActual, uint64_t *poffWrite); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetSeek(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, + uint32_t *puSeekMethod, uint64_t *poffSeek); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetTell(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle); +VBGLR3DECL(int) VbglR3GuestCtrlFileGetSetSize(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t *puHandle, uint64_t *pcbNew); + +/* Guest -> Host. */ +VBGLR3DECL(int) VbglR3GuestCtrlFileCbOpen(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t uFileHandle); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbClose(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbError(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbRead(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, void *pvData, uint32_t cbData); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbReadOffset(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, + void *pvData, uint32_t cbData, int64_t offNew); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbWrite(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t cbWritten); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbWriteOffset(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint32_t cbWritten, int64_t offNew); + +VBGLR3DECL(int) VbglR3GuestCtrlFileCbSeek(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t offCurrent); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbTell(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t offCurrent); +VBGLR3DECL(int) VbglR3GuestCtrlFileCbSetSize(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uRc, uint64_t cbNew); +VBGLR3DECL(int) VbglR3GuestCtrlProcCbStatus(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uPID, uint32_t uStatus, uint32_t fFlags, + void *pvData, uint32_t cbData); +VBGLR3DECL(int) VbglR3GuestCtrlProcCbOutput(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t uPID, uint32_t uHandle, uint32_t fFlags, + void *pvData, uint32_t cbData); +VBGLR3DECL(int) VbglR3GuestCtrlProcCbStatusInput(PVBGLR3GUESTCTRLCMDCTX pCtx, uint32_t u32PID, uint32_t uStatus, + uint32_t fFlags, uint32_t cbWritten); + +/** @} */ +# endif /* VBOX_WITH_GUEST_CONTROL defined */ + +/** @name Auto-logon handling + * @{ */ +VBGLR3DECL(int) VbglR3AutoLogonReportStatus(VBoxGuestFacilityStatus enmStatus); +VBGLR3DECL(bool) VbglR3AutoLogonIsRemoteSession(void); +/** @} */ + +/** @name User credentials handling + * @{ */ +VBGLR3DECL(int) VbglR3CredentialsQueryAvailability(void); +VBGLR3DECL(int) VbglR3CredentialsRetrieve(char **ppszUser, char **ppszPassword, char **ppszDomain); +VBGLR3DECL(int) VbglR3CredentialsRetrieveUtf16(PRTUTF16 *ppwszUser, PRTUTF16 *ppwszPassword, PRTUTF16 *ppwszDomain); +VBGLR3DECL(void) VbglR3CredentialsDestroy(char *pszUser, char *pszPassword, char *pszDomain, uint32_t cPasses); +VBGLR3DECL(void) VbglR3CredentialsDestroyUtf16(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 pwszDomain, + uint32_t cPasses); +/** @} */ + +/** @name CPU hotplug monitor + * @{ */ +VBGLR3DECL(int) VbglR3CpuHotPlugInit(void); +VBGLR3DECL(int) VbglR3CpuHotPlugTerm(void); +VBGLR3DECL(int) VbglR3CpuHotPlugWaitForEvent(VMMDevCpuEventType *penmEventType, uint32_t *pidCpuCore, uint32_t *pidCpuPackage); +/** @} */ + +/** @name Page sharing + * @{ */ +struct VMMDEVSHAREDREGIONDESC; +VBGLR3DECL(int) VbglR3RegisterSharedModule(char *pszModuleName, char *pszVersion, RTGCPTR64 GCBaseAddr, uint32_t cbModule, + unsigned cRegions, struct VMMDEVSHAREDREGIONDESC *pRegions); +VBGLR3DECL(int) VbglR3UnregisterSharedModule(char *pszModuleName, char *pszVersion, RTGCPTR64 GCBaseAddr, uint32_t cbModule); +VBGLR3DECL(int) VbglR3CheckSharedModules(void); +VBGLR3DECL(bool) VbglR3PageSharingIsEnabled(void); +VBGLR3DECL(int) VbglR3PageIsShared(RTGCPTR pPage, bool *pfShared, uint64_t *puPageFlags); +/** @} */ + +# ifdef VBOX_WITH_DRAG_AND_DROP +/** @name Drag and Drop + * @{ */ +/** + * Structure containing the context required for + * either retrieving or sending a HGCM guest drag'n drop + * commands from or to the host. + * + * Note: Do not change parameter order without also + * adapting all structure initializers. + */ +typedef struct VBGLR3GUESTDNDCMDCTX +{ + /** @todo This struct could be handy if we want to implement + * a second communication channel, e.g. via TCP/IP. + * Use a union for the HGCM stuff then. */ + + /** HGCM client ID to use for communication. */ + uint32_t uClientID; + /** The VM's current session ID. */ + uint64_t uSessionID; + /** Protocol version to use. + * Deprecated; do not used / rely on it anymore. */ + uint32_t uProtocolDeprecated; + /** Host feature flags (VBOX_DND_HF_XXX). + * This is set by VbglR3DnDConnect(). */ + uint64_t fHostFeatures; + /** The guest feature flags reported to the host (VBOX_DND_GF_XXX). + * This is set by VbglR3DnDConnect(). */ + uint64_t fGuestFeatures; + /** Number of parameters retrieved for the current command. */ + uint32_t uNumParms; + /** Max chunk size (in bytes) for data transfers. */ + uint32_t cbMaxChunkSize; +} VBGLR3GUESTDNDCMDCTX, *PVBGLR3GUESTDNDCMDCTX; + +/** + * Enumeration for specifying the DnD meta data type. + */ +typedef enum VBGLR3GUESTDNDMETADATATYPE +{ + /** Unknown meta data type; don't use. */ + VBGLR3GUESTDNDMETADATATYPE_UNKNOWN = 0, + /** Raw meta data; can be everything. */ + VBGLR3GUESTDNDMETADATATYPE_RAW, + /** Meta data is a transfer list, specifying objects. */ + VBGLR3GUESTDNDMETADATATYPE_URI_LIST, + /** Blow the type up to 32-bit. */ + VBGLR3GUESTDNDMETADATATYPE_32BIT_HACK = 0x7fffffff +} VBGLR3GUESTDNDMETADATATYPE; + +/** + * Structure for keeping + handling DnD meta data. + */ +typedef struct VBGLR3GUESTDNDMETADATA +{ + /** The meta data type the union contains. */ + VBGLR3GUESTDNDMETADATATYPE enmType; + /** Union based on \a enmType. */ + union + { + struct + { + /** Pointer to actual meta data. */ + void *pvMeta; + /** Size (in bytes) of meta data. */ + uint32_t cbMeta; + } Raw; + struct + { + DNDTRANSFERLIST Transfer; + } URI; + } u; +} VBGLR3GUESTDNDMETADATA; + +/** Pointer to VBGLR3GUESTDNDMETADATA. */ +typedef VBGLR3GUESTDNDMETADATA *PVBGLR3GUESTDNDMETADATA; + +/** Const pointer to VBGLR3GUESTDNDMETADATA. */ +typedef const PVBGLR3GUESTDNDMETADATA CPVBGLR3GUESTDNDMETADATA; + +/** + * Enumeration specifying a DnD event type. + */ +typedef enum VBGLR3DNDEVENTTYPE +{ + VBGLR3DNDEVENTTYPE_INVALID = 0, + VBGLR3DNDEVENTTYPE_CANCEL, + VBGLR3DNDEVENTTYPE_HG_ERROR, + VBGLR3DNDEVENTTYPE_HG_ENTER, + VBGLR3DNDEVENTTYPE_HG_MOVE, + VBGLR3DNDEVENTTYPE_HG_LEAVE, + VBGLR3DNDEVENTTYPE_HG_DROP, + VBGLR3DNDEVENTTYPE_HG_RECEIVE, +# ifdef VBOX_WITH_DRAG_AND_DROP_GH + VBGLR3DNDEVENTTYPE_GH_ERROR, + VBGLR3DNDEVENTTYPE_GH_REQ_PENDING, + VBGLR3DNDEVENTTYPE_GH_DROP, +# endif + /** Tells the caller that it has to quit operation. */ + VBGLR3DNDEVENTTYPE_QUIT, + /** Blow the type up to 32-bit. */ + VBGLR3DNDEVENTTYPE_32BIT_HACK = 0x7fffffff +} VBGLR3DNDEVENTTYPE; + +typedef struct VBGLR3DNDEVENT +{ + /** The event type the union contains. */ + VBGLR3DNDEVENTTYPE enmType; + union + { + struct + { + /** Screen ID this request belongs to. */ + uint32_t uScreenID; + /** Format list (UTF-8, \r\n separated). */ + char *pszFormats; + /** Size (in bytes) of pszFormats (\0 included). */ + uint32_t cbFormats; + /** List of allowed DnD actions. */ + VBOXDNDACTIONLIST dndLstActionsAllowed; + } HG_Enter; + struct + { + /** Absolute X position of guest screen. */ + uint32_t uXpos; + /** Absolute Y position of guest screen. */ + uint32_t uYpos; + /** Default DnD action. */ + VBOXDNDACTION dndActionDefault; + } HG_Move; + struct + { + /** Absolute X position of guest screen. */ + uint32_t uXpos; + /** Absolute Y position of guest screen. */ + uint32_t uYpos; + /** Default DnD action. */ + VBOXDNDACTION dndActionDefault; + } HG_Drop; + struct + { + /** Meta data for the operation. */ + VBGLR3GUESTDNDMETADATA Meta; + } HG_Received; + struct + { + /** IPRT-style error code. */ + int rc; + } HG_Error; +# ifdef VBOX_WITH_DRAG_AND_DROP_GH + struct + { + /** Screen ID this request belongs to. */ + uint32_t uScreenID; + } GH_IsPending; + struct + { + /** Requested format by the host. */ + char *pszFormat; + /** Size (in bytes) of pszFormat (\0 included). */ + uint32_t cbFormat; + /** Requested DnD action. */ + VBOXDNDACTION dndActionRequested; + } GH_Drop; +# endif + } u; +} VBGLR3DNDEVENT; +typedef VBGLR3DNDEVENT *PVBGLR3DNDEVENT; +typedef const PVBGLR3DNDEVENT CPVBGLR3DNDEVENT; + +VBGLR3DECL(int) VbglR3DnDConnect(PVBGLR3GUESTDNDCMDCTX pCtx); +VBGLR3DECL(int) VbglR3DnDDisconnect(PVBGLR3GUESTDNDCMDCTX pCtx); + +VBGLR3DECL(int) VbglR3DnDReportFeatures(uint32_t idClient, uint64_t fGuestFeatures, uint64_t *pfHostFeatures); +VBGLR3DECL(int) VbglR3DnDSendError(PVBGLR3GUESTDNDCMDCTX pCtx, int rcOp); + +VBGLR3DECL(int) VbglR3DnDEventGetNext(PVBGLR3GUESTDNDCMDCTX pCtx, PVBGLR3DNDEVENT *ppEvent); +VBGLR3DECL(void) VbglR3DnDEventFree(PVBGLR3DNDEVENT pEvent); + +VBGLR3DECL(int) VbglR3DnDHGSendAckOp(PVBGLR3GUESTDNDCMDCTX pCtx, VBOXDNDACTION dndAction); +VBGLR3DECL(int) VbglR3DnDHGSendReqData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pcszFormat); +VBGLR3DECL(int) VbglR3DnDHGSendProgress(PVBGLR3GUESTDNDCMDCTX pCtx, uint32_t uStatus, uint8_t uPercent, int rcErr); +# ifdef VBOX_WITH_DRAG_AND_DROP_GH +VBGLR3DECL(int) VbglR3DnDGHSendAckPending(PVBGLR3GUESTDNDCMDCTX pCtx, VBOXDNDACTION dndActionDefault, VBOXDNDACTIONLIST dndLstActionsAllowed, const char* pcszFormats, uint32_t cbFormats); +VBGLR3DECL(int) VbglR3DnDGHSendData(PVBGLR3GUESTDNDCMDCTX pCtx, const char *pszFormat, void *pvData, uint32_t cbData); +# endif /* VBOX_WITH_DRAG_AND_DROP_GH */ +/** @} */ +# endif /* VBOX_WITH_DRAG_AND_DROP */ + +/* Generic Host Channel Service. */ +VBGLR3DECL(int) VbglR3HostChannelInit(uint32_t *pidClient); +VBGLR3DECL(void) VbglR3HostChannelTerm(uint32_t idClient); +VBGLR3DECL(int) VbglR3HostChannelAttach(uint32_t *pu32ChannelHandle, uint32_t u32HGCMClientId, + const char *pszName, uint32_t u32Flags); +VBGLR3DECL(void) VbglR3HostChannelDetach(uint32_t u32ChannelHandle, uint32_t u32HGCMClientId); +VBGLR3DECL(int) VbglR3HostChannelSend(uint32_t u32ChannelHandle, uint32_t u32HGCMClientId, + void *pvData, uint32_t cbData); +VBGLR3DECL(int) VbglR3HostChannelRecv(uint32_t u32ChannelHandle, uint32_t u32HGCMClientId, + void *pvData, uint32_t cbData, + uint32_t *pu32SizeReceived, uint32_t *pu32SizeRemaining); +VBGLR3DECL(int) VbglR3HostChannelControl(uint32_t u32ChannelHandle, uint32_t u32HGCMClientId, + uint32_t u32Code, void *pvParm, uint32_t cbParm, + void *pvData, uint32_t cbData, uint32_t *pu32SizeDataReturned); +VBGLR3DECL(int) VbglR3HostChannelEventWait(uint32_t *pu32ChannelHandle, uint32_t u32HGCMClientId, + uint32_t *pu32EventId, void *pvParm, uint32_t cbParm, + uint32_t *pu32SizeReturned); +VBGLR3DECL(int) VbglR3HostChannelEventCancel(uint32_t u32ChannelHandle, uint32_t u32HGCMClientId); +VBGLR3DECL(int) VbglR3HostChannelQuery(const char *pszName, uint32_t u32HGCMClientId, uint32_t u32Code, + void *pvParm, uint32_t cbParm, void *pvData, uint32_t cbData, + uint32_t *pu32SizeDataReturned); + +/** @name Mode hint storage + * @{ */ +VBGLR3DECL(int) VbglR3ReadVideoMode(unsigned cDisplay, unsigned *cx, + unsigned *cy, unsigned *cBPP, unsigned *x, + unsigned *y, unsigned *fEnabled); +VBGLR3DECL(int) VbglR3WriteVideoMode(unsigned cDisplay, unsigned cx, + unsigned cy, unsigned cBPP, unsigned x, + unsigned y, unsigned fEnabled); +/** @} */ + +/** @name Generic HGCM + * @{ */ +VBGLR3DECL(int) VbglR3HGCMConnect(const char *pszServiceName, HGCMCLIENTID *pidClient); +VBGLR3DECL(int) VbglR3HGCMDisconnect(HGCMCLIENTID idClient); +struct VBGLIOCHGCMCALL; +VBGLR3DECL(int) VbglR3HGCMCall(struct VBGLIOCHGCMCALL *pInfo, size_t cbInfo); +/** @} */ + +#endif /* IN_RING3 */ +/** @} */ + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_VBoxGuestLib_h */ diff --git a/include/VBox/VBoxGuestLibSharedFolders.h b/include/VBox/VBoxGuestLibSharedFolders.h new file mode 100644 index 00000000..c227cc39 --- /dev/null +++ b/include/VBox/VBoxGuestLibSharedFolders.h @@ -0,0 +1,131 @@ +/* $Id: VBoxGuestLibSharedFolders.h $ */ +/** @file + * VBoxGuestLib - Central calls header. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VBoxGuestLibSharedFolders_h +#define VBOX_INCLUDED_VBoxGuestLibSharedFolders_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +#ifndef IN_RING0 +# error "ring-0 only" +#endif + +RT_C_DECLS_BEGIN + + +/** @addtogroup grp_vboxguest_lib_r0 + * @{ + */ + +typedef struct VBGLSFCLIENT +{ + HGCMCLIENTID idClient; + VBGLHGCMHANDLE handle; +} VBGLSFCLIENT; +typedef VBGLSFCLIENT *PVBGLSFCLIENT; + +typedef struct VBGLSFMAP +{ + SHFLROOT root; +} VBGLSFMAP, *PVBGLSFMAP; + +DECLVBGL(int) VbglR0SfInit(void); +DECLVBGL(void) VbglR0SfTerm(void); +DECLVBGL(int) VbglR0SfConnect(PVBGLSFCLIENT pClient); +DECLVBGL(void) VbglR0SfDisconnect(PVBGLSFCLIENT pClient); + +DECLVBGL(int) VbglR0SfQueryMappings(PVBGLSFCLIENT pClient, SHFLMAPPING paMappings[], uint32_t *pcMappings); + +DECLVBGL(int) VbglR0SfQueryMapName(PVBGLSFCLIENT pClient, SHFLROOT root, SHFLSTRING *pString, uint32_t size); + +/** + * Create a new file or folder or open an existing one in a shared folder. Proxies + * to vbsfCreate in the host shared folder service. + * + * @returns IPRT status code, but see note below + * @param pClient Host-guest communication connection + * @param pMap The mapping for the shared folder in which the file + * or folder is to be created + * @param pParsedPath The path of the file or folder relative to the shared + * folder + * @param pCreateParms Parameters for file/folder creation. See the + * structure description in shflsvc.h + * @retval pCreateParms See the structure description in shflsvc.h + * + * @note This function reports errors as follows. The return value is always + * VINF_SUCCESS unless an exceptional condition occurs - out of + * memory, invalid arguments, etc. If the file or folder could not be + * opened or created, pCreateParms->Handle will be set to + * SHFL_HANDLE_NIL on return. In this case the value in + * pCreateParms->Result provides information as to why (e.g. + * SHFL_FILE_EXISTS). pCreateParms->Result is also set on success + * as additional information. + */ +DECLVBGL(int) VbglR0SfCreate(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING pParsedPath, PSHFLCREATEPARMS pCreateParms); + +DECLVBGL(int) VbglR0SfClose(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE Handle); +DECLVBGL(int) VbglR0SfRemove(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING pParsedPath, uint32_t flags); +DECLVBGL(int) VbglR0SfRename(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING pSrcPath, PSHFLSTRING pDestPath, uint32_t flags); +DECLVBGL(int) VbglR0SfFlush(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile); + +DECLVBGL(int) VbglR0SfRead(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, uint8_t *pBuffer, bool fLocked); +DECLVBGL(int) VbglR0SfReadPageList(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, + uint16_t offFirstPage, uint16_t cPages, RTGCPHYS64 *paPages); +DECLVBGL(int) VbglR0SfWrite(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, + uint32_t *pcbBuffer, uint8_t *pBuffer, bool fLocked); +DECLVBGL(int) VbglR0SfWritePhysCont(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, + uint32_t *pcbBuffer, RTCCPHYS PhysBuffer); +DECLVBGL(int) VbglR0SfWritePageList(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint32_t *pcbBuffer, + uint16_t offFirstPage, uint16_t cPages, RTGCPHYS64 *paPages); + +DECLVBGL(int) VbglR0SfLock(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint64_t offset, uint64_t cbSize, uint32_t fLock); + +DECLVBGL(int) VbglR0SfDirInfo(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile,PSHFLSTRING ParsedPath, uint32_t flags, + uint32_t index, uint32_t *pcbBuffer, PSHFLDIRINFO pBuffer, uint32_t *pcFiles); +DECLVBGL(int) VbglR0SfFsInfo(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, SHFLHANDLE hFile, uint32_t flags, uint32_t *pcbBuffer, PSHFLDIRINFO pBuffer); + +DECLVBGL(int) VbglR0SfMapFolder(PVBGLSFCLIENT pClient, PSHFLSTRING szFolderName, PVBGLSFMAP pMap); +DECLVBGL(int) VbglR0SfUnmapFolder(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap); +DECLVBGL(int) VbglR0SfSetUtf8(PVBGLSFCLIENT pClient); + +DECLVBGL(int) VbglR0SfReadLink(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING ParsedPath, uint32_t pcbBuffer, uint8_t *pBuffer); +DECLVBGL(int) VbglR0SfSymlink(PVBGLSFCLIENT pClient, PVBGLSFMAP pMap, PSHFLSTRING pNewPath, PSHFLSTRING pOldPath, PSHFLFSOBJINFO pBuffer); +DECLVBGL(int) VbglR0SfSetSymlinks(PVBGLSFCLIENT pClient); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_VBoxGuestLibSharedFolders_h */ + diff --git a/include/VBox/VBoxGuestLibSharedFoldersInline.h b/include/VBox/VBoxGuestLibSharedFoldersInline.h new file mode 100644 index 00000000..7d67ffea --- /dev/null +++ b/include/VBox/VBoxGuestLibSharedFoldersInline.h @@ -0,0 +1,1612 @@ +/* $Id: VBoxGuestLibSharedFoldersInline.h $ */ +/** @file + * VBoxGuestLib - Shared Folders Host Request Helpers (ring-0). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VBoxGuestLibSharedFoldersInline_h +#define VBOX_INCLUDED_VBoxGuestLibSharedFoldersInline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + + +/** @defgroup grp_vboxguest_lib_r0_sf_inline Shared Folders Host Request Helpers + * @ingroup grp_vboxguest_lib_r0 + * + * @note Using inline functions to avoid wasting precious ring-0 stack space on + * passing parameters that ends up in the structure @a pReq points to. It + * is also safe to assume that it's faster too. It's worth a few bytes + * larger code section in the resulting shared folders driver. + * + * @note This currently requires a C++ compiler or a C compiler capable of + * mixing code and variables (i.e. C99). + * + * @{ + */ + +/** VMMDEV_HVF_XXX (set during init). */ +extern uint32_t g_fHostFeatures; +extern VBGLSFCLIENT g_SfClient; /**< Move this into the parameters? */ + +/** Request structure for VbglR0SfHostReqQueryFeatures. */ +typedef struct VBOXSFQUERYFEATURES +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmQueryFeatures Parms; +} VBOXSFQUERYFEATURES; + +/** + * SHFL_FN_QUERY_FEATURES request. + */ +DECLINLINE(int) VbglR0SfHostReqQueryFeatures(VBOXSFQUERYFEATURES *pReq) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_QUERY_FEATURES, SHFL_CPARMS_QUERY_FEATURES, sizeof(*pReq)); + + pReq->Parms.f64Features.type = VMMDevHGCMParmType_64bit; + pReq->Parms.f64Features.u.value64 = 0; + + pReq->Parms.u32LastFunction.type = VMMDevHGCMParmType_32bit; + pReq->Parms.u32LastFunction.u.value32 = 0; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + + /* + * Provide fallback values based on g_fHostFeatures to simplify + * compatibility with older hosts and avoid duplicating this logic. + */ + if (RT_FAILURE(vrc)) + { + pReq->Parms.f64Features.u.value64 = 0; + pReq->Parms.u32LastFunction.u.value32 = g_fHostFeatures & VMMDEV_HVF_HGCM_NO_BOUNCE_PAGE_LIST + ? SHFL_FN_SET_FILE_SIZE : SHFL_FN_SET_SYMLINKS; + if (vrc == VERR_NOT_SUPPORTED) + vrc = VINF_NOT_SUPPORTED; + } + return vrc; +} + +/** + * SHFL_FN_QUERY_FEATURES request, simplified version. + */ +DECLINLINE(int) VbglR0SfHostReqQueryFeaturesSimple(uint64_t *pfFeatures, uint32_t *puLastFunction) +{ + VBOXSFQUERYFEATURES *pReq = (VBOXSFQUERYFEATURES *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int rc = VbglR0SfHostReqQueryFeatures(pReq); + if (pfFeatures) + *pfFeatures = pReq->Parms.f64Features.u.value64; + if (puLastFunction) + *puLastFunction = pReq->Parms.u32LastFunction.u.value32; + + VbglR0PhysHeapFree(pReq); + return rc; + } + return VERR_NO_MEMORY; +} + + +/** Request structure for VbglR0SfHostReqSetUtf8 and VbglR0SfHostReqSetSymlink. */ +typedef struct VBOXSFNOPARMS +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + /* no parameters */ +} VBOXSFNOPARMS; + +/** + * Worker for request without any parameters. + */ +DECLINLINE(int) VbglR0SfHostReqNoParms(VBOXSFNOPARMS *pReq, uint32_t uFunction, uint32_t cParms) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + uFunction, cParms, sizeof(*pReq)); + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * Worker for request without any parameters, simplified. + */ +DECLINLINE(int) VbglR0SfHostReqNoParmsSimple(uint32_t uFunction, uint32_t cParms) +{ + VBOXSFNOPARMS *pReq = (VBOXSFNOPARMS *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int vrc = VbglR0SfHostReqNoParms(pReq, uFunction, cParms); + VbglR0PhysHeapFree(pReq); + return vrc; + } + return VERR_NO_MEMORY; +} + + +/** + * SHFL_F_SET_UTF8 request. + */ +DECLINLINE(int) VbglR0SfHostReqSetUtf8(VBOXSFNOPARMS *pReq) +{ + return VbglR0SfHostReqNoParms(pReq, SHFL_FN_SET_UTF8, SHFL_CPARMS_SET_UTF8); +} + +/** + * SHFL_F_SET_UTF8 request, simplified version. + */ +DECLINLINE(int) VbglR0SfHostReqSetUtf8Simple(void) +{ + return VbglR0SfHostReqNoParmsSimple(SHFL_FN_SET_UTF8, SHFL_CPARMS_SET_UTF8); +} + + +/** + * SHFL_F_SET_SYMLINKS request. + */ +DECLINLINE(int) VbglR0SfHostReqSetSymlinks(VBOXSFNOPARMS *pReq) +{ + return VbglR0SfHostReqNoParms(pReq, SHFL_FN_SET_SYMLINKS, SHFL_CPARMS_SET_SYMLINKS); +} + +/** + * SHFL_F_SET_SYMLINKS request, simplified version. + */ +DECLINLINE(int) VbglR0SfHostReqSetSymlinksSimple(void) +{ + return VbglR0SfHostReqNoParmsSimple(SHFL_FN_SET_SYMLINKS, SHFL_CPARMS_SET_SYMLINKS); +} + + +/** Request structure for VbglR0SfHostReqSetErrorStyle. */ +typedef struct VBOXSFSETERRORSTYLE +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmSetErrorStyle Parms; +} VBOXSFSETERRORSTYLE; + +/** + * SHFL_FN_QUERY_FEATURES request. + */ +DECLINLINE(int) VbglR0SfHostReqSetErrorStyle(VBOXSFSETERRORSTYLE *pReq, SHFLERRORSTYLE enmStyle) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_SET_ERROR_STYLE, SHFL_CPARMS_SET_ERROR_STYLE, sizeof(*pReq)); + + pReq->Parms.u32Style.type = VMMDevHGCMParmType_32bit; + pReq->Parms.u32Style.u.value32 = (uint32_t)enmStyle; + + pReq->Parms.u32Reserved.type = VMMDevHGCMParmType_32bit; + pReq->Parms.u32Reserved.u.value32 = 0; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_QUERY_FEATURES request, simplified version. + */ +DECLINLINE(int) VbglR0SfHostReqSetErrorStyleSimple(SHFLERRORSTYLE enmStyle) +{ + VBOXSFSETERRORSTYLE *pReq = (VBOXSFSETERRORSTYLE *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int rc = VbglR0SfHostReqSetErrorStyle(pReq, enmStyle); + VbglR0PhysHeapFree(pReq); + return rc; + } + return VERR_NO_MEMORY; +} + + +/** Request structure for VbglR0SfHostReqMapFolderWithBuf. */ +typedef struct VBOXSFMAPFOLDERWITHBUFREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmMapFolder Parms; + HGCMPageListInfo PgLst; +} VBOXSFMAPFOLDERWITHBUFREQ; + + +/** + * SHFL_FN_MAP_FOLDER request. + */ +DECLINLINE(int) VbglR0SfHostReqMapFolderWithContig(VBOXSFMAPFOLDERWITHBUFREQ *pReq, PSHFLSTRING pStrName, RTGCPHYS64 PhysStrName, + RTUTF16 wcDelimiter, bool fCaseSensitive) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_MAP_FOLDER, SHFL_CPARMS_MAP_FOLDER, sizeof(*pReq)); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = SHFL_ROOT_NIL; + + pReq->Parms.uc32Delimiter.type = VMMDevHGCMParmType_32bit; + pReq->Parms.uc32Delimiter.u.value32 = wcDelimiter; + + pReq->Parms.fCaseSensitive.type = VMMDevHGCMParmType_32bit; + pReq->Parms.fCaseSensitive.u.value32 = fCaseSensitive; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + { + pReq->Parms.pStrName.type = VMMDevHGCMParmType_PageList; + pReq->Parms.pStrName.u.PageList.size = SHFLSTRING_HEADER_SIZE + pStrName->u16Size; + pReq->Parms.pStrName.u.PageList.offset = RT_UOFFSETOF(VBOXSFMAPFOLDERWITHBUFREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_BOTH; + pReq->PgLst.offFirstPage = (uint16_t)PhysStrName & (uint16_t)(PAGE_OFFSET_MASK); + pReq->PgLst.aPages[0] = PhysStrName & ~(RTGCPHYS64)PAGE_OFFSET_MASK; + pReq->PgLst.cPages = 1; + } + else + { + pReq->Parms.pStrName.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrName.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pStrName->u16Size; + pReq->Parms.pStrName.u.LinAddr.uAddr = (uintptr_t)pStrName; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_MAP_FOLDER request. + */ +DECLINLINE(int) VbglR0SfHostReqMapFolderWithContigSimple(PSHFLSTRING pStrName, RTGCPHYS64 PhysStrName, + RTUTF16 wcDelimiter, bool fCaseSensitive, SHFLROOT *pidRoot) +{ + VBOXSFMAPFOLDERWITHBUFREQ *pReq = (VBOXSFMAPFOLDERWITHBUFREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int rc = VbglR0SfHostReqMapFolderWithContig(pReq, pStrName, PhysStrName, wcDelimiter, fCaseSensitive); + *pidRoot = RT_SUCCESS(rc) ? pReq->Parms.id32Root.u.value32 : SHFL_ROOT_NIL; + VbglR0PhysHeapFree(pReq); + return rc; + } + *pidRoot = SHFL_ROOT_NIL; + return VERR_NO_MEMORY; +} + + +/** + * SHFL_FN_MAP_FOLDER request. + */ +DECLINLINE(int) VbglR0SfHostReqMapFolderWithBuf(VBOXSFMAPFOLDERWITHBUFREQ *pReq, PSHFLSTRING pStrName, + RTUTF16 wcDelimiter, bool fCaseSensitive) +{ + return VbglR0SfHostReqMapFolderWithContig(pReq, pStrName, VbglR0PhysHeapGetPhysAddr(pStrName), wcDelimiter, fCaseSensitive); +} + + + +/** Request structure used by vboxSfOs2HostReqUnmapFolder. */ +typedef struct VBOXSFUNMAPFOLDERREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmUnmapFolder Parms; +} VBOXSFUNMAPFOLDERREQ; + + +/** + * SHFL_FN_UNMAP_FOLDER request. + */ +DECLINLINE(int) VbglR0SfHostReqUnmapFolderSimple(uint32_t idRoot) +{ + VBOXSFUNMAPFOLDERREQ *pReq = (VBOXSFUNMAPFOLDERREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_UNMAP_FOLDER, SHFL_CPARMS_UNMAP_FOLDER, sizeof(*pReq)); + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + + VbglR0PhysHeapFree(pReq); + return vrc; + } + return VERR_NO_MEMORY; +} + + +/** Request structure for VbglR0SfHostReqCreate. */ +typedef struct VBOXSFCREATEREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmCreate Parms; + SHFLCREATEPARMS CreateParms; + SHFLSTRING StrPath; +} VBOXSFCREATEREQ; + +/** + * SHFL_FN_CREATE request. + */ +DECLINLINE(int) VbglR0SfHostReqCreate(SHFLROOT idRoot, VBOXSFCREATEREQ *pReq) +{ + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath.String) + pReq->StrPath.u16Size + : RT_UOFFSETOF(VBOXSFCREATEREQ, CreateParms); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_CREATE, SHFL_CPARMS_CREATE, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pStrPath.u.Embedded.cbData = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.Embedded.offData = RT_UOFFSETOF(VBOXSFCREATEREQ, StrPath) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pStrPath.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + + pReq->Parms.pCreateParms.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pCreateParms.u.Embedded.cbData = sizeof(pReq->CreateParms); + pReq->Parms.pCreateParms.u.Embedded.offData = RT_UOFFSETOF(VBOXSFCREATEREQ, CreateParms) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pCreateParms.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_BOTH; + } + else + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrPath.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.LinAddr.uAddr = (uintptr_t)&pReq->StrPath; + + pReq->Parms.pCreateParms.type = VMMDevHGCMParmType_LinAddr; + pReq->Parms.pCreateParms.u.LinAddr.cb = sizeof(pReq->CreateParms); + pReq->Parms.pCreateParms.u.LinAddr.uAddr = (uintptr_t)&pReq->CreateParms; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqClose. */ +typedef struct VBOXSFCLOSEREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmClose Parms; +} VBOXSFCLOSEREQ; + +/** + * SHFL_FN_CLOSE request. + */ +DECLINLINE(int) VbglR0SfHostReqClose(SHFLROOT idRoot, VBOXSFCLOSEREQ *pReq, uint64_t hHostFile) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_CLOSE, SHFL_CPARMS_CLOSE, sizeof(*pReq)); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_CLOSE request, allocate request buffer. + */ +DECLINLINE(int) VbglR0SfHostReqCloseSimple(SHFLROOT idRoot, uint64_t hHostFile) +{ + VBOXSFCLOSEREQ *pReq = (VBOXSFCLOSEREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int vrc = VbglR0SfHostReqClose(idRoot, pReq, hHostFile); + VbglR0PhysHeapFree(pReq); + return vrc; + } + return VERR_NO_MEMORY; +} + + +/** Request structure for VbglR0SfHostReqQueryVolInfo. */ +typedef struct VBOXSFVOLINFOREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmInformation Parms; + SHFLVOLINFO VolInfo; +} VBOXSFVOLINFOREQ; + +/** + * SHFL_FN_INFORMATION[SHFL_INFO_VOLUME | SHFL_INFO_GET] request. + */ +DECLINLINE(int) VbglR0SfHostReqQueryVolInfo(SHFLROOT idRoot, VBOXSFVOLINFOREQ *pReq, uint64_t hHostFile) +{ + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? sizeof(*pReq) : RT_UOFFSETOF(VBOXSFVOLINFOREQ, VolInfo); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = SHFL_INFO_VOLUME | SHFL_INFO_GET; + + pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32.u.value32 = sizeof(pReq->VolInfo); + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pInfo.u.Embedded.cbData = sizeof(pReq->VolInfo); + pReq->Parms.pInfo.u.Embedded.offData = RT_UOFFSETOF(VBOXSFVOLINFOREQ, VolInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pInfo.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + } + else + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pInfo.u.LinAddr.cb = sizeof(pReq->VolInfo); + pReq->Parms.pInfo.u.LinAddr.uAddr = (uintptr_t)&pReq->VolInfo; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqSetObjInfo & VbglR0SfHostReqQueryObjInfo. */ +typedef struct VBOXSFOBJINFOREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmInformation Parms; + SHFLFSOBJINFO ObjInfo; +} VBOXSFOBJINFOREQ; + +/** + * SHFL_FN_INFORMATION[SHFL_INFO_GET | SHFL_INFO_FILE] request. + */ +DECLINLINE(int) VbglR0SfHostReqQueryObjInfo(SHFLROOT idRoot, VBOXSFOBJINFOREQ *pReq, uint64_t hHostFile) +{ + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? sizeof(*pReq) : RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = SHFL_INFO_GET | SHFL_INFO_FILE; + + pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32.u.value32 = sizeof(pReq->ObjInfo); + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pInfo.u.Embedded.cbData = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.Embedded.offData = RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pInfo.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + } + else + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pInfo.u.LinAddr.cb = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.LinAddr.uAddr = (uintptr_t)&pReq->ObjInfo; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** + * SHFL_FN_INFORMATION[SHFL_INFO_SET | SHFL_INFO_FILE] request. + */ +DECLINLINE(int) VbglR0SfHostReqSetObjInfo(SHFLROOT idRoot, VBOXSFOBJINFOREQ *pReq, uint64_t hHostFile) +{ + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? sizeof(*pReq) : RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = SHFL_INFO_SET | SHFL_INFO_FILE; + + pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32.u.value32 = sizeof(pReq->ObjInfo); + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pInfo.u.Embedded.cbData = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.Embedded.offData = RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pInfo.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_BOTH; + } + else + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_LinAddr; + pReq->Parms.pInfo.u.LinAddr.cb = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.LinAddr.uAddr = (uintptr_t)&pReq->ObjInfo; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** + * SHFL_FN_INFORMATION[SHFL_INFO_SET | SHFL_INFO_SIZE] request. + */ +DECLINLINE(int) VbglR0SfHostReqSetFileSizeOld(SHFLROOT idRoot, VBOXSFOBJINFOREQ *pReq, uint64_t hHostFile) +{ + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? sizeof(*pReq) : RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = SHFL_INFO_SET | SHFL_INFO_SIZE; + + pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32.u.value32 = sizeof(pReq->ObjInfo); + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pInfo.u.Embedded.cbData = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.Embedded.offData = RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pInfo.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_BOTH; + } + else + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_LinAddr; + pReq->Parms.pInfo.u.LinAddr.cb = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.LinAddr.uAddr = (uintptr_t)&pReq->ObjInfo; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqSetObjInfo. */ +typedef struct VBOXSFOBJINFOWITHBUFREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmInformation Parms; + HGCMPageListInfo PgLst; +} VBOXSFOBJINFOWITHBUFREQ; + +/** + * SHFL_FN_INFORMATION[SHFL_INFO_SET | SHFL_INFO_FILE] request, with separate + * buffer (on the physical heap). + */ +DECLINLINE(int) VbglR0SfHostReqSetObjInfoWithBuf(SHFLROOT idRoot, VBOXSFOBJINFOWITHBUFREQ *pReq, uint64_t hHostFile, + PSHFLFSOBJINFO pObjInfo, uint32_t offObjInfoInAlloc) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_INFORMATION, SHFL_CPARMS_INFORMATION, sizeof(*pReq)); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = SHFL_INFO_SET | SHFL_INFO_FILE; + + pReq->Parms.cb32.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32.u.value32 = sizeof(*pObjInfo); + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pInfo.u.PageList.size = sizeof(*pObjInfo); + pReq->Parms.pInfo.u.PageList.offset = RT_UOFFSETOF(VBOXSFOBJINFOREQ, ObjInfo) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_BOTH; + pReq->PgLst.aPages[0] = VbglR0PhysHeapGetPhysAddr((uint8_t *)pObjInfo - offObjInfoInAlloc) + offObjInfoInAlloc; + pReq->PgLst.offFirstPage = (uint16_t)(pReq->PgLst.aPages[0] & PAGE_OFFSET_MASK); + pReq->PgLst.aPages[0] &= ~(RTGCPHYS)PAGE_OFFSET_MASK; + pReq->PgLst.cPages = 1; + } + else + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_LinAddr; + pReq->Parms.pInfo.u.LinAddr.cb = sizeof(*pObjInfo); + pReq->Parms.pInfo.u.LinAddr.uAddr = (uintptr_t)pObjInfo; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqRemove. */ +typedef struct VBOXSFREMOVEREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmRemove Parms; + SHFLSTRING StrPath; +} VBOXSFREMOVEREQ; + +/** + * SHFL_FN_REMOVE request. + */ +DECLINLINE(int) VbglR0SfHostReqRemove(SHFLROOT idRoot, VBOXSFREMOVEREQ *pReq, uint32_t fFlags) +{ + uint32_t const cbReq = RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath.String) + + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? pReq->StrPath.u16Size : 0); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_REMOVE, SHFL_CPARMS_REMOVE, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pStrPath.u.Embedded.cbData = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.Embedded.offData = RT_UOFFSETOF(VBOXSFREMOVEREQ, StrPath) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pStrPath.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + } + else + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrPath.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.LinAddr.uAddr = (uintptr_t)&pReq->StrPath; + } + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = fFlags; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqCloseAndRemove. */ +typedef struct VBOXSFCLOSEANDREMOVEREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmCloseAndRemove Parms; + SHFLSTRING StrPath; +} VBOXSFCLOSEANDREMOVEREQ; + +/** + * SHFL_FN_CLOSE_AND_REMOVE request. + */ +DECLINLINE(int) VbglR0SfHostReqCloseAndRemove(SHFLROOT idRoot, VBOXSFCLOSEANDREMOVEREQ *pReq, uint32_t fFlags, SHFLHANDLE hToClose) +{ + uint32_t const cbReq = RT_UOFFSETOF(VBOXSFCLOSEANDREMOVEREQ, StrPath.String) + + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? pReq->StrPath.u16Size : 0); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_CLOSE_AND_REMOVE, SHFL_CPARMS_CLOSE_AND_REMOVE, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pStrPath.u.Embedded.cbData = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.Embedded.offData = RT_UOFFSETOF(VBOXSFCLOSEANDREMOVEREQ, StrPath) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pStrPath.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + } + else + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrPath.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.LinAddr.uAddr = (uintptr_t)&pReq->StrPath; + } + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = fFlags; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hToClose; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqRenameWithSrcContig and + * VbglR0SfHostReqRenameWithSrcBuf. */ +typedef struct VBOXSFRENAMEWITHSRCBUFREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmRename Parms; + HGCMPageListInfo PgLst; + SHFLSTRING StrDstPath; +} VBOXSFRENAMEWITHSRCBUFREQ; + + +/** + * SHFL_FN_REMOVE request. + */ +DECLINLINE(int) VbglR0SfHostReqRenameWithSrcContig(SHFLROOT idRoot, VBOXSFRENAMEWITHSRCBUFREQ *pReq, + PSHFLSTRING pSrcStr, RTGCPHYS64 PhysSrcStr, uint32_t fFlags) +{ + uint32_t const cbReq = RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, StrDstPath.String) + + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? pReq->StrDstPath.u16Size : 0); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_RENAME, SHFL_CPARMS_RENAME, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + { + pReq->Parms.pStrSrcPath.type = VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pStrSrcPath.u.PageList.size = SHFLSTRING_HEADER_SIZE + pSrcStr->u16Size; + pReq->Parms.pStrSrcPath.u.PageList.offset = RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, PgLst) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + pReq->PgLst.offFirstPage = (uint16_t)PhysSrcStr & (uint16_t)(PAGE_OFFSET_MASK); + pReq->PgLst.aPages[0] = PhysSrcStr & ~(RTGCPHYS64)PAGE_OFFSET_MASK; + pReq->PgLst.cPages = 1; + } + else + { + pReq->Parms.pStrSrcPath.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrSrcPath.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pSrcStr->u16Size; + pReq->Parms.pStrSrcPath.u.LinAddr.uAddr = (uintptr_t)pSrcStr; + } + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pStrDstPath.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pStrDstPath.u.Embedded.cbData = SHFLSTRING_HEADER_SIZE + pReq->StrDstPath.u16Size; + pReq->Parms.pStrDstPath.u.Embedded.offData = RT_UOFFSETOF(VBOXSFRENAMEWITHSRCBUFREQ, StrDstPath) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pStrDstPath.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + } + else + { + pReq->Parms.pStrDstPath.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrDstPath.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pReq->StrDstPath.u16Size; + pReq->Parms.pStrDstPath.u.LinAddr.uAddr = (uintptr_t)&pReq->StrDstPath; + } + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = fFlags; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** + * SHFL_FN_REMOVE request. + */ +DECLINLINE(int) VbglR0SfHostReqRenameWithSrcBuf(SHFLROOT idRoot, VBOXSFRENAMEWITHSRCBUFREQ *pReq, + PSHFLSTRING pSrcStr, uint32_t fFlags) +{ + return VbglR0SfHostReqRenameWithSrcContig(idRoot, pReq, pSrcStr, VbglR0PhysHeapGetPhysAddr(pSrcStr), fFlags); +} + + +/** Request structure for VbglR0SfHostReqFlush. */ +typedef struct VBOXSFFLUSHREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmFlush Parms; +} VBOXSFFLUSHREQ; + +/** + * SHFL_FN_FLUSH request. + */ +DECLINLINE(int) VbglR0SfHostReqFlush(SHFLROOT idRoot, VBOXSFFLUSHREQ *pReq, uint64_t hHostFile) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_FLUSH, SHFL_CPARMS_FLUSH, sizeof(*pReq)); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_FLUSH request, allocate request buffer. + */ +DECLINLINE(int) VbglR0SfHostReqFlushSimple(SHFLROOT idRoot, uint64_t hHostFile) +{ + VBOXSFFLUSHREQ *pReq = (VBOXSFFLUSHREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int vrc = VbglR0SfHostReqFlush(idRoot, pReq, hHostFile); + VbglR0PhysHeapFree(pReq); + return vrc; + } + return VERR_NO_MEMORY; +} + + +/** Request structure for VbglR0SfHostReqSetFileSize. */ +typedef struct VBOXSFSETFILESIZEREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmSetFileSize Parms; +} VBOXSFSETFILESIZEREQ; + +/** + * SHFL_FN_SET_FILE_SIZE request. + */ +DECLINLINE(int) VbglR0SfHostReqSetFileSize(SHFLROOT idRoot, VBOXSFSETFILESIZEREQ *pReq, uint64_t hHostFile, uint64_t cbNewSize) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_SET_FILE_SIZE, SHFL_CPARMS_SET_FILE_SIZE, sizeof(*pReq)); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.cb64NewSize.type = VMMDevHGCMParmType_64bit; + pReq->Parms.cb64NewSize.u.value64 = cbNewSize; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_SET_FILE_SIZE request, allocate request buffer. + */ +DECLINLINE(int) VbglR0SfHostReqSetFileSizeSimple(SHFLROOT idRoot, uint64_t hHostFile, uint64_t cbNewSize) +{ + VBOXSFSETFILESIZEREQ *pReq = (VBOXSFSETFILESIZEREQ *)VbglR0PhysHeapAlloc(sizeof(*pReq)); + if (pReq) + { + int vrc = VbglR0SfHostReqSetFileSize(idRoot, pReq, hHostFile, cbNewSize); + VbglR0PhysHeapFree(pReq); + return vrc; + } + return VERR_NO_MEMORY; +} + + +/** Request structure for VbglR0SfHostReqReadEmbedded. */ +typedef struct VBOXSFREADEMBEDDEDREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmRead Parms; + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abData[RT_FLEXIBLE_ARRAY]; +} VBOXSFREADEMBEDDEDREQ; + +/** + * SHFL_FN_READ request using embedded data buffer. + */ +DECLINLINE(int) VbglR0SfHostReqReadEmbedded(SHFLROOT idRoot, VBOXSFREADEMBEDDEDREQ *pReq, uint64_t hHostFile, + uint64_t offRead, uint32_t cbToRead) +{ + uint32_t const cbReq = RT_UOFFSETOF(VBOXSFREADEMBEDDEDREQ, abData[0]) + + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? cbToRead : 0); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_READ, SHFL_CPARMS_READ, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.off64Read.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Read.u.value64 = offRead; + + pReq->Parms.cb32Read.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Read.u.value32 = cbToRead; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pBuf.u.Embedded.cbData = cbToRead; + pReq->Parms.pBuf.u.Embedded.offData = RT_UOFFSETOF(VBOXSFREADEMBEDDEDREQ, abData[0]) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pBuf.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + } + else + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pBuf.u.LinAddr.cb = cbToRead; + pReq->Parms.pBuf.u.LinAddr.uAddr = (uintptr_t)&pReq->abData[0]; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for vboxSfOs2HostReqRead & VbglR0SfHostReqReadContig. */ +typedef struct VBOXSFREADPGLSTREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmRead Parms; + HGCMPageListInfo PgLst; +} VBOXSFREADPGLSTREQ; + +/** + * SHFL_FN_READ request using page list for data buffer (caller populated). + */ +DECLINLINE(int) VbglR0SfHostReqReadPgLst(SHFLROOT idRoot, VBOXSFREADPGLSTREQ *pReq, uint64_t hHostFile, + uint64_t offRead, uint32_t cbToRead, uint32_t cPages) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_READ, SHFL_CPARMS_READ, + RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[cPages])); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.off64Read.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Read.u.value64 = offRead; + + pReq->Parms.cb32Read.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Read.u.value32 = cbToRead; + + pReq->Parms.pBuf.type = g_fHostFeatures & VMMDEV_HVF_HGCM_NO_BOUNCE_PAGE_LIST + ? VMMDevHGCMParmType_NoBouncePageList : VMMDevHGCMParmType_PageList; + pReq->Parms.pBuf.u.PageList.size = cbToRead; + pReq->Parms.pBuf.u.PageList.offset = RT_UOFFSETOF(VBOXSFREADPGLSTREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + pReq->PgLst.cPages = (uint16_t)cPages; + AssertReturn(cPages <= UINT16_MAX, VERR_OUT_OF_RANGE); + /* caller sets offset */ + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, + RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[cPages])); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** + * SHFL_FN_READ request using a physically contiguous buffer. + */ +DECLINLINE(int) VbglR0SfHostReqReadContig(SHFLROOT idRoot, VBOXSFREADPGLSTREQ *pReq, uint64_t hHostFile, + uint64_t offRead, uint32_t cbToRead, void *pvBuffer, RTGCPHYS64 PhysBuffer) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_READ, SHFL_CPARMS_READ, RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[1])); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.off64Read.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Read.u.value64 = offRead; + + pReq->Parms.cb32Read.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Read.u.value32 = cbToRead; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pBuf.u.PageList.size = cbToRead; + pReq->Parms.pBuf.u.PageList.offset = RT_UOFFSETOF(VBOXSFREADPGLSTREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + pReq->PgLst.offFirstPage = (uint16_t)(PhysBuffer & PAGE_OFFSET_MASK); + pReq->PgLst.cPages = 1; + pReq->PgLst.aPages[0] = PhysBuffer & ~(RTGCPHYS64)PAGE_OFFSET_MASK; + } + else + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pBuf.u.LinAddr.cb = cbToRead; + pReq->Parms.pBuf.u.LinAddr.uAddr = (uintptr_t)pvBuffer; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, RT_UOFFSETOF_DYN(VBOXSFREADPGLSTREQ, PgLst.aPages[1])); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + + +/** Request structure for VbglR0SfHostReqWriteEmbedded. */ +typedef struct VBOXSFWRITEEMBEDDEDREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmWrite Parms; + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abData[RT_FLEXIBLE_ARRAY]; +} VBOXSFWRITEEMBEDDEDREQ; + +/** + * SHFL_FN_WRITE request using embedded data buffer. + */ +DECLINLINE(int) VbglR0SfHostReqWriteEmbedded(SHFLROOT idRoot, VBOXSFWRITEEMBEDDEDREQ *pReq, uint64_t hHostFile, + uint64_t offWrite, uint32_t cbToWrite) +{ + uint32_t const cbReq = RT_UOFFSETOF(VBOXSFWRITEEMBEDDEDREQ, abData[0]) + + (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS ? cbToWrite : 0); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_WRITE, SHFL_CPARMS_WRITE, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.off64Write.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Write.u.value64 = offWrite; + + pReq->Parms.cb32Write.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Write.u.value32 = cbToWrite; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pBuf.u.Embedded.cbData = cbToWrite; + pReq->Parms.pBuf.u.Embedded.offData = RT_UOFFSETOF(VBOXSFWRITEEMBEDDEDREQ, abData[0]) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pBuf.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + } + else + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pBuf.u.LinAddr.cb = cbToWrite; + pReq->Parms.pBuf.u.LinAddr.uAddr = (uintptr_t)&pReq->abData[0]; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for vboxSfOs2HostReqWrite and VbglR0SfHostReqWriteContig. */ +typedef struct VBOXSFWRITEPGLSTREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmWrite Parms; + HGCMPageListInfo PgLst; +} VBOXSFWRITEPGLSTREQ; + +/** + * SHFL_FN_WRITE request using page list for data buffer (caller populated). + */ +DECLINLINE(int) VbglR0SfHostReqWritePgLst(SHFLROOT idRoot, VBOXSFWRITEPGLSTREQ *pReq, uint64_t hHostFile, + uint64_t offWrite, uint32_t cbToWrite, uint32_t cPages) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_WRITE, SHFL_CPARMS_WRITE, + RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[cPages])); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.off64Write.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Write.u.value64 = offWrite; + + pReq->Parms.cb32Write.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Write.u.value32 = cbToWrite; + + pReq->Parms.pBuf.type = g_fHostFeatures & VMMDEV_HVF_HGCM_NO_BOUNCE_PAGE_LIST + ? VMMDevHGCMParmType_NoBouncePageList : VMMDevHGCMParmType_PageList;; + pReq->Parms.pBuf.u.PageList.size = cbToWrite; + pReq->Parms.pBuf.u.PageList.offset = RT_UOFFSETOF(VBOXSFWRITEPGLSTREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + pReq->PgLst.cPages = (uint16_t)cPages; + AssertReturn(cPages <= UINT16_MAX, VERR_OUT_OF_RANGE); + /* caller sets offset */ + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, + RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[cPages])); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** + * SHFL_FN_WRITE request using a physically contiguous buffer. + */ +DECLINLINE(int) VbglR0SfHostReqWriteContig(SHFLROOT idRoot, VBOXSFWRITEPGLSTREQ *pReq, uint64_t hHostFile, + uint64_t offWrite, uint32_t cbToWrite, void const *pvBuffer, RTGCPHYS64 PhysBuffer) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_WRITE, SHFL_CPARMS_WRITE, RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[1])); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostFile; + + pReq->Parms.off64Write.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Write.u.value64 = offWrite; + + pReq->Parms.cb32Write.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Write.u.value32 = cbToWrite; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pBuf.u.PageList.size = cbToWrite; + pReq->Parms.pBuf.u.PageList.offset = RT_UOFFSETOF(VBOXSFWRITEPGLSTREQ, PgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + pReq->PgLst.offFirstPage = (uint16_t)(PhysBuffer & PAGE_OFFSET_MASK); + pReq->PgLst.cPages = 1; + pReq->PgLst.aPages[0] = PhysBuffer & ~(RTGCPHYS64)PAGE_OFFSET_MASK; + } + else + { + pReq->Parms.pBuf.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pBuf.u.LinAddr.cb = cbToWrite; + pReq->Parms.pBuf.u.LinAddr.uAddr = (uintptr_t)pvBuffer; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, RT_UOFFSETOF_DYN(VBOXSFWRITEPGLSTREQ, PgLst.aPages[1])); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + +/** Request structure for VbglR0SfHostReqCopyFilePart. */ +typedef struct VBOXSFCOPYFILEPARTREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmCopyFilePart Parms; +} VBOXSFCOPYFILEPARTREQ; + +/** + * SHFL_FN_CREATE request. + */ +DECLINLINE(int) VbglR0SfHostReqCopyFilePart(SHFLROOT idRootSrc, SHFLHANDLE hHostFileSrc, uint64_t offSrc, + SHFLROOT idRootDst, SHFLHANDLE hHostFileDst, uint64_t offDst, + uint64_t cbToCopy, uint32_t fFlags, VBOXSFCOPYFILEPARTREQ *pReq) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_COPY_FILE_PART, SHFL_CPARMS_COPY_FILE_PART, sizeof(*pReq)); + + pReq->Parms.id32RootSrc.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32RootSrc.u.value32 = idRootSrc; + + pReq->Parms.u64HandleSrc.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64HandleSrc.u.value64 = hHostFileSrc; + + pReq->Parms.off64Src.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Src.u.value64 = offSrc; + + pReq->Parms.id32RootDst.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32RootDst.u.value32 = idRootDst; + + pReq->Parms.u64HandleDst.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64HandleDst.u.value64 = hHostFileDst; + + pReq->Parms.off64Dst.type = VMMDevHGCMParmType_64bit; + pReq->Parms.off64Dst.u.value64 = offDst; + + pReq->Parms.cb64ToCopy.type = VMMDevHGCMParmType_64bit; + pReq->Parms.cb64ToCopy.u.value64 = cbToCopy; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = fFlags; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + + + +/** Request structure for VbglR0SfHostReqListDirContig2x() and + * VbglR0SfHostReqListDir(). */ +typedef struct VBOXSFLISTDIRREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmList Parms; + HGCMPageListInfo StrPgLst; + HGCMPageListInfo BufPgLst; +} VBOXSFLISTDIRREQ; + +/** + * SHFL_FN_LIST request with separate string buffer and buffers for entries, + * both physically contiguous allocations. + */ +DECLINLINE(int) VbglR0SfHostReqListDirContig2x(SHFLROOT idRoot, VBOXSFLISTDIRREQ *pReq, uint64_t hHostDir, + PSHFLSTRING pFilter, RTGCPHYS64 PhysFilter, uint32_t fFlags, + PSHFLDIRINFO pBuffer, RTGCPHYS64 PhysBuffer, uint32_t cbBuffer) +{ + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_LIST, SHFL_CPARMS_LIST, sizeof(*pReq)); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + pReq->Parms.u64Handle.type = VMMDevHGCMParmType_64bit; + pReq->Parms.u64Handle.u.value64 = hHostDir; + + pReq->Parms.f32Flags.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32Flags.u.value32 = fFlags; + + pReq->Parms.cb32Buffer.type = VMMDevHGCMParmType_32bit; + pReq->Parms.cb32Buffer.u.value32 = cbBuffer; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + { + pReq->Parms.pStrFilter.type = VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pStrFilter.u.PageList.offset = RT_UOFFSETOF(VBOXSFLISTDIRREQ, StrPgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->StrPgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + pReq->StrPgLst.cPages = 1; + if (pFilter) + { + pReq->Parms.pStrFilter.u.PageList.size = SHFLSTRING_HEADER_SIZE + pFilter->u16Size; + uint32_t const offFirstPage = (uint32_t)PhysFilter & PAGE_OFFSET_MASK; + pReq->StrPgLst.offFirstPage = (uint16_t)offFirstPage; + pReq->StrPgLst.aPages[0] = PhysFilter - offFirstPage; + } + else + { + pReq->Parms.pStrFilter.u.PageList.size = 0; + pReq->StrPgLst.offFirstPage = 0; + pReq->StrPgLst.aPages[0] = NIL_RTGCPHYS64; + } + + pReq->Parms.pBuffer.type = VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pBuffer.u.PageList.offset = RT_UOFFSETOF(VBOXSFLISTDIRREQ, BufPgLst) - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pBuffer.u.PageList.size = cbBuffer; + pReq->BufPgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + pReq->BufPgLst.cPages = 1; + uint32_t const offFirstPage = (uint32_t)PhysBuffer & PAGE_OFFSET_MASK; + pReq->BufPgLst.offFirstPage = (uint16_t)offFirstPage; + pReq->BufPgLst.aPages[0] = PhysBuffer - offFirstPage; + } + else + { + pReq->Parms.pStrFilter.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrFilter.u.LinAddr.cb = pFilter ? SHFLSTRING_HEADER_SIZE + pFilter->u16Size : 0; + pReq->Parms.pStrFilter.u.LinAddr.uAddr = (uintptr_t)pFilter; + + pReq->Parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pBuffer.u.LinAddr.cb = cbBuffer; + pReq->Parms.pBuffer.u.LinAddr.uAddr = (uintptr_t)pBuffer; + } + + pReq->Parms.f32More.type = VMMDevHGCMParmType_32bit; + pReq->Parms.f32More.u.value32 = 0; + + pReq->Parms.c32Entries.type = VMMDevHGCMParmType_32bit; + pReq->Parms.c32Entries.u.value32 = 0; + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, sizeof(*pReq)); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_LIST request with separate string buffer and buffers for entries, + * both allocated on the physical heap. + */ +DECLINLINE(int) VbglR0SfHostReqListDir(SHFLROOT idRoot, VBOXSFLISTDIRREQ *pReq, uint64_t hHostDir, + PSHFLSTRING pFilter, uint32_t fFlags, PSHFLDIRINFO pBuffer, uint32_t cbBuffer) +{ + return VbglR0SfHostReqListDirContig2x(idRoot, + pReq, + hHostDir, + pFilter, + pFilter ? VbglR0PhysHeapGetPhysAddr(pFilter) : NIL_RTGCPHYS64, + fFlags, + pBuffer, + VbglR0PhysHeapGetPhysAddr(pBuffer), + cbBuffer); +} + + +/** Request structure for VbglR0SfHostReqReadLink. */ +typedef struct VBOXSFREADLINKREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmReadLink Parms; + HGCMPageListInfo PgLst; + SHFLSTRING StrPath; +} VBOXSFREADLINKREQ; + +/** + * SHFL_FN_READLINK request. + * + * @note Buffer contains UTF-8 characters on success, regardless of the + * UTF-8/UTF-16 setting of the connection. + */ +DECLINLINE(int) VbglR0SfHostReqReadLinkContig(SHFLROOT idRoot, void *pvBuffer, RTGCPHYS64 PhysBuffer, uint32_t cbBuffer, + VBOXSFREADLINKREQ *pReq) +{ + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? RT_UOFFSETOF(VBOXSFREADLINKREQ, StrPath.String) + pReq->StrPath.u16Size + : cbBuffer <= PAGE_SIZE - (PhysBuffer & PAGE_OFFSET_MASK) + || (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST) + ? RT_UOFFSETOF(VBOXSFREADLINKREQ, StrPath.String) + : RT_UOFFSETOF(VBOXSFREADLINKREQ, PgLst); + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_READLINK, SHFL_CPARMS_READLINK, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pStrPath.u.Embedded.cbData = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.Embedded.offData = RT_UOFFSETOF(VBOXSFREADLINKREQ, StrPath) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pStrPath.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + } + else + { + pReq->Parms.pStrPath.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrPath.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pReq->StrPath.u16Size; + pReq->Parms.pStrPath.u.LinAddr.uAddr = (uintptr_t)&pReq->StrPath; + } + + if ( cbBuffer <= PAGE_SIZE - (PhysBuffer & PAGE_OFFSET_MASK) + || (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST)) + { + pReq->Parms.pBuffer.type = cbBuffer <= PAGE_SIZE - (PhysBuffer & PAGE_OFFSET_MASK) + ? VMMDevHGCMParmType_PageList + : VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pBuffer.u.PageList.size = cbBuffer; + pReq->Parms.pBuffer.u.PageList.offset = RT_UOFFSETOF(VBOXSFREADLINKREQ, PgLst) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLst.flags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + pReq->PgLst.offFirstPage = (uint16_t)PhysBuffer & (uint16_t)(PAGE_OFFSET_MASK); + pReq->PgLst.aPages[0] = PhysBuffer & ~(RTGCPHYS64)PAGE_OFFSET_MASK; + pReq->PgLst.cPages = 1; + } + else + { + pReq->Parms.pBuffer.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pBuffer.u.LinAddr.cb = cbBuffer; + pReq->Parms.pBuffer.u.LinAddr.uAddr = (uintptr_t)pvBuffer; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** + * SHFL_FN_READLINK request, simplified version. + * + * + * @note Buffer contains UTF-8 characters on success, regardless of the + * UTF-8/UTF-16 setting of the connection. + */ +DECLINLINE(int) VbglR0SfHostReqReadLinkContigSimple(SHFLROOT idRoot, const char *pszPath, size_t cchPath, void *pvBuf, + RTGCPHYS64 PhysBuffer, uint32_t cbBuffer) +{ + if (cchPath < _64K - 1) + { + VBOXSFREADLINKREQ *pReq = (VBOXSFREADLINKREQ *)VbglR0PhysHeapAlloc(RT_UOFFSETOF(VBOXSFREADLINKREQ, StrPath.String) + + SHFLSTRING_HEADER_SIZE + (uint32_t)cchPath); + if (pReq) + { + pReq->StrPath.u16Length = (uint16_t)cchPath; + pReq->StrPath.u16Size = (uint16_t)cchPath + 1; + memcpy(pReq->StrPath.String.ach, pszPath, cchPath); + pReq->StrPath.String.ach[cchPath] = '\0'; + + { + int vrc = VbglR0SfHostReqReadLinkContig(idRoot, pvBuf, PhysBuffer, cbBuffer, pReq); + VbglR0PhysHeapFree(pReq); + return vrc; + } + } + return VERR_NO_MEMORY; + } + return VERR_FILENAME_TOO_LONG; +} + + +/** Request structure for VbglR0SfHostReqCreateSymlink. */ +typedef struct VBOXSFCREATESYMLINKREQ +{ + VBGLIOCIDCHGCMFASTCALL Hdr; + VMMDevHGCMCall Call; + VBoxSFParmCreateSymlink Parms; + HGCMPageListInfo PgLstTarget; + SHFLFSOBJINFO ObjInfo; + SHFLSTRING StrSymlinkPath; +} VBOXSFCREATESYMLINKREQ; + +/** + * SHFL_FN_SYMLINK request. + * + * Caller fills in the symlink string and supplies a physical contiguous + * target string + */ +DECLINLINE(int) VbglR0SfHostReqCreateSymlinkContig(SHFLROOT idRoot, PCSHFLSTRING pStrTarget, RTGCPHYS64 PhysTarget, + VBOXSFCREATESYMLINKREQ *pReq) +{ + uint32_t const cbTarget = SHFLSTRING_HEADER_SIZE + pStrTarget->u16Size; + uint32_t const cbReq = g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS + ? RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, StrSymlinkPath.String) + pReq->StrSymlinkPath.u16Size + : RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, ObjInfo) /*simplified*/; + VBGLIOCIDCHGCMFASTCALL_INIT(&pReq->Hdr, VbglR0PhysHeapGetPhysAddr(pReq), &pReq->Call, g_SfClient.idClient, + SHFL_FN_SYMLINK, SHFL_CPARMS_SYMLINK, cbReq); + + pReq->Parms.id32Root.type = VMMDevHGCMParmType_32bit; + pReq->Parms.id32Root.u.value32 = idRoot; + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pStrSymlink.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pStrSymlink.u.Embedded.cbData = SHFLSTRING_HEADER_SIZE + pReq->StrSymlinkPath.u16Size; + pReq->Parms.pStrSymlink.u.Embedded.offData = RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, StrSymlinkPath) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pStrSymlink.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + } + else + { + pReq->Parms.pStrSymlink.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrSymlink.u.LinAddr.cb = SHFLSTRING_HEADER_SIZE + pReq->StrSymlinkPath.u16Size; + pReq->Parms.pStrSymlink.u.LinAddr.uAddr = (uintptr_t)&pReq->StrSymlinkPath; + } + + if ( cbTarget <= PAGE_SIZE - (PhysTarget & PAGE_OFFSET_MASK) + || (g_fHostFeatures & VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST)) + { + pReq->Parms.pStrTarget.type = cbTarget <= PAGE_SIZE - (PhysTarget & PAGE_OFFSET_MASK) + ? VMMDevHGCMParmType_PageList + : VMMDevHGCMParmType_ContiguousPageList; + pReq->Parms.pStrTarget.u.PageList.size = cbTarget; + pReq->Parms.pStrTarget.u.PageList.offset = RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, PgLstTarget) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->PgLstTarget.flags = VBOX_HGCM_F_PARM_DIRECTION_TO_HOST; + pReq->PgLstTarget.offFirstPage = (uint16_t)PhysTarget & (uint16_t)(PAGE_OFFSET_MASK); + pReq->PgLstTarget.aPages[0] = PhysTarget & ~(RTGCPHYS64)PAGE_OFFSET_MASK; + pReq->PgLstTarget.cPages = 1; + } + else + { + pReq->Parms.pStrTarget.type = VMMDevHGCMParmType_LinAddr_In; + pReq->Parms.pStrTarget.u.LinAddr.cb = cbTarget; + pReq->Parms.pStrTarget.u.LinAddr.uAddr = (uintptr_t)pStrTarget; + } + + if (g_fHostFeatures & VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS) + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_Embedded; + pReq->Parms.pInfo.u.Embedded.cbData = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.Embedded.offData = RT_UOFFSETOF(VBOXSFCREATESYMLINKREQ, ObjInfo) + - sizeof(VBGLIOCIDCHGCMFASTCALL); + pReq->Parms.pInfo.u.Embedded.fFlags = VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST; + } + else + { + pReq->Parms.pInfo.type = VMMDevHGCMParmType_LinAddr_Out; + pReq->Parms.pInfo.u.LinAddr.cb = sizeof(pReq->ObjInfo); + pReq->Parms.pInfo.u.LinAddr.uAddr = (uintptr_t)&pReq->ObjInfo; + } + + int vrc = VbglR0HGCMFastCall(g_SfClient.handle, &pReq->Hdr, cbReq); + if (RT_SUCCESS(vrc)) + vrc = pReq->Call.header.result; + return vrc; +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_VBoxGuestLibSharedFoldersInline_h */ + diff --git a/include/VBox/VBoxGuestMangling.h b/include/VBox/VBoxGuestMangling.h new file mode 100644 index 00000000..2049051d --- /dev/null +++ b/include/VBox/VBoxGuestMangling.h @@ -0,0 +1,49 @@ +/** @file + * VBoxGuest - Mangling of IPRT symbols for guest drivers. + * + * This is included via a compiler directive on platforms with a global kernel + * symbol name space (i.e. not Windows, OS/2 and Mac OS X (?)). + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxGuestMangling_h +#define VBOX_INCLUDED_VBoxGuestMangling_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#define RT_MANGLER(symbol) VBoxGuest_##symbol +#include + +#endif /* !VBOX_INCLUDED_VBoxGuestMangling_h */ + diff --git a/include/VBox/VBoxKeyboard.h b/include/VBox/VBoxKeyboard.h new file mode 100644 index 00000000..c39bf522 --- /dev/null +++ b/include/VBox/VBoxKeyboard.h @@ -0,0 +1,56 @@ +/** @file + * Frontends/Common - X11 keyboard driver interface. + */ + +/* + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* + * Oracle LGPL Disclaimer: For the avoidance of doubt, except that if any license choice + * other than GPL or LGPL is available it will apply instead, Oracle elects to use only + * the Lesser General Public License version 2.1 (LGPLv2) at this time for any software where + * a choice of LGPL license versions is made available with the language indicating + * that LGPLv2 or any later version may be used, or where a choice of which version + * of the LGPL is applied is otherwise unspecified. + */ + +#ifndef VBOX_INCLUDED_VBoxKeyboard_h +#define VBOX_INCLUDED_VBoxKeyboard_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/* Exported definitions */ +#undef CCALL +#ifdef __cplusplus +# define CCALL "C" +#else +# define CCALL +#endif +#ifdef VBOX_HAVE_VISIBILITY_HIDDEN +extern CCALL __attribute__((visibility("default"))) unsigned *X11DRV_getKeyc2scan(void); +extern CCALL __attribute__((visibility("default"))) unsigned X11DRV_InitKeyboard(Display *dpy, unsigned *byLayoutOK, unsigned *byTypeOK, unsigned *byXkbOK, int (*remapScancodes)[2]); +extern CCALL __attribute__((visibility("default"))) unsigned X11DRV_KeyEvent(Display *dpy, KeyCode code); +#else +extern CCALL unsigned *X11DRV_getKeyc2scan(void); +extern CCALL unsigned X11DRV_InitKeyboard(Display *dpy, unsigned *byLayoutOK, unsigned *byTypeOK, unsigned *byXkbOK, int (*remapScancodes)[2]); +extern CCALL unsigned X11DRV_KeyEvent(Display *dpy, KeyCode code); +#endif + +#endif /* !VBOX_INCLUDED_VBoxKeyboard_h */ + diff --git a/include/VBox/VBoxNetCfg-win.h b/include/VBox/VBoxNetCfg-win.h new file mode 100644 index 00000000..8a1dc671 --- /dev/null +++ b/include/VBox/VBoxNetCfg-win.h @@ -0,0 +1,147 @@ +/* $Id: VBoxNetCfg-win.h $ */ +/** @file + * Network Configuration API for Windows platforms. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxNetCfg_win_h +#define VBOX_INCLUDED_VBoxNetCfg_win_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* + * Defining VBOXNETCFG_DELAYEDRENAME postpones renaming of host-only adapter + * connection during adapter creation after it has been assigned with an + * IP address. This hopefully prevents collisions that may happen when we + * attempt to rename a connection too early, while its configuration is + * still being 'committed' by the network setup engine. + */ +#define VBOXNETCFG_DELAYEDRENAME + +#include +#include +#include +#include +#include +#include + +/** @defgroup grp_vboxnetcfgwin The Windows Network Configration Library + * @{ */ + +/** @def VBOXNETCFGWIN_DECL + * The usual declaration wrapper. + */ +#if 0 +/* enable this in case we include this in a dll*/ +# ifdef IN_VBOXDDU +# define VBOXNETCFGWIN_DECL(a_Type) DECLEXPORT(a_Type) +# else +# define VBOXNETCFGWIN_DECL(a_Type) DECLIMPORT(a_Type) +# endif +#else +/*enable this in case we include this in a static lib*/ +# define VBOXNETCFGWIN_DECL(a_Type) a_Type VBOXCALL +#endif + +RT_C_DECLS_BEGIN + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinQueryINetCfg(OUT INetCfg **ppNetCfg, + IN BOOL fGetWriteLock, + IN LPCWSTR pszwClientDescription, + IN DWORD cmsTimeout, + OUT LPWSTR *ppszwClientDescription); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinReleaseINetCfg(IN INetCfg *pNetCfg, IN BOOL fHasWriteLock); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetComponentByGuid(IN INetCfg *pNc, IN const GUID *pguidClass, + IN const GUID * pComponentGuid, OUT INetCfgComponent **ppncc); + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltInstall(IN INetCfg *pNc, IN LPCWSTR const *pwszInfFullPaths, IN UINT cInfFullPaths); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetFltUninstall(IN INetCfg *pNc); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfInstall(IN INetCfg *pNc, IN LPCWSTR const pwszInfFullPath); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetLwfUninstall(IN INetCfg *pNc); + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetAdpUninstall(IN INetCfg *pNc, IN LPCWSTR pwszId); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinNetAdpInstall(IN INetCfg *pNc,IN LPCWSTR const pwszInfFullPath); + +#ifndef VBOXNETCFG_DELAYEDRENAME +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pwszInfPath, IN bool fIsInfPathFile, + IN BSTR pBstrDesiredName, + OUT GUID *pGuid, OUT BSTR *pBstrName, OUT BSTR *pErrMsg); +#else /* VBOXNETCFG_DELAYEDRENAME */ +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinCreateHostOnlyNetworkInterface(IN LPCWSTR pwszInfPath, IN bool fIsInfPathFile, + IN BSTR pBstrDesiredName, + OUT GUID *pGuid, OUT BSTR *pBstrId, OUT BSTR *pErrMsg); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameHostOnlyConnection(IN const GUID *pGuid, IN LPCWSTR pszId, OUT BSTR *pDevName); +#endif /* VBOXNETCFG_DELAYEDRENAME */ +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinUpdateHostOnlyNetworkInterface(LPCWSTR pcsxwInf, BOOL *pfRebootRequired, LPCWSTR pcsxwId); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveHostOnlyNetworkInterface(IN const GUID *pGUID, OUT BSTR *pErrMsg); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRemoveAllNetDevicesOfId(IN LPCWSTR lpszPnPId); + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostonlyConnectionName(IN PCWSTR pwszDevName, OUT WCHAR *pwszBuf, + IN ULONG cwcBuf, OUT PULONG pcwcNeeded); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinRenameConnection(IN LPWSTR pwszGuid, IN PCWSTR pwszNewName); + +typedef enum VBOXNECTFGWINPROPCHANGE_TYPE_T +{ + VBOXNECTFGWINPROPCHANGE_TYPE_UNDEFINED = 0, + VBOXNECTFGWINPROPCHANGE_TYPE_DISABLE, + VBOXNECTFGWINPROPCHANGE_TYPE_ENABLE +} VBOXNECTFGWINPROPCHANGE_TYPE_T; + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinPropChangeAllNetDevicesOfId(IN LPCWSTR lpszPnPId, VBOXNECTFGWINPROPCHANGE_TYPE_T enmPcType); + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGenHostOnlyNetworkNetworkIp(OUT PULONG pNetIp, OUT PULONG pNetMask); + +typedef struct ADAPTER_SETTINGS +{ + ULONG ip; + ULONG mask; + BOOL bDhcp; +} ADAPTER_SETTINGS, *PADAPTER_SETTINGS; /**< I'm not prefixed */ + +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableStaticIpConfig(IN const GUID *pGuid, IN ULONG ip, IN ULONG mask); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinGetAdapterSettings(IN const GUID * pGuid, OUT PADAPTER_SETTINGS pSettings); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinEnableDynamicIpConfig(IN const GUID *pGuid); +VBOXNETCFGWIN_DECL(HRESULT) VBoxNetCfgWinDhcpRediscover(IN const GUID *pGuid); + + +typedef DECLCALLBACKTYPE(void, FNVBOXNETCFGLOGGER,(const char *pszString)); +typedef FNVBOXNETCFGLOGGER *PFNVBOXNETCFGLOGGER; +VBOXNETCFGWIN_DECL(void) VBoxNetCfgWinSetLogging(IN PFNVBOXNETCFGLOGGER pfnLogger); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_VBoxNetCfg_win_h */ + diff --git a/include/VBox/VBoxNetCmn-win.h b/include/VBox/VBoxNetCmn-win.h new file mode 100644 index 00000000..e1e0e643 --- /dev/null +++ b/include/VBox/VBoxNetCmn-win.h @@ -0,0 +1,163 @@ +/* $Id: VBoxNetCmn-win.h $ */ +/** @file + * VBoxNetCmn-win.h - NDIS6 Networking Driver Common Definitions, Windows-specific code. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxNetCmn_win_h +#define VBOX_INCLUDED_VBoxNetCmn_win_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include /* for LOG_ENABLED */ + + +DECLHIDDEN(void) vboxNetCmnWinDumpOidRequest(const char *pcszFunction, PNDIS_OID_REQUEST pRequest) +{ +# ifdef LOG_ENABLED + const char *pszType; + const char *pszOid = "unknown"; + + switch (pRequest->RequestType) + { + case NdisRequestSetInformation: pszType = "set"; break; + case NdisRequestMethod: pszType = "method"; break; + case NdisRequestQueryInformation: pszType = "query info"; break; + case NdisRequestQueryStatistics: pszType = "query stats"; break; + default: pszType = "unknown"; + } + switch (pRequest->DATA.SET_INFORMATION.Oid) + { + case OID_GEN_MAX_LINK_SPEED: pszOid = "OID_GEN_MAX_LINK_SPEED"; break; + case OID_GEN_LINK_STATE: pszOid = "OID_GEN_LINK_STATE"; break; + case OID_GEN_LINK_PARAMETERS: pszOid = "OID_GEN_LINK_PARAMETERS"; break; + case OID_GEN_MINIPORT_RESTART_ATTRIBUTES: pszOid = "OID_GEN_MINIPORT_RESTART_ATTRIBUTES"; break; + case OID_GEN_ENUMERATE_PORTS: pszOid = "OID_GEN_ENUMERATE_PORTS"; break; + case OID_GEN_PORT_STATE: pszOid = "OID_GEN_PORT_STATE"; break; + case OID_GEN_PORT_AUTHENTICATION_PARAMETERS: pszOid = "OID_GEN_PORT_AUTHENTICATION_PARAMETERS"; break; + case OID_GEN_INTERRUPT_MODERATION: pszOid = "OID_GEN_INTERRUPT_MODERATION"; break; + case OID_GEN_PHYSICAL_MEDIUM_EX: pszOid = "OID_GEN_PHYSICAL_MEDIUM_EX"; break; + case OID_GEN_SUPPORTED_LIST: pszOid = "OID_GEN_SUPPORTED_LIST"; break; + case OID_GEN_HARDWARE_STATUS: pszOid = "OID_GEN_HARDWARE_STATUS"; break; + case OID_GEN_MEDIA_SUPPORTED: pszOid = "OID_GEN_MEDIA_SUPPORTED"; break; + case OID_GEN_MEDIA_IN_USE: pszOid = "OID_GEN_MEDIA_IN_USE"; break; + case OID_GEN_MAXIMUM_LOOKAHEAD: pszOid = "OID_GEN_MAXIMUM_LOOKAHEAD"; break; + case OID_GEN_MAXIMUM_FRAME_SIZE: pszOid = "OID_GEN_MAXIMUM_FRAME_SIZE"; break; + case OID_GEN_LINK_SPEED: pszOid = "OID_GEN_LINK_SPEED"; break; + case OID_GEN_TRANSMIT_BUFFER_SPACE: pszOid = "OID_GEN_TRANSMIT_BUFFER_SPACE"; break; + case OID_GEN_RECEIVE_BUFFER_SPACE: pszOid = "OID_GEN_RECEIVE_BUFFER_SPACE"; break; + case OID_GEN_TRANSMIT_BLOCK_SIZE: pszOid = "OID_GEN_TRANSMIT_BLOCK_SIZE"; break; + case OID_GEN_RECEIVE_BLOCK_SIZE: pszOid = "OID_GEN_RECEIVE_BLOCK_SIZE"; break; + case OID_GEN_VENDOR_ID: pszOid = "OID_GEN_VENDOR_ID"; break; + case OID_GEN_VENDOR_DESCRIPTION: pszOid = "OID_GEN_VENDOR_DESCRIPTION"; break; + case OID_GEN_VENDOR_DRIVER_VERSION: pszOid = "OID_GEN_VENDOR_DRIVER_VERSION"; break; + case OID_GEN_CURRENT_PACKET_FILTER: pszOid = "OID_GEN_CURRENT_PACKET_FILTER"; break; + case OID_GEN_CURRENT_LOOKAHEAD: pszOid = "OID_GEN_CURRENT_LOOKAHEAD"; break; + case OID_GEN_DRIVER_VERSION: pszOid = "OID_GEN_DRIVER_VERSION"; break; + case OID_GEN_MAXIMUM_TOTAL_SIZE: pszOid = "OID_GEN_MAXIMUM_TOTAL_SIZE"; break; + case OID_GEN_PROTOCOL_OPTIONS: pszOid = "OID_GEN_PROTOCOL_OPTIONS"; break; + case OID_GEN_MAC_OPTIONS: pszOid = "OID_GEN_MAC_OPTIONS"; break; + case OID_GEN_MEDIA_CONNECT_STATUS: pszOid = "OID_GEN_MEDIA_CONNECT_STATUS"; break; + case OID_GEN_MAXIMUM_SEND_PACKETS: pszOid = "OID_GEN_MAXIMUM_SEND_PACKETS"; break; + case OID_GEN_SUPPORTED_GUIDS: pszOid = "OID_GEN_SUPPORTED_GUIDS"; break; + case OID_GEN_NETWORK_LAYER_ADDRESSES: pszOid = "OID_GEN_NETWORK_LAYER_ADDRESSES"; break; + case OID_GEN_TRANSPORT_HEADER_OFFSET: pszOid = "OID_GEN_TRANSPORT_HEADER_OFFSET"; break; + case OID_GEN_PHYSICAL_MEDIUM: pszOid = "OID_GEN_PHYSICAL_MEDIUM"; break; + case OID_GEN_MACHINE_NAME: pszOid = "OID_GEN_MACHINE_NAME"; break; + case OID_GEN_VLAN_ID: pszOid = "OID_GEN_VLAN_ID"; break; + case OID_GEN_RNDIS_CONFIG_PARAMETER: pszOid = "OID_GEN_RNDIS_CONFIG_PARAMETER"; break; + case OID_GEN_NDIS_RESERVED_1: pszOid = "OID_GEN_NDIS_RESERVED_1"; break; + case OID_GEN_NDIS_RESERVED_2: pszOid = "OID_GEN_NDIS_RESERVED_2"; break; + case OID_GEN_NDIS_RESERVED_5: pszOid = "OID_GEN_NDIS_RESERVED_5"; break; + case OID_GEN_MEDIA_CAPABILITIES: pszOid = "OID_GEN_MEDIA_CAPABILITIES"; break; + case OID_GEN_DEVICE_PROFILE: pszOid = "OID_GEN_DEVICE_PROFILE"; break; + case OID_GEN_FRIENDLY_NAME: pszOid = "OID_GEN_FRIENDLY_NAME"; break; + case OID_802_3_ADD_MULTICAST_ADDRESS: pszOid = "OID_802_3_ADD_MULTICAST_ADDRESS"; break; + case OID_802_3_DELETE_MULTICAST_ADDRESS: pszOid = "OID_802_3_DELETE_MULTICAST_ADDRESS"; break; + case OID_802_3_PERMANENT_ADDRESS: pszOid = "OID_802_3_PERMANENT_ADDRESS"; break; + case OID_802_3_CURRENT_ADDRESS: pszOid = "OID_802_3_CURRENT_ADDRESS"; break; + case OID_802_3_MULTICAST_LIST: pszOid = "OID_802_3_MULTICAST_LIST"; break; + case OID_802_3_MAXIMUM_LIST_SIZE: pszOid = "OID_802_3_MAXIMUM_LIST_SIZE"; break; + case OID_802_3_MAC_OPTIONS: pszOid = "OID_802_3_MAC_OPTIONS"; break; + case OID_TCP_TASK_OFFLOAD: pszOid = "OID_TCP_TASK_OFFLOAD"; break; + case OID_TCP_TASK_IPSEC_ADD_SA: pszOid = "OID_TCP_TASK_IPSEC_ADD_SA"; break; + case OID_TCP_TASK_IPSEC_ADD_UDPESP_SA: pszOid = "OID_TCP_TASK_IPSEC_ADD_UDPESP_SA"; break; + case OID_TCP_TASK_IPSEC_DELETE_SA: pszOid = "OID_TCP_TASK_IPSEC_DELETE_SA"; break; + case OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA: pszOid = "OID_TCP_TASK_IPSEC_DELETE_UDPESP_SA"; break; + + case OID_GEN_STATISTICS: pszOid = "OID_GEN_STATISTICS"; break; + case OID_GEN_BYTES_RCV: pszOid = "OID_GEN_BYTES_RCV"; break; + case OID_GEN_BYTES_XMIT: pszOid = "OID_GEN_BYTES_XMIT"; break; + case OID_GEN_RCV_DISCARDS: pszOid = "OID_GEN_RCV_DISCARDS"; break; + case OID_GEN_XMIT_DISCARDS: pszOid = "OID_GEN_XMIT_DISCARDS"; break; + case OID_GEN_XMIT_OK: pszOid = "OID_GEN_XMIT_OK"; break; + case OID_GEN_RCV_OK: pszOid = "OID_GEN_RCV_OK"; break; + case OID_GEN_XMIT_ERROR: pszOid = "OID_GEN_XMIT_ERROR"; break; + case OID_GEN_RCV_ERROR: pszOid = "OID_GEN_RCV_ERROR"; break; + case OID_GEN_RCV_NO_BUFFER: pszOid = "OID_GEN_RCV_NO_BUFFER"; break; + case OID_GEN_DIRECTED_BYTES_XMIT: pszOid = "OID_GEN_DIRECTED_BYTES_XMIT"; break; + case OID_GEN_DIRECTED_FRAMES_XMIT: pszOid = "OID_GEN_DIRECTED_FRAMES_XMIT"; break; + case OID_GEN_MULTICAST_BYTES_XMIT: pszOid = "OID_GEN_MULTICAST_BYTES_XMIT"; break; + case OID_GEN_MULTICAST_FRAMES_XMIT: pszOid = "OID_GEN_MULTICAST_FRAMES_XMIT"; break; + case OID_GEN_BROADCAST_BYTES_XMIT: pszOid = "OID_GEN_BROADCAST_BYTES_XMIT"; break; + case OID_GEN_BROADCAST_FRAMES_XMIT: pszOid = "OID_GEN_BROADCAST_FRAMES_XMIT"; break; + case OID_GEN_DIRECTED_BYTES_RCV: pszOid = "OID_GEN_DIRECTED_BYTES_RCV"; break; + case OID_GEN_DIRECTED_FRAMES_RCV: pszOid = "OID_GEN_DIRECTED_FRAMES_RCV"; break; + case OID_GEN_MULTICAST_BYTES_RCV: pszOid = "OID_GEN_MULTICAST_BYTES_RCV"; break; + case OID_GEN_MULTICAST_FRAMES_RCV: pszOid = "OID_GEN_MULTICAST_FRAMES_RCV"; break; + case OID_GEN_BROADCAST_BYTES_RCV: pszOid = "OID_GEN_BROADCAST_BYTES_RCV"; break; + case OID_GEN_BROADCAST_FRAMES_RCV: pszOid = "OID_GEN_BROADCAST_FRAMES_RCV"; break; + case OID_GEN_RCV_CRC_ERROR: pszOid = "OID_GEN_RCV_CRC_ERROR"; break; + case OID_GEN_TRANSMIT_QUEUE_LENGTH: pszOid = "OID_GEN_TRANSMIT_QUEUE_LENGTH"; break; + case OID_GEN_INIT_TIME_MS: pszOid = "OID_GEN_INIT_TIME_MS"; break; + case OID_GEN_RESET_COUNTS: pszOid = "OID_GEN_RESET_COUNTS"; break; + case OID_GEN_MEDIA_SENSE_COUNTS: pszOid = "OID_GEN_MEDIA_SENSE_COUNTS"; break; + + case OID_PNP_CAPABILITIES: pszOid = "OID_PNP_CAPABILITIES"; break; + case OID_PNP_SET_POWER: pszOid = "OID_PNP_SET_POWER"; break; + case OID_PNP_QUERY_POWER: pszOid = "OID_PNP_QUERY_POWER"; break; + case OID_PNP_ADD_WAKE_UP_PATTERN: pszOid = "OID_PNP_ADD_WAKE_UP_PATTERN"; break; + case OID_PNP_REMOVE_WAKE_UP_PATTERN: pszOid = "OID_PNP_REMOVE_WAKE_UP_PATTERN"; break; + case OID_PNP_WAKE_UP_PATTERN_LIST: pszOid = "OID_PNP_WAKE_UP_PATTERN_LIST"; break; + case OID_PNP_ENABLE_WAKE_UP: pszOid = "OID_PNP_ENABLE_WAKE_UP"; break; + case OID_PNP_WAKE_UP_OK: pszOid = "OID_PNP_WAKE_UP_OK"; break; + case OID_PNP_WAKE_UP_ERROR: pszOid = "OID_PNP_WAKE_UP_ERROR"; break; + } + Log(("%s: %s(0x%x) %s(0x%x)\n", pcszFunction, pszType, pRequest->RequestType, pszOid, pRequest->DATA.SET_INFORMATION.Oid)); +# else + RT_NOREF2(pcszFunction, pRequest); +# endif +} + +#endif /* !VBOX_INCLUDED_VBoxNetCmn_win_h */ diff --git a/include/VBox/VBoxOGL.h b/include/VBox/VBoxOGL.h new file mode 100644 index 00000000..df7e27dd --- /dev/null +++ b/include/VBox/VBoxOGL.h @@ -0,0 +1,70 @@ +/* $Id: VBoxOGL.h $ */ +/** @file + * VBox 3D Support API + */ +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxOGL_h +#define VBOX_INCLUDED_VBoxOGL_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/* GUI and VBox OpenGL code require scaling factor value to be stored in container + * of type of 'double'. Communication between them is done via Main. In the same time, + * currently, Main does not like type of 'double' to be used for an interface method parameter. + * An integer type should be used instead. This value is used in order to specify scaling factor in type + * of 'integer' units. It is assumed that GUI feeds Main with its internal scaling factor value + * (which is originally of type of 'double') multiplied by this constant and converted resulting + * value to type of 'uint32_t'. Then Main provides this data to OpenGL HGCM thread. Finally, VBox OpenGL + * code divides received scalar by this constant and converts result to type of 'double'. + * This constant can be increased (multiplied by 10^n) in order to get better precision + * for scaling factor manipulations. */ +#define VBOX_OGL_SCALE_FACTOR_MULTIPLIER 10000.0 + +/* 3D content scale factor range bounds. */ +#define VBOX_OGL_SCALE_FACTOR_MIN 0.01 +#define VBOX_OGL_SCALE_FACTOR_MAX 10.0 + +bool RTCALL VBoxOglIsOfflineRenderingAppropriate(void); +bool RTCALL VBoxOglIs3DAccelerationSupported(void); + +DECLEXPORT(int) VBoxOglSetScaleFactor(uint32_t idScreen, double dScaleFactorW, double dScaleFactorH); + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_VBoxOGL_h */ diff --git a/include/VBox/VBoxPktDmp.h b/include/VBox/VBoxPktDmp.h new file mode 100644 index 00000000..ea6e3303 --- /dev/null +++ b/include/VBox/VBoxPktDmp.h @@ -0,0 +1,186 @@ +/* $Id: VBoxPktDmp.h $ */ +/** @file + * VBoxPktDmp.h - Dump Ethernet frame into debug log. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxPktDmp_h +#define VBOX_INCLUDED_VBoxPktDmp_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#if defined(LOG_ENABLED) && !defined(VBOX_DEVICE_STRUCT_TESTCASE) +# include +#endif + + +DECLINLINE(const char *) vboxEthTypeStr(uint16_t uType) +{ + switch (uType) + { + case RTNET_ETHERTYPE_IPV4: return "IP"; + case RTNET_ETHERTYPE_IPV6: return "IPv6"; + case RTNET_ETHERTYPE_ARP: return "ARP"; + } + return "unknown"; +} + + +DECLINLINE(void) vboxEthPacketDump(const char *pcszInstance, const char *pcszText, const uint8_t *pcPacket, uint32_t cb) +{ +#if defined(LOG_ENABLED) && !defined(VBOX_DEVICE_STRUCT_TESTCASE) + AssertReturnVoid(cb >= 14); + + const uint8_t *pHdr = pcPacket; + const uint8_t *pEnd = pcPacket + cb; + AssertReturnVoid(pEnd - pHdr >= 14); + uint16_t uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+12)); + Log2(("%s: %s (%d bytes), %RTmac => %RTmac, EthType=%s(0x%x)\n", pcszInstance, + pcszText, cb, pHdr+6, pHdr, vboxEthTypeStr(uEthType), uEthType)); + pHdr += sizeof(RTNETETHERHDR); + if (uEthType == RTNET_ETHERTYPE_VLAN) + { + AssertReturnVoid(pEnd - pHdr >= 4); + uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+2)); + Log2((" + VLAN: id=%d EthType=%s(0x%x)\n", RT_N2H_U16(*(uint16_t*)(pHdr)) & 0xFFF, + vboxEthTypeStr(uEthType), uEthType)); + pHdr += 2 * sizeof(uint16_t); + } + uint8_t uProto = 0xFF; + switch (uEthType) + { + case RTNET_ETHERTYPE_IPV6: + AssertReturnVoid(pEnd - pHdr >= 40); + uProto = pHdr[6]; + Log2((" + IPv6: %RTnaipv6 => %RTnaipv6\n", pHdr+8, pHdr+24)); + pHdr += 40; + break; + case RTNET_ETHERTYPE_IPV4: + AssertReturnVoid(pEnd - pHdr >= 20); + uProto = pHdr[9]; + Log2((" + IP: %RTnaipv4 => %RTnaipv4\n", *(uint32_t*)(pHdr+12), *(uint32_t*)(pHdr+16))); + pHdr += (pHdr[0] & 0xF) * 4; + break; + case RTNET_ETHERTYPE_ARP: + AssertReturnVoid(pEnd - pHdr >= 28); + AssertReturnVoid(RT_N2H_U16(*(uint16_t*)(pHdr+2)) == RTNET_ETHERTYPE_IPV4); + switch (RT_N2H_U16(*(uint16_t*)(pHdr+6))) + { + case 1: /* ARP request */ + Log2((" + ARP-REQ: who-has %RTnaipv4 tell %RTnaipv4\n", + *(uint32_t*)(pHdr+24), *(uint32_t*)(pHdr+14))); + break; + case 2: /* ARP reply */ + Log2((" + ARP-RPL: %RTnaipv4 is-at %RTmac\n", + *(uint32_t*)(pHdr+14), pHdr+8)); + break; + default: + Log2((" + ARP: unknown op %d\n", RT_N2H_U16(*(uint16_t*)(pHdr+6)))); + break; + } + break; + /* There is no default case as uProto is initialized with 0xFF */ + } + while (uProto != 0xFF) + { + switch (uProto) + { + case 0: /* IPv6 Hop-by-Hop option*/ + case 60: /* IPv6 Destination option*/ + case 43: /* IPv6 Routing option */ + case 44: /* IPv6 Fragment option */ + Log2((" + IPv6 option (%d): \n", uProto)); + uProto = pHdr[0]; + pHdr += pHdr[1] * 8 + 8; /* Skip to the next extension/protocol */ + break; + case 51: /* IPv6 IPsec AH */ + Log2((" + IPv6 IPsec AH: \n")); + uProto = pHdr[0]; + pHdr += (pHdr[1] + 2) * 4; /* Skip to the next extension/protocol */ + break; + case 50: /* IPv6 IPsec ESP */ + /* Cannot decode IPsec, fall through */ + Log2((" + IPv6 IPsec ESP: \n")); + uProto = 0xFF; + break; + case 59: /* No Next Header */ + Log2((" + IPv6 No Next Header\n")); + uProto = 0xFF; + break; + case 58: /* IPv6-ICMP */ + switch (pHdr[0]) + { + case 1: Log2((" + IPv6-ICMP: destination unreachable, code %d\n", pHdr[1])); break; + case 128: Log2((" + IPv6-ICMP: echo request\n")); break; + case 129: Log2((" + IPv6-ICMP: echo reply\n")); break; + default: Log2((" + IPv6-ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break; + } + uProto = 0xFF; + break; + case 1: /* ICMP */ + switch (pHdr[0]) + { + case 0: Log2((" + ICMP: echo reply\n")); break; + case 8: Log2((" + ICMP: echo request\n")); break; + case 3: Log2((" + ICMP: destination unreachable, code %d\n", pHdr[1])); break; + default: Log2((" + ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break; + } + uProto = 0xFF; + break; + case 6: /* TCP */ + Log2((" + TCP: src=%d dst=%d seq=%x ack=%x\n", + RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2)), + RT_N2H_U32(*(uint32_t*)(pHdr+4)), RT_N2H_U32(*(uint32_t*)(pHdr+8)))); + uProto = 0xFF; + break; + case 17: /* UDP */ + Log2((" + UDP: src=%d dst=%d\n", + RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2)))); + uProto = 0xFF; + break; + default: + Log2((" + Unknown: proto=0x%x\n", uProto)); + uProto = 0xFF; + break; + } + } + Log3(("%.*Rhxd\n", cb, pcPacket)); +#else + RT_NOREF4(pcszInstance, pcszText, pcPacket, cb); +#endif +} + +#endif /* !VBOX_INCLUDED_VBoxPktDmp_h */ diff --git a/include/VBox/VBoxTpG.h b/include/VBox/VBoxTpG.h new file mode 100644 index 00000000..0105ee52 --- /dev/null +++ b/include/VBox/VBoxTpG.h @@ -0,0 +1,455 @@ +/* $Id: VBoxTpG.h $ */ +/** @file + * VBox Tracepoint Generator Structures. + */ + +/* + * Copyright (C) 2012-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VBoxTpG_h +#define VBOX_INCLUDED_VBoxTpG_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** + * 32-bit probe location. + */ +typedef struct VTGPROBELOC32 +{ + uint32_t uLine : 31; + uint32_t fEnabled : 1; + uint32_t idProbe; + uint32_t pszFunction; + uint32_t pProbe; +} VTGPROBELOC32; +AssertCompileSize(VTGPROBELOC32, 16); +/** Pointer to a 32-bit probe location. */ +typedef VTGPROBELOC32 *PVTGPROBELOC32; +/** Pointer to a const 32-bit probe location. */ +typedef VTGPROBELOC32 const *PCVTGPROBELOC32; + +/** + * 64-bit probe location. + */ +typedef struct VTGPROBELOC64 +{ + uint32_t uLine : 31; + uint32_t fEnabled : 1; + uint32_t idProbe; + uint64_t pszFunction; + uint64_t pProbe; + uint64_t uAlignment; +} VTGPROBELOC64; +AssertCompileSize(VTGPROBELOC64, 32); +/** Pointer to a 64-bit probe location. */ +typedef VTGPROBELOC64 *PVTGPROBELOC64; +/** Pointer to a const 64-bit probe location. */ +typedef VTGPROBELOC64 const *PCVTGPROBELOC64; + + +/** + * Probe location. + */ +typedef struct VTGPROBELOC +{ + uint32_t uLine : 31; + uint32_t fEnabled : 1; + uint32_t idProbe; + const char *pszFunction; + struct VTGDESCPROBE *pProbe; +#if ARCH_BITS == 64 + uintptr_t uAlignment; +#endif +} VTGPROBELOC; +AssertCompileSizeAlignment(VTGPROBELOC, 16); +/** Pointer to a probe location. */ +typedef VTGPROBELOC *PVTGPROBELOC; +/** Pointer to a const probe location. */ +typedef VTGPROBELOC const *PCVTGPROBELOC; + +/** @def VTG_OBJ_SECT + * The name of the section containing the other probe data provided by the + * assembly / object generated by VBoxTpG. */ +/** @def VTG_LOC_SECT + * The name of the section containing the VTGPROBELOC structures. This is + * filled by the probe macros, @see VTG_DECL_VTGPROBELOC. */ +/** @def VTG_DECL_VTGPROBELOC + * Declares a static variable, @a a_VarName, of type VTGPROBELOC in the section + * indicated by VTG_LOC_SECT. */ +#if defined(RT_OS_WINDOWS) +# define VTG_OBJ_SECT "VTGObj" +# define VTG_LOC_SECT "VTGPrLc.Data" +# ifdef _MSC_VER +# define VTG_DECL_VTGPROBELOC(a_VarName) \ + __declspec(allocate(VTG_LOC_SECT)) static VTGPROBELOC a_VarName +# elif defined(__GNUC__) || defined(DOXYGEN_RUNNING) +# define VTG_DECL_VTGPROBELOC(a_VarName) \ + static VTGPROBELOC __attribute__((section(VTG_LOC_SECT))) a_VarName +# else +# error "Unsupported Windows compiler!" +# endif + +#elif defined(RT_OS_DARWIN) +# define VTG_OBJ_SECT "__VTGObj" +# define VTG_LOC_SECT "__VTGPrLc" +# define VTG_LOC_SEG "__VTG" +# if defined(__GNUC__) || defined(DOXYGEN_RUNNING) +# define VTG_DECL_VTGPROBELOC(a_VarName) \ + static VTGPROBELOC __attribute__((section(VTG_LOC_SEG "," VTG_LOC_SECT ",regular")/*, aligned(16)*/)) a_VarName +# else +# error "Unsupported Darwin compiler!" +# endif + +#elif defined(RT_OS_OS2) /** @todo This doesn't actually work, but it makes the code compile. */ +# define VTG_OBJ_SECT "__DATA" +# define VTG_LOC_SECT "__VTGPrLc" +# define VTG_LOC_SET "__VTGPrLcSet" +# if defined(__GNUC__) || defined(DOXYGEN_RUNNING) +# define VTG_DECL_VTGPROBELOC(a_VarName) \ + static VTGPROBELOC a_VarName; \ + __asm__ (".stabs \"__VTGPrLcSet\", 23, 0, 0, _" #a_VarName ); + +# else +# error "Unsupported Darwin compiler!" +# endif + +#else /* Assume the rest uses ELF. */ +# define VTG_OBJ_SECT ".VTGObj" +# define VTG_LOC_SECT ".VTGPrLc" +# if defined(__GNUC__) || defined(DOXYGEN_RUNNING) +# define VTG_DECL_VTGPROBELOC(a_VarName) \ + static VTGPROBELOC __attribute__((section(VTG_LOC_SECT))) a_VarName +# else +# error "Unsupported compiler!" +# endif +#endif + +/** VTG string table offset. */ +typedef uint32_t VTGSTROFF; + + +/** @name VTG type flags + * @{ */ +/** Masking out the fixed size if given. */ +#define VTG_TYPE_SIZE_MASK UINT32_C(0x000000ff) +/** Indicates that VTG_TYPE_SIZE_MASK can be applied, UNSIGNED or SIGNED is + * usually set as well, so may PHYS. */ +#define VTG_TYPE_FIXED_SIZED RT_BIT_32(8) +/** It's a pointer type, the size is given by the context the probe fired in. */ +#define VTG_TYPE_POINTER RT_BIT_32(9) +/** A context specfic pointer or address, consult VTG_TYPE_CTX_XXX. */ +#define VTG_TYPE_CTX_POINTER RT_BIT_32(10) +/** The type has the same size as the host architecture. */ +#define VTG_TYPE_HC_ARCH_SIZED RT_BIT_32(11) +/** Const char pointer, requires casting in wrapper headers. */ +#define VTG_TYPE_CONST_CHAR_PTR RT_BIT_32(12) +/** The type applies to ring-3 context. */ +#define VTG_TYPE_CTX_R3 RT_BIT_32(24) +/** The type applies to ring-0 context. */ +#define VTG_TYPE_CTX_R0 RT_BIT_32(25) +/** The type applies to raw-mode context. */ +#define VTG_TYPE_CTX_RC RT_BIT_32(26) +/** The type applies to guest context. */ +#define VTG_TYPE_CTX_GST RT_BIT_32(27) +/** The type context mask. */ +#define VTG_TYPE_CTX_MASK UINT32_C(0x0f000000) +/** The type is automatically converted to a ring-0 pointer. */ +#define VTG_TYPE_AUTO_CONV_PTR RT_BIT_32(28) +/** The type is a physical address. */ +#define VTG_TYPE_PHYS RT_BIT_32(29) +/** The type is unsigned. */ +#define VTG_TYPE_UNSIGNED RT_BIT_32(30) +/** The type is signed. */ +#define VTG_TYPE_SIGNED RT_BIT_32(31) +/** Mask of valid bits (for simple validation). */ +#define VTG_TYPE_VALID_MASK UINT32_C(0xff001fff) +/** @} */ + +/** + * Checks if the VTG type flags indicates a large fixed size argument. + */ +#define VTG_TYPE_IS_LARGE(a_fType) \ + ( ((a_fType) & VTG_TYPE_SIZE_MASK) > 4 && ((a_fType) & VTG_TYPE_FIXED_SIZED) ) + + +/** + * VTG argument descriptor. + */ +typedef struct VTGDESCARG +{ + VTGSTROFF offType; + uint32_t fType; +} VTGDESCARG; +/** Pointer to an argument descriptor. */ +typedef VTGDESCARG *PVTGDESCARG; +/** Pointer to a const argument descriptor. */ +typedef VTGDESCARG const *PCVTGDESCARG; + + +/** + * VTG argument list descriptor. + */ +typedef struct VTGDESCARGLIST +{ + uint8_t cArgs; + uint8_t fHaveLargeArgs; + uint8_t abReserved[2]; + VTGDESCARG aArgs[1]; +} VTGDESCARGLIST; +/** Pointer to a VTG argument list descriptor. */ +typedef VTGDESCARGLIST *PVTGDESCARGLIST; +/** Pointer to a const VTG argument list descriptor. */ +typedef VTGDESCARGLIST const *PCVTGDESCARGLIST; + + +/** + * VTG probe descriptor. + */ +typedef struct VTGDESCPROBE +{ + VTGSTROFF offName; + uint32_t offArgList; + uint16_t idxEnabled; + uint16_t idxProvider; + /** The distance from this structure to the VTG object header. */ + int32_t offObjHdr; +} VTGDESCPROBE; +AssertCompileSize(VTGDESCPROBE, 16); +/** Pointer to a VTG probe descriptor. */ +typedef VTGDESCPROBE *PVTGDESCPROBE; +/** Pointer to a const VTG probe descriptor. */ +typedef VTGDESCPROBE const *PCVTGDESCPROBE; + + +/** + * Code/data stability. + */ +typedef enum kVTGStability +{ + kVTGStability_Invalid = 0, + kVTGStability_Internal, + kVTGStability_Private, + kVTGStability_Obsolete, + kVTGStability_External, + kVTGStability_Unstable, + kVTGStability_Evolving, + kVTGStability_Stable, + kVTGStability_Standard, + kVTGStability_End +} kVTGStability; + +/** + * Data dependency. + */ +typedef enum kVTGClass +{ + kVTGClass_Invalid = 0, + kVTGClass_Unknown, + kVTGClass_Cpu, + kVTGClass_Platform, + kVTGClass_Group, + kVTGClass_Isa, + kVTGClass_Common, + kVTGClass_End +} kVTGClass; + + +/** + * VTG attributes. + */ +typedef struct VTGDESCATTR +{ + uint8_t u8Code; + uint8_t u8Data; + uint8_t u8DataDep; +} VTGDESCATTR; +AssertCompileSize(VTGDESCATTR, 3); +/** Pointer to a const VTG attribute. */ +typedef VTGDESCATTR const *PCVTGDESCATTR; + + +/** + * VTG provider descriptor. + */ +typedef struct VTGDESCPROVIDER +{ + VTGSTROFF offName; + uint16_t iFirstProbe; + uint16_t cProbes; + VTGDESCATTR AttrSelf; + VTGDESCATTR AttrModules; + VTGDESCATTR AttrFunctions; + VTGDESCATTR AttrNames; + VTGDESCATTR AttrArguments; + uint8_t bReserved; + uint32_t volatile cProbesEnabled; + /** This increases every time a probe is enabled or disabled. + * Can be used in non-ring-3 context via PROVIDER_GET_SETTINGS_SEQ_NO() in + * order to only configure probes related stuff when actually required. */ + uint32_t volatile uSettingsSerialNo; +} VTGDESCPROVIDER; +AssertCompileSize(VTGDESCPROVIDER, 32); +/** Pointer to a VTG provider descriptor. */ +typedef VTGDESCPROVIDER *PVTGDESCPROVIDER; +/** Pointer to a const VTG provider descriptor. */ +typedef VTGDESCPROVIDER const *PCVTGDESCPROVIDER; + + +/** + * VTG data object header. + */ +typedef struct VTGOBJHDR +{ + /** Magic value (VTGOBJHDR_MAGIC). */ + char szMagic[24]; + /** The bitness of the structures. + * This only affects the probe location pointers and structures. */ + uint32_t cBits; + /** The size of the VTG object. This excludes the probe locations. */ + uint32_t cbObj; + + /** @name Area Descriptors + * @remarks The offsets are relative to the header. The members are + * ordered by ascending offset (maybe with the exception of the + * probe locations). No overlaps, though there might be zero + * filled gaps between them due to alignment. + * @{ */ + /* 32: */ + /** Offset of the string table (char) relative to this header. */ + uint32_t offStrTab; + /** The size of the string table, in bytes. */ + uint32_t cbStrTab; + /** Offset of the argument lists (VTGDESCARGLIST - variable size) relative + * to this header. */ + uint32_t offArgLists; + /** The size of the argument lists, in bytes. */ + uint32_t cbArgLists; + /* 48: */ + /** Offset of the probe array (VTGDESCPROBE) relative to this header. */ + uint32_t offProbes; + /** The size of the probe array, in bytes. */ + uint32_t cbProbes; + /** Offset of the provider array (VTGDESCPROVIDER) relative to this + * header. */ + uint32_t offProviders; + /** The size of the provider array, in bytes. */ + uint32_t cbProviders; + /* 64: */ + /** Offset of the probe-enabled array (uint32_t) relative to this + * header. */ + uint32_t offProbeEnabled; + /** The size of the probe-enabled array, in bytes. */ + uint32_t cbProbeEnabled; + /** Offset of the probe location array (VTGPROBELOC) relative to this + * header. + * @remarks This is filled in by the first VTG user using uProbeLocs. */ + int32_t offProbeLocs; + /** The size of the probe location array, in bytes. + * @remarks This is filled in by the first VTG user using uProbeLocs. */ + uint32_t cbProbeLocs; + /** @} */ + /* 80: */ + /** + * The probe location array is generated by C code and lives in a + * different section/subsection/segment than the rest of the data. + * + * The assembler cannot generate offsets across sections for most (if not + * all) object formats, so we have to store pointers here. The first user + * of the data will convert these two members into offset and size and fill + * in the offProbeLocs and cbProbeLocs members above. + * + * @remarks Converting these members to offset+size and reusing the members + * to store the converted values isn't possible because of + * raw-mode context modules having relocations associated with the + * fields. + */ + union + { + PVTGPROBELOC p; + uintptr_t uPtr; + uint32_t u32; + uint64_t u64; + } + /** Pointer to the probe location array. */ + uProbeLocs, + /** Pointer to the end of the probe location array. */ + uProbeLocsEnd; + /** UUID for making sharing ring-0 structures for the same ring-3 + * modules easier. */ + RTUUID Uuid; + /** Mac 10.6.x load workaround. + * The linker or/and load messes up the uProbeLocs and uProbeLocsEnd fields + * so that they will be link addresses instead of load addresses. To be + * able to work around it we store the start address of the __VTGObj section + * here and uses it to validate the probe location addresses. */ + uint64_t u64VtgObjSectionStart; + /** Reserved / alignment. */ + uint32_t au32Reserved1[2]; +} VTGOBJHDR; +AssertCompileSize(VTGOBJHDR, 128); +AssertCompileMemberAlignment(VTGOBJHDR, uProbeLocs, 8); +AssertCompileMemberAlignment(VTGOBJHDR, uProbeLocsEnd, 8); +/** Pointer to a VTG data object header. */ +typedef VTGOBJHDR *PVTGOBJHDR; +/** Pointer to a const VTG data object header. */ +typedef VTGOBJHDR const *PCVTGOBJHDR; + +/** The current VTGOBJHDR::szMagic value. */ +#define VTGOBJHDR_MAGIC "VTG Object Header v1.7\0" + +/** The name of the VTG data object header symbol in the object file. */ +extern VTGOBJHDR g_VTGObjHeader; + + +/** @name Macros for converting typical pointer arguments to ring-0 pointers. + * @{ */ +#ifdef IN_RING0 +# define VTG_VM_TO_R0(a_pVM) (a_pVM) +# define VTG_VMCPU_TO_R0(a_pVCpu) (a_pVCpu) +# define VTG_CPUMCTX_TO_R0(a_pVCpu, a_pCtx) (a_pCtx) +#else +# define VTG_VM_TO_R0(a_pVM) ((a_pVM) ? (a_pVM)->pVMR0ForCall : NIL_RTR0PTR) +# define VTG_VMCPU_TO_R0(a_pVCpu) ((a_pVCpu) ? (a_pVCpu)->pVCpuR0ForVtg : NIL_RTR0PTR) +# define VTG_CPUMCTX_TO_R0(a_pVCpu, a_pCtx) ((a_pVCpu) ? (a_pVCpu)->pVCpuR0ForVtg + ((uintptr_t)(a_pCtx) - (uintptr_t)(a_pVCpu)) : NIL_RTR0PTR) +#endif +/** @} */ + + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_VBoxTpG_h */ + diff --git a/include/VBox/VDEPlug.h b/include/VBox/VDEPlug.h new file mode 100644 index 00000000..4463d4fe --- /dev/null +++ b/include/VBox/VDEPlug.h @@ -0,0 +1,74 @@ +/** @file + * libvdeplug header and dynamic symbol loader. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VDEPlug_h +#define VBOX_INCLUDED_VDEPlug_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +#define LIBVDEPLUG_INTERFACE_VERSION 1 + +#define vde_open(vde_switch, descr, open_args) \ + vde_open_real((vde_switch), (descr), LIBVDEPLUG_INTERFACE_VERSION, (open_args)) + +/** Opaque connection type */ +struct vdeconn; +typedef struct vdeconn VDECONN; + +/** Structure to be passed to the open function describing the connection. + * All members can be left zero to use the default values. */ +struct vde_open_args +{ + /** The port of the switch to connect to. */ + int port; + /** The group to set ownership of the port socket to. */ + char *group; + /** The file mode to set the port socket to. */ + mode_t mode; +}; + +/* Declarations of the functions that we need from the library */ +#define VDEPLUG_GENERATE_HEADER + +#include + +#undef VDEPLUG_GENERATE_HEADER + +#endif /* !VBOX_INCLUDED_VDEPlug_h */ +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/include/VBox/VDEPlugSymDefs.h b/include/VBox/VDEPlugSymDefs.h new file mode 100644 index 00000000..beaa73cc --- /dev/null +++ b/include/VBox/VDEPlugSymDefs.h @@ -0,0 +1,73 @@ +/** @file + * Symbols from libvdeplug.so to be loaded at runtime for DrvVDE.cpp + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/** The file name of the DBus library */ +#define VBOX_LIB_VDE_PLUG_NAME "libvdeplug.so" +#define RT_RUNTIME_LOADER_LIB_NAME VBOX_LIB_VDE_PLUG_NAME + +/** The name of the loader function */ +#define RT_RUNTIME_LOADER_FUNCTION DrvVDELoadVDEPlug + +/** The following are the symbols which we need from the library. */ +#define RT_RUNTIME_LOADER_INSERT_SYMBOLS \ + RT_PROXY_STUB(vde_open_real, VDECONN *, \ + (const char *vde_switch, const char *descr, int interface_version, struct vde_open_args *open_args), \ + (vde_switch, descr, interface_version, open_args)) \ + RT_PROXY_STUB(vde_recv, size_t, \ + (VDECONN *conn, void *buf,size_t len, int flags), \ + (conn, buf, len, flags)) \ + RT_PROXY_STUB(vde_send, size_t, \ + (VDECONN *conn, const void *buf, size_t len, int flags), \ + (conn, buf, len, flags)) \ + RT_PROXY_STUB(vde_datafd, int, (VDECONN *conn), (conn)) \ + RT_PROXY_STUB(vde_close, void, (VDECONN *conn), (conn)) + +#ifdef VDEPLUG_GENERATE_HEADER +# define RT_RUNTIME_LOADER_GENERATE_HEADER +# define RT_RUNTIME_LOADER_GENERATE_DECLS +# include +# undef RT_RUNTIME_LOADER_GENERATE_HEADER +# undef RT_RUNTIME_LOADER_GENERATE_DECLS +#elif defined (VDEPLUG_GENERATE_BODY) +# define RT_RUNTIME_LOADER_GENERATE_BODY_STUBS +# include +# undef RT_RUNTIME_LOADER_GENERATE_BODY_STUBS +#else +# error This file should only be included to generate stubs for loading the libvdeplug library at runtime +#endif + +#undef RT_RUNTIME_LOADER_LIB_NAME +#undef RT_RUNTIME_LOADER_INSERT_SYMBOLS + diff --git a/include/VBox/VMMDev.h b/include/VBox/VMMDev.h new file mode 100644 index 00000000..69618cce --- /dev/null +++ b/include/VBox/VMMDev.h @@ -0,0 +1,2034 @@ +/** @file + * Virtual Device for Guest <-> VMM/Host communication (ADD,DEV). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VMMDev_h +#define VBOX_INCLUDED_VMMDev_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include /* for the PCI IDs. */ +#include +#include +#include +#include +#include + + +#pragma pack(4) /* force structure dword packing here. */ +RT_C_DECLS_BEGIN + + +/** @defgroup grp_vmmdev VMM Device + * + * @note This interface cannot be changed, it can only be extended! + * + * @{ + */ + + +/** Size of VMMDev RAM region accessible by guest. + * Must be big enough to contain VMMDevMemory structure (see further down). + * For now: 4 megabyte. + */ +#define VMMDEV_RAM_SIZE (4 * 256 * PAGE_SIZE) + +/** Size of VMMDev heap region accessible by guest. + * (Must be a power of two (pci range).) + */ +#define VMMDEV_HEAP_SIZE (4 * PAGE_SIZE) + +/** Port for generic request interface (relative offset). */ +#define VMMDEV_PORT_OFF_REQUEST 0 +/** Port for requests that can be handled w/o going to ring-3 (relative offset). + * This works like VMMDevReq_AcknowledgeEvents when read. */ +#define VMMDEV_PORT_OFF_REQUEST_FAST 8 + + +/** @defgroup grp_vmmdev_req VMMDev Generic Request Interface + * @{ + */ + +/** @name Current version of the VMMDev interface. + * + * Additions are allowed to work only if + * additions_major == vmmdev_current && additions_minor <= vmmdev_current. + * Additions version is reported to host (VMMDev) by VMMDevReq_ReportGuestInfo. + * + * @remarks These defines also live in the 16-bit and assembly versions of this + * header. + * @{ + */ +#define VMMDEV_VERSION 0x00010004 +#define VMMDEV_VERSION_MAJOR (VMMDEV_VERSION >> 16) +#define VMMDEV_VERSION_MINOR (VMMDEV_VERSION & 0xffff) +/** @} */ + +/** Maximum request packet size. */ +#define VMMDEV_MAX_VMMDEVREQ_SIZE _1M +/** Maximum number of HGCM parameters. + * @note This used to be 1024, which is kind of insane. Was changed to 32, + * given that (guest) user land can only pass 61 anyway. + * See comments on VBGLIOCHGCMCALL::cParms. */ +#define VMMDEV_MAX_HGCM_PARMS 32 +/** Maximum total size of hgcm buffers in one call. + * @note Used to be 2G, since reduced to 128MB. */ +#define VMMDEV_MAX_HGCM_DATA_SIZE _128M + +/** + * VMMDev request types. + * @note when updating this, adjust vmmdevGetRequestSize() as well + */ +typedef enum VMMDevRequestType +{ + VMMDevReq_InvalidRequest = 0, + VMMDevReq_GetMouseStatus = 1, + VMMDevReq_SetMouseStatus = 2, + VMMDevReq_SetPointerShape = 3, + VMMDevReq_GetHostVersion = 4, + VMMDevReq_Idle = 5, + VMMDevReq_GetHostTime = 10, + VMMDevReq_GetHypervisorInfo = 20, + VMMDevReq_SetHypervisorInfo = 21, + VMMDevReq_RegisterPatchMemory = 22, /**< @since version 3.0.6 */ + VMMDevReq_DeregisterPatchMemory = 23, /**< @since version 3.0.6 */ + VMMDevReq_SetPowerStatus = 30, + VMMDevReq_AcknowledgeEvents = 41, + VMMDevReq_CtlGuestFilterMask = 42, + VMMDevReq_ReportGuestInfo = 50, + VMMDevReq_ReportGuestInfo2 = 58, /**< @since version 3.2.0 */ + VMMDevReq_ReportGuestStatus = 59, /**< @since version 3.2.8 */ + VMMDevReq_ReportGuestUserState = 74, /**< @since version 4.3 */ + /** + * Retrieve a display resize request sent by the host using + * @a IDisplay:setVideoModeHint. Deprecated. + * + * Similar to @a VMMDevReq_GetDisplayChangeRequest2, except that it only + * considers host requests sent for the first virtual display. This guest + * request should not be used in new guest code, and the results are + * undefined if a guest mixes calls to this and + * @a VMMDevReq_GetDisplayChangeRequest2. + */ + VMMDevReq_GetDisplayChangeRequest = 51, + VMMDevReq_VideoModeSupported = 52, + VMMDevReq_GetHeightReduction = 53, + /** + * Retrieve a display resize request sent by the host using + * @a IDisplay:setVideoModeHint. + * + * Queries a display resize request sent from the host. If the + * @a eventAck member is sent to true and there is an unqueried + * request available for one of the virtual display then that request will + * be returned. If several displays have unqueried requests the lowest + * numbered display will be chosen first. Only the most recent unseen + * request for each display is remembered. + * If @a eventAck is set to false, the last host request queried with + * @a eventAck set is resent, or failing that the most recent received from + * the host. If no host request was ever received then all zeros are + * returned. + */ + VMMDevReq_GetDisplayChangeRequest2 = 54, + VMMDevReq_ReportGuestCapabilities = 55, + VMMDevReq_SetGuestCapabilities = 56, + VMMDevReq_VideoModeSupported2 = 57, /**< @since version 3.2.0 */ + VMMDevReq_GetDisplayChangeRequestEx = 80, /**< @since version 4.2.4 */ + VMMDevReq_GetDisplayChangeRequestMulti = 81, +#ifdef VBOX_WITH_HGCM + VMMDevReq_HGCMConnect = 60, + VMMDevReq_HGCMDisconnect = 61, + VMMDevReq_HGCMCall32 = 62, + VMMDevReq_HGCMCall64 = 63, +# ifdef IN_GUEST +# if ARCH_BITS == 64 + VMMDevReq_HGCMCall = VMMDevReq_HGCMCall64, +# elif ARCH_BITS == 32 || ARCH_BITS == 16 + VMMDevReq_HGCMCall = VMMDevReq_HGCMCall32, +# else +# error "Unsupported ARCH_BITS" +# endif +# endif + VMMDevReq_HGCMCancel = 64, + VMMDevReq_HGCMCancel2 = 65, +#endif + VMMDevReq_VideoAccelEnable = 70, + VMMDevReq_VideoAccelFlush = 71, + VMMDevReq_VideoSetVisibleRegion = 72, + VMMDevReq_GetSeamlessChangeRequest = 73, + VMMDevReq_QueryCredentials = 100, + VMMDevReq_ReportCredentialsJudgement = 101, + VMMDevReq_ReportGuestStats = 110, + VMMDevReq_GetMemBalloonChangeRequest = 111, + VMMDevReq_GetStatisticsChangeRequest = 112, + VMMDevReq_ChangeMemBalloon = 113, + VMMDevReq_GetVRDPChangeRequest = 150, + VMMDevReq_LogString = 200, + VMMDevReq_GetCpuHotPlugRequest = 210, + VMMDevReq_SetCpuHotPlugStatus = 211, + VMMDevReq_RegisterSharedModule = 212, + VMMDevReq_UnregisterSharedModule = 213, + VMMDevReq_CheckSharedModules = 214, + VMMDevReq_GetPageSharingStatus = 215, + VMMDevReq_DebugIsPageShared = 216, + VMMDevReq_GetSessionId = 217, /**< @since version 3.2.8 */ + VMMDevReq_WriteCoreDump = 218, + VMMDevReq_GuestHeartbeat = 219, + VMMDevReq_HeartbeatConfigure = 220, + VMMDevReq_NtBugCheck = 221, + VMMDevReq_VideoUpdateMonitorPositions= 222, + VMMDevReq_GetMouseStatusEx = 223, + VMMDevReq_SizeHack = 0x7fffffff +} VMMDevRequestType; + +/** Version of VMMDevRequestHeader structure. */ +#define VMMDEV_REQUEST_HEADER_VERSION (0x10001) + + +/** + * Generic VMMDev request header. + * + * This structure is copied/mirrored by VBGLREQHDR in the VBoxGuest I/O control + * interface. Changes there needs to be mirrored in it. + * + * @sa VBGLREQHDR + */ +typedef struct VMMDevRequestHeader +{ + /** IN: Size of the structure in bytes (including body). + * (VBGLREQHDR uses this for input size and output if reserved1 is zero). */ + uint32_t size; + /** IN: Version of the structure. */ + uint32_t version; + /** IN: Type of the request. + * @note VBGLREQHDR uses this for optional output size. */ + VMMDevRequestType requestType; + /** OUT: VBox status code. */ + int32_t rc; + /** Reserved field no.1. MBZ. + * @note VBGLREQHDR uses this for optional output size, however never for a + * real VMMDev request, only in the I/O control interface. */ + uint32_t reserved1; + /** IN: Requestor information (VMMDEV_REQUESTOR_XXX) when + * VBOXGSTINFO2_F_REQUESTOR_INFO is set, otherwise ignored by the host. */ + uint32_t fRequestor; +} VMMDevRequestHeader; +AssertCompileSize(VMMDevRequestHeader, 24); + +/** @name VMMDEV_REQUESTOR_XXX - Requestor information. + * + * This is information provided to the host by the VBoxGuest device driver, so + * the host can implemented fine grained access to functionality if it likes. + * @bugref{9105} + * + * @{ */ +/** Requestor user not given. */ +#define VMMDEV_REQUESTOR_USR_NOT_GIVEN UINT32_C(0x00000000) +/** The kernel driver (VBoxGuest) is the requestor. */ +#define VMMDEV_REQUESTOR_USR_DRV UINT32_C(0x00000001) +/** Some other kernel driver is the requestor. */ +#define VMMDEV_REQUESTOR_USR_DRV_OTHER UINT32_C(0x00000002) +/** The root or a admin user is the requestor. */ +#define VMMDEV_REQUESTOR_USR_ROOT UINT32_C(0x00000003) +/** Requestor is the windows system user (SID S-1-5-18). */ +#define VMMDEV_REQUESTOR_USR_SYSTEM UINT32_C(0x00000004) +/** Reserved requestor user \#1, treat like VMMDEV_REQUESTOR_USR_USER. */ +#define VMMDEV_REQUESTOR_USR_RESERVED1 UINT32_C(0x00000005) +/** Regular joe user is making the request. */ +#define VMMDEV_REQUESTOR_USR_USER UINT32_C(0x00000006) +/** Requestor is a guest user (or in a guest user group). */ +#define VMMDEV_REQUESTOR_USR_GUEST UINT32_C(0x00000007) +/** User classification mask. */ +#define VMMDEV_REQUESTOR_USR_MASK UINT32_C(0x00000007) + +/** Kernel mode request. + * @note This is zero, so test for VMMDEV_REQUESTOR_USERMODE instead. */ +#define VMMDEV_REQUESTOR_KERNEL UINT32_C(0x00000000) +/** User mode request. */ +#define VMMDEV_REQUESTOR_USERMODE UINT32_C(0x00000008) + +/** Don't know the physical console association of the requestor. */ +#define VMMDEV_REQUESTOR_CON_DONT_KNOW UINT32_C(0x00000000) +/** The request originates with a process that is NOT associated with the + * physical console. */ +#define VMMDEV_REQUESTOR_CON_NO UINT32_C(0x00000010) +/** Requestor process DOES is associated with the physical console. */ +#define VMMDEV_REQUESTOR_CON_YES UINT32_C(0x00000020) +/** Requestor process belongs to user on the physical console, but cannot + * ascertain that it is associated with that login. */ +#define VMMDEV_REQUESTOR_CON_USER UINT32_C(0x00000030) +/** Mask the physical console state of the request. */ +#define VMMDEV_REQUESTOR_CON_MASK UINT32_C(0x00000030) + +/** Requestor is member of special VirtualBox user group (not on windows). */ +#define VMMDEV_REQUESTOR_GRP_VBOX UINT32_C(0x00000080) +/** Requestor is member of wheel / administrators group (SID S-1-5-32-544). */ +#define VMMDEV_REQUESTOR_GRP_WHEEL UINT32_C(0x00000100) + +/** Requestor trust level: Unspecified */ +#define VMMDEV_REQUESTOR_TRUST_NOT_GIVEN UINT32_C(0x00000000) +/** Requestor trust level: Untrusted (SID S-1-16-0) */ +#define VMMDEV_REQUESTOR_TRUST_UNTRUSTED UINT32_C(0x00001000) +/** Requestor trust level: Untrusted (SID S-1-16-4096) */ +#define VMMDEV_REQUESTOR_TRUST_LOW UINT32_C(0x00002000) +/** Requestor trust level: Medium (SID S-1-16-8192) */ +#define VMMDEV_REQUESTOR_TRUST_MEDIUM UINT32_C(0x00003000) +/** Requestor trust level: Medium plus (SID S-1-16-8448) */ +#define VMMDEV_REQUESTOR_TRUST_MEDIUM_PLUS UINT32_C(0x00004000) +/** Requestor trust level: High (SID S-1-16-12288) */ +#define VMMDEV_REQUESTOR_TRUST_HIGH UINT32_C(0x00005000) +/** Requestor trust level: System (SID S-1-16-16384) */ +#define VMMDEV_REQUESTOR_TRUST_SYSTEM UINT32_C(0x00006000) +/** Requestor trust level: Protected or higher (SID S-1-16-20480, S-1-16-28672) + * @note To avoid wasting an unnecessary bit, we combine the two top most + * mandatory security labels on Windows (protected and secure). */ +#define VMMDEV_REQUESTOR_TRUST_PROTECTED UINT32_C(0x00007000) +/** Requestor trust level mask. + * The higher the value, the more the guest trusts the process. */ +#define VMMDEV_REQUESTOR_TRUST_MASK UINT32_C(0x00007000) + +/** Requestor is using the less trusted user device node (/dev/vboxuser). */ +#define VMMDEV_REQUESTOR_USER_DEVICE UINT32_C(0x00008000) +/** There is no user device node (/dev/vboxuser). */ +#define VMMDEV_REQUESTOR_NO_USER_DEVICE UINT32_C(0x00010000) + +/** Legacy value for when VBOXGSTINFO2_F_REQUESTOR_INFO is clear. + * @internal Host only. */ +#define VMMDEV_REQUESTOR_LEGACY UINT32_MAX +/** Lowest conceivable trust level, for error situations of getters. + * @internal Host only. */ +#define VMMDEV_REQUESTOR_LOWEST ( VMMDEV_REQUESTOR_TRUST_UNTRUSTED | VMMDEV_REQUESTOR_USER_DEVICE \ + | VMMDEV_REQUESTOR_CON_NO | VMMDEV_REQUESTOR_USERMODE \ + | VMMDEV_REQUESTOR_USR_GUEST) +/** Used on the host to check whether a requestor value is present or not. */ +#define VMMDEV_REQUESTOR_IS_PRESENT(a_fRequestor) ((a_fRequestor) != VMMDEV_REQUESTOR_LEGACY) +/** @} */ + +/** Initialize a VMMDevRequestHeader structure. + * Same as VBGLREQHDR_INIT_VMMDEV(). */ +#define VMMDEV_REQ_HDR_INIT(a_pHdr, a_cb, a_enmType) \ + do { \ + (a_pHdr)->size = (a_cb); \ + (a_pHdr)->version = VMMDEV_REQUEST_HEADER_VERSION; \ + (a_pHdr)->requestType = (a_enmType); \ + (a_pHdr)->rc = VERR_INTERNAL_ERROR; \ + (a_pHdr)->reserved1 = 0; \ + (a_pHdr)->fRequestor = 0; \ + } while (0) + + +/** + * Mouse status request structure. + * + * Used by VMMDevReq_GetMouseStatus and VMMDevReq_SetMouseStatus. + */ +typedef struct +{ + /** header */ + VMMDevRequestHeader header; + /** Mouse feature mask. See VMMDEV_MOUSE_*. */ + uint32_t mouseFeatures; + /** Mouse x position. */ + int32_t pointerXPos; + /** Mouse y position. */ + int32_t pointerYPos; +} VMMDevReqMouseStatus; +AssertCompileSize(VMMDevReqMouseStatus, 24+12); + + +/** @name Mouse buttons state bits for VMMDevReqMouseStatusEx::fButtons (identical to PDMIMOUSEPORT_BUTTON_XXX). + * @{ */ +/** Left mouse button pressed. */ +#define VMMDEV_MOUSE_BUTTON_LEFT RT_BIT(0) +/** Right mouse button pressed. */ +#define VMMDEV_MOUSE_BUTTON_RIGHT RT_BIT(1) +/** Middle mouse button pressed. */ +#define VMMDEV_MOUSE_BUTTON_MIDDLE RT_BIT(2) +/** X1 mouse button pressed. */ +#define VMMDEV_MOUSE_BUTTON_X1 RT_BIT(3) +/** X2 mouse button pressed. */ +#define VMMDEV_MOUSE_BUTTON_X2 RT_BIT(4) +/** @} */ + + +/** + * Extended mouse status request structure. + * + * Used by VMMDevReq_GetMouseStatusEx. + */ +typedef struct +{ + /** Legacy mouse status request structure. */ + VMMDevReqMouseStatus Core; + /** Mouse wheel vertical mvement. */ + int32_t dz; + /** Mouse wheel horizontal movement. */ + int32_t dw; + /** Mouse buttons state. */ + uint32_t fButtons; +} VMMDevReqMouseStatusEx; +AssertCompileSize(VMMDevReqMouseStatusEx, 24+24); + + +/** @name Mouse capability bits (VMMDevReqMouseStatus::mouseFeatures). + * @{ */ +/** The guest can (== wants to) handle absolute coordinates. */ +#define VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE RT_BIT(0) +/** The host can (== wants to) send absolute coordinates. + * (Input not captured.) */ +#define VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE RT_BIT(1) +/** The guest can *NOT* switch to software cursor and therefore depends on the + * host cursor. + * + * When guest additions are installed and the host has promised to display the + * cursor itself, the guest installs a hardware mouse driver. Don't ask the + * guest to switch to a software cursor then. */ +#define VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR RT_BIT(2) +/** The host does NOT provide support for drawing the cursor itself. */ +#define VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER RT_BIT(3) +/** The guest can read VMMDev events to find out about pointer movement */ +#define VMMDEV_MOUSE_NEW_PROTOCOL RT_BIT(4) +/** If the guest changes the status of the + * VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR bit, the host will honour this */ +#define VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR RT_BIT(5) +/** The host supplies an absolute pointing device. The Guest Additions may + * wish to use this to decide whether to install their own driver */ +#define VMMDEV_MOUSE_HOST_HAS_ABS_DEV RT_BIT(6) +/** The guest can read VMMDev events to find out about full mouse state */ +#define VMMDEV_MOUSE_GUEST_USES_FULL_STATE_PROTOCOL RT_BIT(7) +/** The host can provide full mouse state over VMMDev events */ +#define VMMDEV_MOUSE_HOST_USES_FULL_STATE_PROTOCOL RT_BIT(8) +/** The mask of all VMMDEV_MOUSE_* flags */ +#define VMMDEV_MOUSE_MASK UINT32_C(0x000001ff) +/** The mask of guest capability changes for which notification events should + * be sent */ +#define VMMDEV_MOUSE_NOTIFY_HOST_MASK \ + (VMMDEV_MOUSE_GUEST_CAN_ABSOLUTE | VMMDEV_MOUSE_GUEST_NEEDS_HOST_CURSOR) +/** The mask of all capabilities which the guest can legitimately change */ +#define VMMDEV_MOUSE_GUEST_MASK \ + (VMMDEV_MOUSE_NOTIFY_HOST_MASK | VMMDEV_MOUSE_NEW_PROTOCOL | VMMDEV_MOUSE_GUEST_USES_FULL_STATE_PROTOCOL) +/** The mask of host capability changes for which notification events should + * be sent */ +#define VMMDEV_MOUSE_NOTIFY_GUEST_MASK \ + VMMDEV_MOUSE_HOST_WANTS_ABSOLUTE +/** The mask of all capabilities which the host can legitimately change */ +#define VMMDEV_MOUSE_HOST_MASK \ + ( VMMDEV_MOUSE_NOTIFY_GUEST_MASK \ + | VMMDEV_MOUSE_HOST_CANNOT_HWPOINTER \ + | VMMDEV_MOUSE_HOST_RECHECKS_NEEDS_HOST_CURSOR \ + | VMMDEV_MOUSE_HOST_HAS_ABS_DEV \ + | VMMDEV_MOUSE_HOST_USES_FULL_STATE_PROTOCOL) +/** @} */ + +/** @name Absolute mouse reporting range + * @{ */ +/** @todo Should these be here? They are needed by both host and guest. */ +/** The minumum value our pointing device can return. */ +#define VMMDEV_MOUSE_RANGE_MIN 0 +/** The maximum value our pointing device can return. */ +#define VMMDEV_MOUSE_RANGE_MAX 0xFFFF +/** The full range our pointing device can return. */ +#define VMMDEV_MOUSE_RANGE (VMMDEV_MOUSE_RANGE_MAX - VMMDEV_MOUSE_RANGE_MIN) +/** @} */ + + +/** + * Mouse pointer shape/visibility change request. + * + * Used by VMMDevReq_SetPointerShape. The size is variable. + */ +typedef struct VMMDevReqMousePointer +{ + /** Header. */ + VMMDevRequestHeader header; + /** VBOX_MOUSE_POINTER_* bit flags from VBox/Graphics/VBoxVideo.h. */ + uint32_t fFlags; + /** x coordinate of hot spot. */ + uint32_t xHot; + /** y coordinate of hot spot. */ + uint32_t yHot; + /** Width of the pointer in pixels. */ + uint32_t width; + /** Height of the pointer in scanlines. */ + uint32_t height; + /** Pointer data. + * + **** + * The data consists of 1 bpp AND mask followed by 32 bpp XOR (color) mask. + * + * For pointers without alpha channel the XOR mask pixels are 32 bit values: (lsb)BGR0(msb). + * For pointers with alpha channel the XOR mask consists of (lsb)BGRA(msb) 32 bit values. + * + * Guest driver must create the AND mask for pointers with alpha channel, so if host does not + * support alpha, the pointer could be displayed as a normal color pointer. The AND mask can + * be constructed from alpha values. For example alpha value >= 0xf0 means bit 0 in the AND mask. + * + * The AND mask is 1 bpp bitmap with byte aligned scanlines. Size of AND mask, + * therefore, is cbAnd = (width + 7) / 8 * height. The padding bits at the + * end of any scanline are undefined. + * + * The XOR mask follows the AND mask on the next 4 bytes aligned offset: + * uint8_t *pXor = pAnd + (cbAnd + 3) & ~3 + * Bytes in the gap between the AND and the XOR mask are undefined. + * XOR mask scanlines have no gap between them and size of XOR mask is: + * cXor = width * 4 * height. + **** + * + * Preallocate 4 bytes for accessing actual data as p->pointerData. + */ + char pointerData[4]; +} VMMDevReqMousePointer; +AssertCompileSize(VMMDevReqMousePointer, 24+24); + +/** + * Get the size that a VMMDevReqMousePointer request should have for a given + * size of cursor, including the trailing cursor image and mask data. + * @note an "empty" request still has the four preallocated bytes of data + * + * @returns the size + * @param width the cursor width + * @param height the cursor height + */ +DECLINLINE(size_t) vmmdevGetMousePointerReqSize(uint32_t width, uint32_t height) +{ + size_t cbBase = RT_UOFFSETOF(VMMDevReqMousePointer, pointerData[0]); + size_t cbMask = (width + 7) / 8 * height; + size_t cbArgb = width * height * 4; + return RT_MAX(cbBase + ((cbMask + 3) & ~(size_t)3) + cbArgb, + sizeof(VMMDevReqMousePointer)); +} + + +/** + * String log request structure. + * + * Used by VMMDevReq_LogString. + * @deprecated Use the IPRT logger or VbglR3WriteLog instead. + */ +typedef struct +{ + /** header */ + VMMDevRequestHeader header; + /** variable length string data */ + char szString[1]; +} VMMDevReqLogString; +AssertCompileSize(VMMDevReqLogString, 24+4); + + +/** + * VirtualBox host version request structure. + * + * Used by VMMDevReq_GetHostVersion. + * + * @remarks VBGL uses this to detect the precense of new features in the + * interface. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Major version. */ + uint16_t major; + /** Minor version. */ + uint16_t minor; + /** Build number. */ + uint32_t build; + /** SVN revision. */ + uint32_t revision; + /** Feature mask. */ + uint32_t features; +} VMMDevReqHostVersion; +AssertCompileSize(VMMDevReqHostVersion, 24+16); + +/** @name VMMDEV_HVF_XXX - VMMDevReqHostVersion::features + * @{ */ +/** Physical page lists are supported by HGCM. */ +#define VMMDEV_HVF_HGCM_PHYS_PAGE_LIST RT_BIT_32(0) +/** HGCM supports the embedded buffer parameter type. */ +#define VMMDEV_HVF_HGCM_EMBEDDED_BUFFERS RT_BIT_32(1) +/** HGCM supports the contiguous page list parameter type. */ +#define VMMDEV_HVF_HGCM_CONTIGUOUS_PAGE_LIST RT_BIT_32(2) +/** HGCM supports the no-bounce page list parameter type. */ +#define VMMDEV_HVF_HGCM_NO_BOUNCE_PAGE_LIST RT_BIT_32(3) +/** VMMDev supports fast IRQ acknowledgements. */ +#define VMMDEV_HVF_FAST_IRQ_ACK RT_BIT_32(31) +/** @} */ + + +/** + * Guest capabilities structure. + * + * Used by VMMDevReq_ReportGuestCapabilities. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Capabilities (VMMDEV_GUEST_*). */ + uint32_t caps; +} VMMDevReqGuestCapabilities; +AssertCompileSize(VMMDevReqGuestCapabilities, 24+4); + + +/** + * Guest capabilities structure, version 2. + * + * Used by VMMDevReq_SetGuestCapabilities. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Mask of capabilities to be added. */ + uint32_t u32OrMask; + /** Mask of capabilities to be removed. */ + uint32_t u32NotMask; +} VMMDevReqGuestCapabilities2; +AssertCompileSize(VMMDevReqGuestCapabilities2, 24+8); + + +/** + * Idle request structure. + * + * Used by VMMDevReq_Idle. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; +} VMMDevReqIdle; +AssertCompileSize(VMMDevReqIdle, 24); + + +/** + * Host time request structure. + * + * Used by VMMDevReq_GetHostTime. + */ +typedef struct +{ + /** Header */ + VMMDevRequestHeader header; + /** OUT: Time in milliseconds since unix epoch. */ + uint64_t time; +} VMMDevReqHostTime; +AssertCompileSize(VMMDevReqHostTime, 24+8); + + +/** + * Hypervisor info structure. + * + * Used by VMMDevReq_GetHypervisorInfo and VMMDevReq_SetHypervisorInfo. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest virtual address of proposed hypervisor start. + * Not used by VMMDevReq_GetHypervisorInfo. + * @todo Make this 64-bit compatible? */ + RTGCPTR32 hypervisorStart; + /** Hypervisor size in bytes. */ + uint32_t hypervisorSize; +} VMMDevReqHypervisorInfo; +AssertCompileSize(VMMDevReqHypervisorInfo, 24+8); + +/** @name Default patch memory size . + * Used by VMMDevReq_RegisterPatchMemory and VMMDevReq_DeregisterPatchMemory. + * @{ */ +#define VMMDEV_GUEST_DEFAULT_PATCHMEM_SIZE 8192 +/** @} */ + +/** + * Patching memory structure. (locked executable & read-only page from the guest's perspective) + * + * Used by VMMDevReq_RegisterPatchMemory and VMMDevReq_DeregisterPatchMemory + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest virtual address of the patching page(s). */ + RTGCPTR64 pPatchMem; + /** Patch page size in bytes. */ + uint32_t cbPatchMem; +} VMMDevReqPatchMemory; +AssertCompileSize(VMMDevReqPatchMemory, 24+12); + + +/** + * Guest power requests. + * + * See VMMDevReq_SetPowerStatus and VMMDevPowerStateRequest. + */ +typedef enum +{ + VMMDevPowerState_Invalid = 0, + VMMDevPowerState_Pause = 1, + VMMDevPowerState_PowerOff = 2, + VMMDevPowerState_SaveState = 3, + VMMDevPowerState_SizeHack = 0x7fffffff +} VMMDevPowerState; +AssertCompileSize(VMMDevPowerState, 4); + +/** + * VM power status structure. + * + * Used by VMMDevReq_SetPowerStatus. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Power state request. */ + VMMDevPowerState powerState; +} VMMDevPowerStateRequest; +AssertCompileSize(VMMDevPowerStateRequest, 24+4); + + +/** + * Pending events structure. + * + * Used by VMMDevReq_AcknowledgeEvents. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** OUT: Pending event mask. */ + uint32_t events; +} VMMDevEvents; +AssertCompileSize(VMMDevEvents, 24+4); + + +/** + * Guest event filter mask control. + * + * Used by VMMDevReq_CtlGuestFilterMask. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Mask of events to be added to the filter. */ + uint32_t u32OrMask; + /** Mask of events to be removed from the filter. */ + uint32_t u32NotMask; +} VMMDevCtlGuestFilterMask; +AssertCompileSize(VMMDevCtlGuestFilterMask, 24+8); + + +/** + * Guest information structure. + * + * Used by VMMDevReportGuestInfo and PDMIVMMDEVCONNECTOR::pfnUpdateGuestVersion. + */ +typedef struct VBoxGuestInfo +{ + /** The VMMDev interface version expected by additions. + * *Deprecated*, do not use anymore! Will be removed. */ + uint32_t interfaceVersion; + /** Guest OS type. */ + VBOXOSTYPE osType; +} VBoxGuestInfo; +AssertCompileSize(VBoxGuestInfo, 8); + +/** + * Guest information report. + * + * Used by VMMDevReq_ReportGuestInfo. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest information. */ + VBoxGuestInfo guestInfo; +} VMMDevReportGuestInfo; +AssertCompileSize(VMMDevReportGuestInfo, 24+8); + + +/** + * Guest information structure, version 2. + * + * Used by VMMDevReportGuestInfo2 and PDMIVMMDEVCONNECTOR::pfnUpdateGuestVersion2. + */ +typedef struct VBoxGuestInfo2 +{ + /** Major version. */ + uint16_t additionsMajor; + /** Minor version. */ + uint16_t additionsMinor; + /** Build number. */ + uint32_t additionsBuild; + /** SVN revision. */ + uint32_t additionsRevision; + /** Feature mask, VBOXGSTINFO2_F_XXX. */ + uint32_t additionsFeatures; + /** The intentional meaning of this field was: + * Some additional information, for example 'Beta 1' or something like that. + * + * The way it was implemented was implemented: VBOX_VERSION_STRING. + * + * This means the first three members are duplicated in this field (if the guest + * build config is sane). So, the user must check this and chop it off before + * usage. There is, because of the Main code's blind trust in the field's + * content, no way back. */ + char szName[128]; +} VBoxGuestInfo2; +AssertCompileSize(VBoxGuestInfo2, 144); + +/** @name VBOXGSTINFO2_F_XXX - Features + * @{ */ +/** Request header carries requestor information. */ +#define VBOXGSTINFO2_F_REQUESTOR_INFO RT_BIT_32(0) +/** @} */ + + +/** + * Guest information report, version 2. + * + * Used by VMMDevReq_ReportGuestInfo2. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest information. */ + VBoxGuestInfo2 guestInfo; +} VMMDevReportGuestInfo2; +AssertCompileSize(VMMDevReportGuestInfo2, 24+144); + + +/** + * The facility class. + * + * This needs to be kept in sync with AdditionsFacilityClass of the Main API! + */ +typedef enum +{ + VBoxGuestFacilityClass_None = 0, + VBoxGuestFacilityClass_Driver = 10, + VBoxGuestFacilityClass_Service = 30, + VBoxGuestFacilityClass_Program = 50, + VBoxGuestFacilityClass_Feature = 100, + VBoxGuestFacilityClass_ThirdParty = 999, + VBoxGuestFacilityClass_All = 0x7ffffffe, + VBoxGuestFacilityClass_SizeHack = 0x7fffffff +} VBoxGuestFacilityClass; +AssertCompileSize(VBoxGuestFacilityClass, 4); + +/** + * Guest status structure. + * + * Used by VMMDevReqGuestStatus. + */ +typedef struct VBoxGuestStatus +{ + /** Facility the status is indicated for. */ + VBoxGuestFacilityType facility; + /** Current guest status. */ + VBoxGuestFacilityStatus status; + /** Flags, not used at the moment. */ + uint32_t flags; +} VBoxGuestStatus; +AssertCompileSize(VBoxGuestStatus, 12); + +/** + * Guest Additions status structure. + * + * Used by VMMDevReq_ReportGuestStatus. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest information. */ + VBoxGuestStatus guestStatus; +} VMMDevReportGuestStatus; +AssertCompileSize(VMMDevReportGuestStatus, 24+12); + + +/** + * Guest user status updates. + */ +typedef struct VBoxGuestUserStatus +{ + /** The guest user state to send. */ + VBoxGuestUserState state; + /** Size (in bytes) of szUser. */ + uint32_t cbUser; + /** Size (in bytes) of szDomain. */ + uint32_t cbDomain; + /** Size (in bytes) of aDetails. */ + uint32_t cbDetails; + /** Note: Here begins the dynamically + * allocated region. */ + /** Guest user to report state for. */ + char szUser[1]; + /** Domain the guest user is bound to. */ + char szDomain[1]; + /** Optional details of the state. */ + uint8_t aDetails[1]; +} VBoxGuestUserStatus; +AssertCompileSize(VBoxGuestUserStatus, 20); + + +/** + * Guest user status structure. + * + * Used by VMMDevReq_ReportGuestUserStatus. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest user status. */ + VBoxGuestUserStatus status; +} VMMDevReportGuestUserState; +AssertCompileSize(VMMDevReportGuestUserState, 24+20); + + +/** + * Guest statistics structure. + * + * Used by VMMDevReportGuestStats and PDMIVMMDEVCONNECTOR::pfnReportStatistics. + */ +typedef struct VBoxGuestStatistics +{ + /** Virtual CPU ID. */ + uint32_t u32CpuId; + /** Reported statistics. */ + uint32_t u32StatCaps; + /** Idle CPU load (0-100) for last interval. */ + uint32_t u32CpuLoad_Idle; + /** Kernel CPU load (0-100) for last interval. */ + uint32_t u32CpuLoad_Kernel; + /** User CPU load (0-100) for last interval. */ + uint32_t u32CpuLoad_User; + /** Nr of threads. */ + uint32_t u32Threads; + /** Nr of processes. */ + uint32_t u32Processes; + /** Nr of handles. */ + uint32_t u32Handles; + /** Memory load (0-100). */ + uint32_t u32MemoryLoad; + /** Page size of guest system. */ + uint32_t u32PageSize; + /** Total physical memory (in 4KB pages). */ + uint32_t u32PhysMemTotal; + /** Available physical memory (in 4KB pages). */ + uint32_t u32PhysMemAvail; + /** Ballooned physical memory (in 4KB pages). */ + uint32_t u32PhysMemBalloon; + /** Total number of committed memory (which is not necessarily in-use) (in 4KB pages). */ + uint32_t u32MemCommitTotal; + /** Total amount of memory used by the kernel (in 4KB pages). */ + uint32_t u32MemKernelTotal; + /** Total amount of paged memory used by the kernel (in 4KB pages). */ + uint32_t u32MemKernelPaged; + /** Total amount of nonpaged memory used by the kernel (in 4KB pages). */ + uint32_t u32MemKernelNonPaged; + /** Total amount of memory used for the system cache (in 4KB pages). */ + uint32_t u32MemSystemCache; + /** Pagefile size (in 4KB pages). */ + uint32_t u32PageFileSize; +} VBoxGuestStatistics; +AssertCompileSize(VBoxGuestStatistics, 19*4); + +/** @name Guest statistics values (VBoxGuestStatistics::u32StatCaps). + * @{ */ +#define VBOX_GUEST_STAT_CPU_LOAD_IDLE RT_BIT(0) +#define VBOX_GUEST_STAT_CPU_LOAD_KERNEL RT_BIT(1) +#define VBOX_GUEST_STAT_CPU_LOAD_USER RT_BIT(2) +#define VBOX_GUEST_STAT_THREADS RT_BIT(3) +#define VBOX_GUEST_STAT_PROCESSES RT_BIT(4) +#define VBOX_GUEST_STAT_HANDLES RT_BIT(5) +#define VBOX_GUEST_STAT_MEMORY_LOAD RT_BIT(6) +#define VBOX_GUEST_STAT_PHYS_MEM_TOTAL RT_BIT(7) +#define VBOX_GUEST_STAT_PHYS_MEM_AVAIL RT_BIT(8) +#define VBOX_GUEST_STAT_PHYS_MEM_BALLOON RT_BIT(9) +#define VBOX_GUEST_STAT_MEM_COMMIT_TOTAL RT_BIT(10) +#define VBOX_GUEST_STAT_MEM_KERNEL_TOTAL RT_BIT(11) +#define VBOX_GUEST_STAT_MEM_KERNEL_PAGED RT_BIT(12) +#define VBOX_GUEST_STAT_MEM_KERNEL_NONPAGED RT_BIT(13) +#define VBOX_GUEST_STAT_MEM_SYSTEM_CACHE RT_BIT(14) +#define VBOX_GUEST_STAT_PAGE_FILE_SIZE RT_BIT(15) +/** @} */ + +/** + * Guest statistics command structure. + * + * Used by VMMDevReq_ReportGuestStats. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Guest information. */ + VBoxGuestStatistics guestStats; +} VMMDevReportGuestStats; +AssertCompileSize(VMMDevReportGuestStats, 24+19*4); + + +/** Memory balloon change request structure. */ +#define VMMDEV_MAX_MEMORY_BALLOON(PhysMemTotal) ( (9 * (PhysMemTotal)) / 10 ) + +/** + * Poll for ballooning change request. + * + * Used by VMMDevReq_GetMemBalloonChangeRequest. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Balloon size in megabytes. */ + uint32_t cBalloonChunks; + /** Guest ram size in megabytes. */ + uint32_t cPhysMemChunks; + /** Setting this to VMMDEV_EVENT_BALLOON_CHANGE_REQUEST indicates that the + * request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t eventAck; +} VMMDevGetMemBalloonChangeRequest; +AssertCompileSize(VMMDevGetMemBalloonChangeRequest, 24+12); + + +/** + * Change the size of the balloon. + * + * Used by VMMDevReq_ChangeMemBalloon. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** The number of pages in the array. */ + uint32_t cPages; + /** true = inflate, false = deflate. */ + uint32_t fInflate; + /** Physical address (RTGCPHYS) of each page, variable size. */ + RTGCPHYS aPhysPage[1]; +} VMMDevChangeMemBalloon; +AssertCompileSize(VMMDevChangeMemBalloon, 24+16); + + +/** + * Guest statistics interval change request structure. + * + * Used by VMMDevReq_GetStatisticsChangeRequest. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** The interval in seconds. */ + uint32_t u32StatInterval; + /** Setting this to VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST indicates + * that the request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t eventAck; +} VMMDevGetStatisticsChangeRequest; +AssertCompileSize(VMMDevGetStatisticsChangeRequest, 24+8); + + +/** The size of a string field in the credentials request (including '\\0'). + * @see VMMDevCredentials */ +#define VMMDEV_CREDENTIALS_SZ_SIZE 128 + +/** + * Credentials request structure. + * + * Used by VMMDevReq_QueryCredentials. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** IN/OUT: Request flags. */ + uint32_t u32Flags; + /** OUT: User name (UTF-8). */ + char szUserName[VMMDEV_CREDENTIALS_SZ_SIZE]; + /** OUT: Password (UTF-8). */ + char szPassword[VMMDEV_CREDENTIALS_SZ_SIZE]; + /** OUT: Domain name (UTF-8). */ + char szDomain[VMMDEV_CREDENTIALS_SZ_SIZE]; +} VMMDevCredentials; +AssertCompileSize(VMMDevCredentials, 24+4+3*128); + +/** @name Credentials request flag (VMMDevCredentials::u32Flags) + * @{ */ +/** query from host whether credentials are present */ +#define VMMDEV_CREDENTIALS_QUERYPRESENCE RT_BIT(1) +/** read credentials from host (can be combined with clear) */ +#define VMMDEV_CREDENTIALS_READ RT_BIT(2) +/** clear credentials on host (can be combined with read) */ +#define VMMDEV_CREDENTIALS_CLEAR RT_BIT(3) +/** read credentials for judgement in the guest */ +#define VMMDEV_CREDENTIALS_READJUDGE RT_BIT(8) +/** clear credentials for judegement on the host */ +#define VMMDEV_CREDENTIALS_CLEARJUDGE RT_BIT(9) +/** report credentials acceptance by guest */ +#define VMMDEV_CREDENTIALS_JUDGE_OK RT_BIT(10) +/** report credentials denial by guest */ +#define VMMDEV_CREDENTIALS_JUDGE_DENY RT_BIT(11) +/** report that no judgement could be made by guest */ +#define VMMDEV_CREDENTIALS_JUDGE_NOJUDGEMENT RT_BIT(12) + +/** flag telling the guest that credentials are present */ +#define VMMDEV_CREDENTIALS_PRESENT RT_BIT(16) +/** flag telling guest that local logons should be prohibited */ +#define VMMDEV_CREDENTIALS_NOLOCALLOGON RT_BIT(17) +/** @} */ + + +/** + * Seamless mode change request structure. + * + * Used by VMMDevReq_GetSeamlessChangeRequest. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + + /** New seamless mode. */ + VMMDevSeamlessMode mode; + /** Setting this to VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST indicates + * that the request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t eventAck; +} VMMDevSeamlessChangeRequest; +AssertCompileSize(VMMDevSeamlessChangeRequest, 24+8); +AssertCompileMemberOffset(VMMDevSeamlessChangeRequest, eventAck, 24+4); + + +/** + * Display change request structure. + * + * Used by VMMDevReq_GetDisplayChangeRequest. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Horizontal pixel resolution (0 = do not change). */ + uint32_t xres; + /** Vertical pixel resolution (0 = do not change). */ + uint32_t yres; + /** Bits per pixel (0 = do not change). */ + uint32_t bpp; + /** Setting this to VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST indicates + * that the request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t eventAck; +} VMMDevDisplayChangeRequest; +AssertCompileSize(VMMDevDisplayChangeRequest, 24+16); + + +/** + * Display change request structure, version 2. + * + * Used by VMMDevReq_GetDisplayChangeRequest2. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Horizontal pixel resolution (0 = do not change). */ + uint32_t xres; + /** Vertical pixel resolution (0 = do not change). */ + uint32_t yres; + /** Bits per pixel (0 = do not change). */ + uint32_t bpp; + /** Setting this to VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST indicates + * that the request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t eventAck; + /** 0 for primary display, 1 for the first secondary, etc. */ + uint32_t display; +} VMMDevDisplayChangeRequest2; +AssertCompileSize(VMMDevDisplayChangeRequest2, 24+20); + + +/** + * Display change request structure, version Extended. + * + * Used by VMMDevReq_GetDisplayChangeRequestEx. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Horizontal pixel resolution (0 = do not change). */ + uint32_t xres; + /** Vertical pixel resolution (0 = do not change). */ + uint32_t yres; + /** Bits per pixel (0 = do not change). */ + uint32_t bpp; + /** Setting this to VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST indicates + * that the request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t eventAck; + /** 0 for primary display, 1 for the first secondary, etc. */ + uint32_t display; + /** New OriginX of secondary virtual screen */ + uint32_t cxOrigin; + /** New OriginY of secondary virtual screen */ + uint32_t cyOrigin; + /** Change in origin of the secondary virtaul scree is + * required */ + bool fChangeOrigin; + /** secondary virtual screen enabled or disabled */ + bool fEnabled; +} VMMDevDisplayChangeRequestEx; +AssertCompileSize(VMMDevDisplayChangeRequestEx, 24+32); + + +/** Flags for VMMDevDisplayDef::fDisplayFlags */ +#define VMMDEV_DISPLAY_PRIMARY UINT32_C(0x00000001) /**< Primary display. */ +#define VMMDEV_DISPLAY_DISABLED UINT32_C(0x00000002) /**< Display is disabled. */ +#define VMMDEV_DISPLAY_ORIGIN UINT32_C(0x00000004) /**< Change position of the diplay. */ +#define VMMDEV_DISPLAY_CX UINT32_C(0x00000008) /**< Change the horizontal resolution of the display. */ +#define VMMDEV_DISPLAY_CY UINT32_C(0x00000010) /**< Change the vertical resolution of the display. */ +#define VMMDEV_DISPLAY_BPP UINT32_C(0x00000020) /**< Change the color depth of the display. */ + +/** Definition of one monitor. Used by VMMDevReq_GetDisplayChangeRequestMulti. */ +typedef struct VMMDevDisplayDef +{ + uint32_t fDisplayFlags; /**< VMMDEV_DISPLAY_* flags. */ + uint32_t idDisplay; /**< The display number. */ + int32_t xOrigin; /**< New OriginX of the guest screen. */ + int32_t yOrigin; /**< New OriginY of the guest screen. */ + uint32_t cx; /**< Horizontal pixel resolution. */ + uint32_t cy; /**< Vertical pixel resolution. */ + uint32_t cBitsPerPixel; /**< Bits per pixel. */ +} VMMDevDisplayDef; +AssertCompileSize(VMMDevDisplayDef, 28); + +/** Multimonitor display change request structure. Used by VMMDevReq_GetDisplayChangeRequestMulti. */ +typedef struct VMMDevDisplayChangeRequestMulti +{ + VMMDevRequestHeader header; /**< Header. */ + uint32_t eventAck; /**< Setting this to VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST indicates + * that the request is a response to that event. + * (Don't confuse this with VMMDevReq_AcknowledgeEvents.) */ + uint32_t cDisplays; /**< Number of monitors. In: how many the guest expects. + * Out: how many the host provided. */ + VMMDevDisplayDef aDisplays[1]; /**< Layout of monitors. */ +} VMMDevDisplayChangeRequestMulti; +AssertCompileSize(VMMDevDisplayChangeRequestMulti, 24+8+28); + + +/** + * Video mode supported request structure. + * + * Used by VMMDevReq_VideoModeSupported. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** IN: Horizontal pixel resolution. */ + uint32_t width; + /** IN: Vertical pixel resolution. */ + uint32_t height; + /** IN: Bits per pixel. */ + uint32_t bpp; + /** OUT: Support indicator. */ + bool fSupported; +} VMMDevVideoModeSupportedRequest; +AssertCompileSize(VMMDevVideoModeSupportedRequest, 24+16); + +/** + * Video mode supported request structure for a specific display. + * + * Used by VMMDevReq_VideoModeSupported2. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** IN: The guest display number. */ + uint32_t display; + /** IN: Horizontal pixel resolution. */ + uint32_t width; + /** IN: Vertical pixel resolution. */ + uint32_t height; + /** IN: Bits per pixel. */ + uint32_t bpp; + /** OUT: Support indicator. */ + bool fSupported; +} VMMDevVideoModeSupportedRequest2; +AssertCompileSize(VMMDevVideoModeSupportedRequest2, 24+20); + +/** + * Video modes height reduction request structure. + * + * Used by VMMDevReq_GetHeightReduction. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** OUT: Height reduction in pixels. */ + uint32_t heightReduction; +} VMMDevGetHeightReductionRequest; +AssertCompileSize(VMMDevGetHeightReductionRequest, 24+4); + + +/** + * VRDP change request structure. + * + * Used by VMMDevReq_GetVRDPChangeRequest. + */ +typedef struct +{ + /** Header */ + VMMDevRequestHeader header; + /** Whether VRDP is active or not. */ + uint8_t u8VRDPActive; + /** The configured experience level for active VRDP. */ + uint32_t u32VRDPExperienceLevel; +} VMMDevVRDPChangeRequest; +AssertCompileSize(VMMDevVRDPChangeRequest, 24+8); +AssertCompileMemberOffset(VMMDevVRDPChangeRequest, u8VRDPActive, 24); +AssertCompileMemberOffset(VMMDevVRDPChangeRequest, u32VRDPExperienceLevel, 24+4); + +/** @name VRDP Experience level (VMMDevVRDPChangeRequest::u32VRDPExperienceLevel) + * @{ */ +#define VRDP_EXPERIENCE_LEVEL_ZERO 0 /**< Theming disabled. */ +#define VRDP_EXPERIENCE_LEVEL_LOW 1 /**< Full window dragging and desktop wallpaper disabled. */ +#define VRDP_EXPERIENCE_LEVEL_MEDIUM 2 /**< Font smoothing, gradients. */ +#define VRDP_EXPERIENCE_LEVEL_HIGH 3 /**< Animation effects disabled. */ +#define VRDP_EXPERIENCE_LEVEL_FULL 4 /**< Everything enabled. */ +/** @} */ + + +/** + * VBVA enable request structure. + * + * Used by VMMDevReq_VideoAccelEnable. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** 0 - disable, !0 - enable. */ + uint32_t u32Enable; + /** The size of VBVAMEMORY::au8RingBuffer expected by driver. + * The host will refuse to enable VBVA if the size is not equal to + * VBVA_RING_BUFFER_SIZE. + */ + uint32_t cbRingBuffer; + /** Guest initializes the status to 0. Host sets appropriate VBVA_F_STATUS_ flags. */ + uint32_t fu32Status; +} VMMDevVideoAccelEnable; +AssertCompileSize(VMMDevVideoAccelEnable, 24+12); + +/** @name VMMDevVideoAccelEnable::fu32Status. + * @{ */ +#define VBVA_F_STATUS_ACCEPTED (0x01) +#define VBVA_F_STATUS_ENABLED (0x02) +/** @} */ + + +/** + * VBVA flush request structure. + * + * Used by VMMDevReq_VideoAccelFlush. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; +} VMMDevVideoAccelFlush; +AssertCompileSize(VMMDevVideoAccelFlush, 24); + + +/** + * VBVA set visible region request structure. + * + * Used by VMMDevReq_VideoSetVisibleRegion. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Number of rectangles */ + uint32_t cRect; + /** Rectangle array. + * @todo array is spelled aRects[1]. */ + RTRECT Rect; +} VMMDevVideoSetVisibleRegion; +AssertCompileSize(RTRECT, 16); +AssertCompileSize(VMMDevVideoSetVisibleRegion, 24+4+16); + +/** + * VBVA monitor positions update request structure. + * + * Used by VMMDevReq_VideoUpdateMonitorPositions. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Number of monitor positions (monitors) */ + uint32_t cPositions; + /** Positions array.*/ + RTPOINT aPositions[1]; +} VMMDevVideoUpdateMonitorPositions; +AssertCompileSize(RTPOINT, 8); +AssertCompileSize(VMMDevVideoUpdateMonitorPositions, 24+4+8); + +/** + * CPU event types. + */ +typedef enum +{ + VMMDevCpuStatusType_Invalid = 0, + VMMDevCpuStatusType_Disable = 1, + VMMDevCpuStatusType_Enable = 2, + VMMDevCpuStatusType_SizeHack = 0x7fffffff +} VMMDevCpuStatusType; + +/** + * CPU hotplug event status request. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Status type */ + VMMDevCpuStatusType enmStatusType; +} VMMDevCpuHotPlugStatusRequest; +AssertCompileSize(VMMDevCpuHotPlugStatusRequest, 24+4); + +/** + * Get the ID of the changed CPU and event type. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Event type */ + VMMDevCpuEventType enmEventType; + /** core id of the CPU changed */ + uint32_t idCpuCore; + /** package id of the CPU changed */ + uint32_t idCpuPackage; +} VMMDevGetCpuHotPlugRequest; +AssertCompileSize(VMMDevGetCpuHotPlugRequest, 24+4+4+4); + + +AssertCompileSize(VMMDEVSHAREDREGIONDESC, 16); /* structure was promoted to VBox/types.h. */ + +#define VMMDEVSHAREDREGIONDESC_MAX 32 + +/** + * Shared module registration + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Shared module size. */ + uint32_t cbModule; + /** Number of included region descriptors */ + uint32_t cRegions; + /** Base address of the shared module. */ + RTGCPTR64 GCBaseAddr; + /** Guest OS type. */ + VBOXOSFAMILY enmGuestOS; + /** Alignment. */ + uint32_t u32Align; + /** Module name */ + char szName[128]; + /** Module version */ + char szVersion[16]; + /** Shared region descriptor(s). */ + VMMDEVSHAREDREGIONDESC aRegions[1]; +} VMMDevSharedModuleRegistrationRequest; +AssertCompileSize(VMMDevSharedModuleRegistrationRequest, 24+4+4+8+4+4+128+16+16); + + +/** + * Shared module unregistration + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Shared module size. */ + uint32_t cbModule; + /** Align at 8 byte boundary. */ + uint32_t u32Alignment; + /** Base address of the shared module. */ + RTGCPTR64 GCBaseAddr; + /** Module name */ + char szName[128]; + /** Module version */ + char szVersion[16]; +} VMMDevSharedModuleUnregistrationRequest; +AssertCompileSize(VMMDevSharedModuleUnregistrationRequest, 24+4+4+8+128+16); + + +/** + * Shared module periodic check + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; +} VMMDevSharedModuleCheckRequest; +AssertCompileSize(VMMDevSharedModuleCheckRequest, 24); + +/** + * Paging sharing enabled query + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Enabled flag (out) */ + bool fEnabled; + /** Alignment */ + bool fAlignment[3]; +} VMMDevPageSharingStatusRequest; +AssertCompileSize(VMMDevPageSharingStatusRequest, 24+4); + + +/** + * Page sharing status query (debug build only) + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Page address. */ + RTGCPTR GCPtrPage; + /** Page flags. */ + uint64_t uPageFlags; + /** Shared flag (out) */ + bool fShared; + /** Alignment */ + bool fAlignment[3]; +} VMMDevPageIsSharedRequest; + +/** + * Session id request structure. + * + * Used by VMMDevReq_GetSessionId. + */ +typedef struct +{ + /** Header */ + VMMDevRequestHeader header; + /** OUT: unique session id; the id will be different after each start, reset or restore of the VM */ + uint64_t idSession; +} VMMDevReqSessionId; +AssertCompileSize(VMMDevReqSessionId, 24+8); + + +/** + * Write Core Dump request. + * + * Used by VMMDevReq_WriteCoreDump. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** Flags (reserved, MBZ). */ + uint32_t fFlags; +} VMMDevReqWriteCoreDump; +AssertCompileSize(VMMDevReqWriteCoreDump, 24+4); + + +/** + * Heart beat check state structure. + * Used by VMMDevReq_HeartbeatConfigure. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** OUT: Guest heartbeat interval in nanosec. */ + uint64_t cNsInterval; + /** Heartbeat check flag. */ + bool fEnabled; +} VMMDevReqHeartbeat; +AssertCompileSize(VMMDevReqHeartbeat, 24+12); + + +/** + * NT bug check report. + * Used by VMMDevReq_NtBugCheck. + * @remarks Can be issued with just the header if no more data is available. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** The bug check number (P0). */ + uint64_t uBugCheck; + /** The four bug check parameters. */ + uint64_t auParameters[4]; +} VMMDevReqNtBugCheck; +AssertCompileSize(VMMDevReqNtBugCheck, 24+40); + + + +#ifdef VBOX_WITH_HGCM + +/** @name HGCM flags. + * @{ + */ +# define VBOX_HGCM_REQ_DONE RT_BIT_32(VBOX_HGCM_REQ_DONE_BIT) +# define VBOX_HGCM_REQ_DONE_BIT 0 +# define VBOX_HGCM_REQ_CANCELLED (0x2) +/** @} */ + +/** + * HGCM request header. + */ +typedef struct VMMDevHGCMRequestHeader +{ + /** Request header. */ + VMMDevRequestHeader header; + + /** HGCM flags. */ + uint32_t fu32Flags; + + /** Result code. */ + int32_t result; +} VMMDevHGCMRequestHeader; +AssertCompileSize(VMMDevHGCMRequestHeader, 24+8); + +/** + * HGCM connect request structure. + * + * Used by VMMDevReq_HGCMConnect. + */ +typedef struct +{ + /** HGCM request header. */ + VMMDevHGCMRequestHeader header; + + /** IN: Description of service to connect to. */ + HGCMServiceLocation loc; + + /** OUT: Client identifier assigned by local instance of HGCM. */ + uint32_t u32ClientID; +} VMMDevHGCMConnect; +AssertCompileSize(VMMDevHGCMConnect, 32+132+4); + + +/** + * HGCM disconnect request structure. + * + * Used by VMMDevReq_HGCMDisconnect. + */ +typedef struct +{ + /** HGCM request header. */ + VMMDevHGCMRequestHeader header; + + /** IN: Client identifier. */ + uint32_t u32ClientID; +} VMMDevHGCMDisconnect; +AssertCompileSize(VMMDevHGCMDisconnect, 32+4); + +/** + * HGCM call request structure. + * + * Used by VMMDevReq_HGCMCall32 and VMMDevReq_HGCMCall64. + */ +typedef struct +{ + /* request header */ + VMMDevHGCMRequestHeader header; + + /** IN: Client identifier. */ + uint32_t u32ClientID; + /** IN: Service function number. */ + uint32_t u32Function; + /** IN: Number of parameters. */ + uint32_t cParms; + /** Parameters follow in form: HGCMFunctionParameter aParms[X]; */ +} VMMDevHGCMCall; +AssertCompileSize(VMMDevHGCMCall, 32+12); + +/** @name Direction of data transfer (HGCMPageListInfo::flags). Bit flags. + * @{ */ +#define VBOX_HGCM_F_PARM_DIRECTION_NONE UINT32_C(0x00000000) +#define VBOX_HGCM_F_PARM_DIRECTION_TO_HOST UINT32_C(0x00000001) +#define VBOX_HGCM_F_PARM_DIRECTION_FROM_HOST UINT32_C(0x00000002) +#define VBOX_HGCM_F_PARM_DIRECTION_BOTH UINT32_C(0x00000003) +#define VBOX_HGCM_F_PARM_DIRECTION_MASK UINT32_C(0x00000003) +/** Macro for validating that the specified flags are valid. */ +#define VBOX_HGCM_F_PARM_ARE_VALID(fFlags) \ + ( ((fFlags) & VBOX_HGCM_F_PARM_DIRECTION_MASK) \ + && !((fFlags) & ~VBOX_HGCM_F_PARM_DIRECTION_MASK) ) +/** @} */ + +/** + * VMMDevHGCMParmType_PageList points to this structure to actually describe the + * buffer. + */ +typedef struct +{ + uint32_t flags; /**< VBOX_HGCM_F_PARM_*. */ + uint16_t offFirstPage; /**< Offset in the first page where data begins. */ + uint16_t cPages; /**< Number of pages. */ + RTGCPHYS64 aPages[1]; /**< Page addresses. */ +} HGCMPageListInfo; +AssertCompileSize(HGCMPageListInfo, 4+2+2+8); + + +/** Get the pointer to the first parmater of a HGCM call request. */ +# define VMMDEV_HGCM_CALL_PARMS(a) ((HGCMFunctionParameter *)((uint8_t *)(a) + sizeof (VMMDevHGCMCall))) +/** Get the pointer to the first parmater of a 32-bit HGCM call request. */ +# define VMMDEV_HGCM_CALL_PARMS32(a) ((HGCMFunctionParameter32 *)((uint8_t *)(a) + sizeof (VMMDevHGCMCall))) + +# ifdef VBOX_WITH_64_BITS_GUESTS +/* Explicit defines for the host code. */ +# ifdef VBOX_HGCM_HOST_CODE +# define VMMDEV_HGCM_CALL_PARMS32(a) ((HGCMFunctionParameter32 *)((uint8_t *)(a) + sizeof (VMMDevHGCMCall))) +# define VMMDEV_HGCM_CALL_PARMS64(a) ((HGCMFunctionParameter64 *)((uint8_t *)(a) + sizeof (VMMDevHGCMCall))) +# endif /* VBOX_HGCM_HOST_CODE */ +# endif /* VBOX_WITH_64_BITS_GUESTS */ + +# define VBOX_HGCM_MAX_PARMS 32 + +/** + * HGCM cancel request structure. + * + * The Cancel request is issued using the same physical memory address as was + * used for the corresponding initial HGCMCall. + * + * Used by VMMDevReq_HGCMCancel. + */ +typedef struct +{ + /** Header. */ + VMMDevHGCMRequestHeader header; +} VMMDevHGCMCancel; +AssertCompileSize(VMMDevHGCMCancel, 32); + +/** + * HGCM cancel request structure, version 2. + * + * Used by VMMDevReq_HGCMCancel2. + * + * VINF_SUCCESS when cancelled. + * VERR_NOT_FOUND if the specified request cannot be found. + * VERR_INVALID_PARAMETER if the address is invalid valid. + */ +typedef struct +{ + /** Header. */ + VMMDevRequestHeader header; + /** The physical address of the request to cancel. */ + RTGCPHYS32 physReqToCancel; +} VMMDevHGCMCancel2; +AssertCompileSize(VMMDevHGCMCancel2, 24+4); + +#endif /* VBOX_WITH_HGCM */ + + +/** + * Inline helper to determine the request size for the given operation. + * Returns 0 if the given operation is not handled and/or supported. + * + * @returns Size. + * @param requestType The VMMDev request type. + */ +DECLINLINE(size_t) vmmdevGetRequestSize(VMMDevRequestType requestType) +{ + switch (requestType) + { + case VMMDevReq_GetMouseStatus: + case VMMDevReq_SetMouseStatus: + return sizeof(VMMDevReqMouseStatus); + case VMMDevReq_GetMouseStatusEx: + return sizeof(VMMDevReqMouseStatusEx); + case VMMDevReq_SetPointerShape: + return sizeof(VMMDevReqMousePointer); + case VMMDevReq_GetHostVersion: + return sizeof(VMMDevReqHostVersion); + case VMMDevReq_Idle: + return sizeof(VMMDevReqIdle); + case VMMDevReq_GetHostTime: + return sizeof(VMMDevReqHostTime); + case VMMDevReq_GetHypervisorInfo: + case VMMDevReq_SetHypervisorInfo: + return sizeof(VMMDevReqHypervisorInfo); + case VMMDevReq_RegisterPatchMemory: + case VMMDevReq_DeregisterPatchMemory: + return sizeof(VMMDevReqPatchMemory); + case VMMDevReq_SetPowerStatus: + return sizeof(VMMDevPowerStateRequest); + case VMMDevReq_AcknowledgeEvents: + return sizeof(VMMDevEvents); + case VMMDevReq_ReportGuestInfo: + return sizeof(VMMDevReportGuestInfo); + case VMMDevReq_ReportGuestInfo2: + return sizeof(VMMDevReportGuestInfo2); + case VMMDevReq_ReportGuestStatus: + return sizeof(VMMDevReportGuestStatus); + case VMMDevReq_ReportGuestUserState: + return sizeof(VMMDevReportGuestUserState); + case VMMDevReq_GetDisplayChangeRequest: + return sizeof(VMMDevDisplayChangeRequest); + case VMMDevReq_GetDisplayChangeRequest2: + return sizeof(VMMDevDisplayChangeRequest2); + case VMMDevReq_GetDisplayChangeRequestEx: + return sizeof(VMMDevDisplayChangeRequestEx); + case VMMDevReq_GetDisplayChangeRequestMulti: + return RT_UOFFSETOF(VMMDevDisplayChangeRequestMulti, aDisplays[0]); + case VMMDevReq_VideoModeSupported: + return sizeof(VMMDevVideoModeSupportedRequest); + case VMMDevReq_GetHeightReduction: + return sizeof(VMMDevGetHeightReductionRequest); + case VMMDevReq_ReportGuestCapabilities: + return sizeof(VMMDevReqGuestCapabilities); + case VMMDevReq_SetGuestCapabilities: + return sizeof(VMMDevReqGuestCapabilities2); +#ifdef VBOX_WITH_HGCM + case VMMDevReq_HGCMConnect: + return sizeof(VMMDevHGCMConnect); + case VMMDevReq_HGCMDisconnect: + return sizeof(VMMDevHGCMDisconnect); + case VMMDevReq_HGCMCall32: + return sizeof(VMMDevHGCMCall); +# ifdef VBOX_WITH_64_BITS_GUESTS + case VMMDevReq_HGCMCall64: + return sizeof(VMMDevHGCMCall); +# endif + case VMMDevReq_HGCMCancel: + return sizeof(VMMDevHGCMCancel); +#endif /* VBOX_WITH_HGCM */ + case VMMDevReq_VideoAccelEnable: + return sizeof(VMMDevVideoAccelEnable); + case VMMDevReq_VideoAccelFlush: + return sizeof(VMMDevVideoAccelFlush); + case VMMDevReq_VideoSetVisibleRegion: + /* The original protocol didn't consider a guest with NO visible + * windows */ + return sizeof(VMMDevVideoSetVisibleRegion) - sizeof(RTRECT); + case VMMDevReq_GetSeamlessChangeRequest: + return sizeof(VMMDevSeamlessChangeRequest); + case VMMDevReq_QueryCredentials: + return sizeof(VMMDevCredentials); + case VMMDevReq_ReportGuestStats: + return sizeof(VMMDevReportGuestStats); + case VMMDevReq_GetMemBalloonChangeRequest: + return sizeof(VMMDevGetMemBalloonChangeRequest); + case VMMDevReq_GetStatisticsChangeRequest: + return sizeof(VMMDevGetStatisticsChangeRequest); + case VMMDevReq_ChangeMemBalloon: + return sizeof(VMMDevChangeMemBalloon); + case VMMDevReq_GetVRDPChangeRequest: + return sizeof(VMMDevVRDPChangeRequest); + case VMMDevReq_LogString: + return sizeof(VMMDevReqLogString); + case VMMDevReq_CtlGuestFilterMask: + return sizeof(VMMDevCtlGuestFilterMask); + case VMMDevReq_GetCpuHotPlugRequest: + return sizeof(VMMDevGetCpuHotPlugRequest); + case VMMDevReq_SetCpuHotPlugStatus: + return sizeof(VMMDevCpuHotPlugStatusRequest); + case VMMDevReq_RegisterSharedModule: + return sizeof(VMMDevSharedModuleRegistrationRequest); + case VMMDevReq_UnregisterSharedModule: + return sizeof(VMMDevSharedModuleUnregistrationRequest); + case VMMDevReq_CheckSharedModules: + return sizeof(VMMDevSharedModuleCheckRequest); + case VMMDevReq_GetPageSharingStatus: + return sizeof(VMMDevPageSharingStatusRequest); + case VMMDevReq_DebugIsPageShared: + return sizeof(VMMDevPageIsSharedRequest); + case VMMDevReq_GetSessionId: + return sizeof(VMMDevReqSessionId); + case VMMDevReq_HeartbeatConfigure: + return sizeof(VMMDevReqHeartbeat); + case VMMDevReq_GuestHeartbeat: + return sizeof(VMMDevRequestHeader); + case VMMDevReq_VideoUpdateMonitorPositions: + return sizeof(VMMDevVideoUpdateMonitorPositions); + default: + break; + } + + return 0; +} + + +/** + * Initializes a request structure. + * + * @returns VBox status code. + * @param req The request structure to initialize. + * @param type The request type. + */ +DECLINLINE(int) vmmdevInitRequest(VMMDevRequestHeader *req, VMMDevRequestType type) +{ + uint32_t requestSize; + if (!req) + return VERR_INVALID_PARAMETER; + requestSize = (uint32_t)vmmdevGetRequestSize(type); + if (!requestSize) + return VERR_INVALID_PARAMETER; + req->size = requestSize; + req->version = VMMDEV_REQUEST_HEADER_VERSION; + req->requestType = type; + req->rc = VERR_GENERAL_FAILURE; + req->reserved1 = 0; + req->fRequestor = 0; + return VINF_SUCCESS; +} + + +/** @name VBVA ring defines. + * + * The VBVA ring buffer is suitable for transferring large (< 2GB) amount of + * data. For example big bitmaps which do not fit to the buffer. + * + * Guest starts writing to the buffer by initializing a record entry in the + * aRecords queue. VBVA_F_RECORD_PARTIAL indicates that the record is being + * written. As data is written to the ring buffer, the guest increases off32End + * for the record. + * + * The host reads the aRecords on flushes and processes all completed records. + * When host encounters situation when only a partial record presents and + * cbRecord & ~VBVA_F_RECORD_PARTIAL >= VBVA_RING_BUFFER_SIZE - + * VBVA_RING_BUFFER_THRESHOLD, the host fetched all record data and updates + * off32Head. After that on each flush the host continues fetching the data + * until the record is completed. + * + * @{ */ +#define VMMDEV_VBVA_RING_BUFFER_SIZE (_4M - _1K) +#define VMMDEV_VBVA_RING_BUFFER_THRESHOLD (4 * _1K) + +#define VMMDEV_VBVA_MAX_RECORDS (64) +/** @} */ + +/** + * VBVA record. + */ +typedef struct VMMDEVVBVARECORD +{ + /** The length of the record. Changed by guest. */ + uint32_t cbRecord; +} VMMDEVVBVARECORD; +AssertCompileSize(VMMDEVVBVARECORD, 4); + +#if ARCH_BITS >= 32 + +/** + * VBVA memory layout. + * + * This is a subsection of the VMMDevMemory structure. + */ +typedef struct VBVAMEMORY +{ + /** VBVA_F_MODE_*. */ + uint32_t fu32ModeFlags; + + /** The offset where the data start in the buffer. */ + uint32_t off32Data; + /** The offset where next data must be placed in the buffer. */ + uint32_t off32Free; + + /** The ring buffer for data. */ + uint8_t au8RingBuffer[VMMDEV_VBVA_RING_BUFFER_SIZE]; + + /** The queue of record descriptions. */ + VMMDEVVBVARECORD aRecords[VMMDEV_VBVA_MAX_RECORDS]; + uint32_t indexRecordFirst; + uint32_t indexRecordFree; + + /** RDP orders supported by the client. The guest reports only them + * and falls back to DIRTY rects for not supported ones. + * + * (1 << VBVA_VRDP_*) + */ + uint32_t fu32SupportedOrders; + +} VBVAMEMORY; +AssertCompileSize(VBVAMEMORY, 12 + (_4M-_1K) + 4*64 + 12); + + +/** + * The layout of VMMDEV RAM region that contains information for guest. + */ +typedef struct VMMDevMemory +{ + /** The size of this structure. */ + uint32_t u32Size; + /** The structure version. (VMMDEV_MEMORY_VERSION) */ + uint32_t u32Version; + + union + { + struct + { + /** Flag telling that VMMDev set the IRQ and acknowlegment is required */ + bool fHaveEvents; + } V1_04; + + struct + { + /** Pending events flags, set by host. */ + uint32_t u32HostEvents; + /** Mask of events the guest wants to see, set by guest. */ + uint32_t u32GuestEventMask; + } V1_03; + } V; + + VBVAMEMORY vbvaMemory; + +} VMMDevMemory; +AssertCompileSize(VMMDevMemory, 8+8 + (12 + (_4M-_1K) + 4*64 + 12) ); +AssertCompileMemberOffset(VMMDevMemory, vbvaMemory, 16); + +/** Version of VMMDevMemory structure (VMMDevMemory::u32Version). */ +# define VMMDEV_MEMORY_VERSION (1) + +#endif /* ARCH_BITS >= 32 */ + +/** @} */ + +/** @} */ +RT_C_DECLS_END +#pragma pack() + +#endif /* !VBOX_INCLUDED_VMMDev_h */ diff --git a/include/VBox/VMMDevCoreTypes.h b/include/VBox/VMMDevCoreTypes.h new file mode 100644 index 00000000..e1d8aef3 --- /dev/null +++ b/include/VBox/VMMDevCoreTypes.h @@ -0,0 +1,556 @@ +/** @file + * Virtual Device for Guest <-> VMM/Host communication, Core Types. (ADD,DEV) + * + * These types are needed by several headers VBoxGuestLib.h and are kept + * separate to avoid having to include the whole VMMDev.h fun. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_VMMDevCoreTypes_h +#define VBOX_INCLUDED_VMMDevCoreTypes_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#ifdef __cplusplus +# include +# include +#endif + + +/** @addtogroup grp_vmmdev + * @{ + */ + +/* Helpful forward declarations: */ +struct VMMDevRequestHeader; +struct VMMDevReqMousePointer; +struct VMMDevMemory; + + +/** @name VMMDev events. + * + * Used mainly by VMMDevReq_AcknowledgeEvents/VMMDevEvents and version 1.3 of + * VMMDevMemory. + * + * @{ + */ +/** Host mouse capabilities has been changed. */ +#define VMMDEV_EVENT_MOUSE_CAPABILITIES_CHANGED RT_BIT(0) +/** HGCM event. */ +#define VMMDEV_EVENT_HGCM RT_BIT(1) +/** A display change request has been issued. */ +#define VMMDEV_EVENT_DISPLAY_CHANGE_REQUEST RT_BIT(2) +/** Credentials are available for judgement. */ +#define VMMDEV_EVENT_JUDGE_CREDENTIALS RT_BIT(3) +/** The guest has been restored. */ +#define VMMDEV_EVENT_RESTORED RT_BIT(4) +/** Seamless mode state changed. */ +#define VMMDEV_EVENT_SEAMLESS_MODE_CHANGE_REQUEST RT_BIT(5) +/** Memory balloon size changed. */ +#define VMMDEV_EVENT_BALLOON_CHANGE_REQUEST RT_BIT(6) +/** Statistics interval changed. */ +#define VMMDEV_EVENT_STATISTICS_INTERVAL_CHANGE_REQUEST RT_BIT(7) +/** VRDP status changed. */ +#define VMMDEV_EVENT_VRDP RT_BIT(8) +/** New mouse position data available. */ +#define VMMDEV_EVENT_MOUSE_POSITION_CHANGED RT_BIT(9) +/** CPU hotplug event occurred. */ +#define VMMDEV_EVENT_CPU_HOTPLUG RT_BIT(10) +/** The mask of valid events, for sanity checking. */ +#define VMMDEV_EVENT_VALID_EVENT_MASK UINT32_C(0x000007ff) +/** @} */ + + +/** @name The ballooning chunk size which VMMDev works at. + * @{ */ +#define VMMDEV_MEMORY_BALLOON_CHUNK_PAGES (_1M/4096) +#define VMMDEV_MEMORY_BALLOON_CHUNK_SIZE (VMMDEV_MEMORY_BALLOON_CHUNK_PAGES*4096) +/** @} */ + + +/** + * Seamless mode. + * + * Used by VbglR3SeamlessWaitEvent + * + * @ingroup grp_vmmdev_req + */ +typedef enum +{ + VMMDev_Seamless_Disabled = 0, /**< normal mode; entire guest desktop displayed. */ + VMMDev_Seamless_Visible_Region = 1, /**< visible region mode; only top-level guest windows displayed. */ + VMMDev_Seamless_Host_Window = 2, /**< windowed mode; each top-level guest window is represented in a host window. */ + VMMDev_Seamless_SizeHack = 0x7fffffff +} VMMDevSeamlessMode; +AssertCompileSize(VMMDevSeamlessMode, 4); + + +/** + * CPU event types. + * + * Used by VbglR3CpuHotplugWaitForEvent + * + * @ingroup grp_vmmdev_req + */ +typedef enum +{ + VMMDevCpuEventType_Invalid = 0, + VMMDevCpuEventType_None = 1, + VMMDevCpuEventType_Plug = 2, + VMMDevCpuEventType_Unplug = 3, + VMMDevCpuEventType_SizeHack = 0x7fffffff +} VMMDevCpuEventType; +AssertCompileSize(VMMDevCpuEventType, 4); + + +/** @name Guest capability bits. + * Used by VMMDevReq_ReportGuestCapabilities and VMMDevReq_SetGuestCapabilities. + * @{ */ +/** The guest supports seamless display rendering. */ +#define VMMDEV_GUEST_SUPPORTS_SEAMLESS RT_BIT_32(0) +/** The guest supports mapping guest to host windows. */ +#define VMMDEV_GUEST_SUPPORTS_GUEST_HOST_WINDOW_MAPPING RT_BIT_32(1) +/** The guest graphical additions are active. + * Used for fast activation and deactivation of certain graphical operations + * (e.g. resizing & seamless). The legacy VMMDevReq_ReportGuestCapabilities + * request sets this automatically, but VMMDevReq_SetGuestCapabilities does + * not. */ +#define VMMDEV_GUEST_SUPPORTS_GRAPHICS RT_BIT_32(2) +/** The mask of valid events, for sanity checking. */ +#define VMMDEV_GUEST_CAPABILITIES_MASK UINT32_C(0x00000007) +/** @} */ + + +/** + * The guest facility. + * This needs to be kept in sync with AdditionsFacilityType of the Main API! + */ +typedef enum +{ + VBoxGuestFacilityType_Unknown = 0, + VBoxGuestFacilityType_VBoxGuestDriver = 20, + VBoxGuestFacilityType_AutoLogon = 90, /* VBoxGINA / VBoxCredProv / pam_vbox. */ + VBoxGuestFacilityType_VBoxService = 100, + VBoxGuestFacilityType_VBoxTrayClient = 101, /* VBoxTray (Windows), VBoxClient (Linux, Unix). */ + VBoxGuestFacilityType_Seamless = 1000, + VBoxGuestFacilityType_Graphics = 1100, + VBoxGuestFacilityType_MonitorAttach = 1101, + VBoxGuestFacilityType_All = 0x7ffffffe, + VBoxGuestFacilityType_SizeHack = 0x7fffffff +} VBoxGuestFacilityType; +AssertCompileSize(VBoxGuestFacilityType, 4); + + +/** + * The current guest status of a facility. + * This needs to be kept in sync with AdditionsFacilityStatus of the Main API! + * + * @remarks r=bird: Pretty please, for future types like this, simply do a + * linear allocation without any gaps. This stuff is impossible work + * efficiently with, let alone validate. Applies to the other facility + * enums too. + */ +typedef enum +{ + VBoxGuestFacilityStatus_Inactive = 0, + VBoxGuestFacilityStatus_Paused = 1, + VBoxGuestFacilityStatus_PreInit = 20, + VBoxGuestFacilityStatus_Init = 30, + VBoxGuestFacilityStatus_Active = 50, + VBoxGuestFacilityStatus_Terminating = 100, + VBoxGuestFacilityStatus_Terminated = 101, + VBoxGuestFacilityStatus_Failed = 800, + VBoxGuestFacilityStatus_Unknown = 999, + VBoxGuestFacilityStatus_SizeHack = 0x7fffffff +} VBoxGuestFacilityStatus; +AssertCompileSize(VBoxGuestFacilityStatus, 4); + + +/** + * The current status of specific guest user. + * This needs to be kept in sync with GuestUserState of the Main API! + */ +typedef enum VBoxGuestUserState +{ + VBoxGuestUserState_Unknown = 0, + VBoxGuestUserState_LoggedIn = 1, + VBoxGuestUserState_LoggedOut = 2, + VBoxGuestUserState_Locked = 3, + VBoxGuestUserState_Unlocked = 4, + VBoxGuestUserState_Disabled = 5, + VBoxGuestUserState_Idle = 6, + VBoxGuestUserState_InUse = 7, + VBoxGuestUserState_Created = 8, + VBoxGuestUserState_Deleted = 9, + VBoxGuestUserState_SessionChanged = 10, + VBoxGuestUserState_CredentialsChanged = 11, + VBoxGuestUserState_RoleChanged = 12, + VBoxGuestUserState_GroupAdded = 13, + VBoxGuestUserState_GroupRemoved = 14, + VBoxGuestUserState_Elevated = 15, + VBoxGuestUserState_SizeHack = 0x7fffffff +} VBoxGuestUserState; +AssertCompileSize(VBoxGuestUserState, 4); + + + +/** + * HGCM service location types. + * @ingroup grp_vmmdev_req + */ +typedef enum +{ + VMMDevHGCMLoc_Invalid = 0, + VMMDevHGCMLoc_LocalHost = 1, + VMMDevHGCMLoc_LocalHost_Existing = 2, + VMMDevHGCMLoc_SizeHack = 0x7fffffff +} HGCMServiceLocationType; +AssertCompileSize(HGCMServiceLocationType, 4); + +/** + * HGCM host service location. + * @ingroup grp_vmmdev_req + */ +typedef struct +{ + char achName[128]; /**< This is really szName. */ +} HGCMServiceLocationHost; +AssertCompileSize(HGCMServiceLocationHost, 128); + +/** + * HGCM service location. + * @ingroup grp_vmmdev_req + */ +typedef struct HGCMSERVICELOCATION +{ + /** Type of the location. */ + HGCMServiceLocationType type; + + union + { + HGCMServiceLocationHost host; + } u; +} HGCMServiceLocation; +AssertCompileSize(HGCMServiceLocation, 128+4); + + +/** + * HGCM parameter type. + */ +typedef enum +{ + VMMDevHGCMParmType_Invalid = 0, + VMMDevHGCMParmType_32bit = 1, + VMMDevHGCMParmType_64bit = 2, + VMMDevHGCMParmType_PhysAddr = 3, /**< @deprecated Doesn't work, use PageList. */ + VMMDevHGCMParmType_LinAddr = 4, /**< In and Out */ + VMMDevHGCMParmType_LinAddr_In = 5, /**< In (read; host<-guest) */ + VMMDevHGCMParmType_LinAddr_Out = 6, /**< Out (write; host->guest) */ + VMMDevHGCMParmType_LinAddr_Locked = 7, /**< Locked In and Out - for VBoxGuest, not host. */ + VMMDevHGCMParmType_LinAddr_Locked_In = 8, /**< Locked In (read; host<-guest) - for VBoxGuest, not host. */ + VMMDevHGCMParmType_LinAddr_Locked_Out = 9, /**< Locked Out (write; host->guest) - for VBoxGuest, not host. */ + VMMDevHGCMParmType_PageList = 10, /**< Physical addresses of locked pages for a buffer. */ + VMMDevHGCMParmType_Embedded = 11, /**< Small buffer embedded in request. */ + VMMDevHGCMParmType_ContiguousPageList = 12, /**< Like PageList but with physically contiguous memory, so only one page entry. */ + VMMDevHGCMParmType_NoBouncePageList = 13, /**< Like PageList but host function requires no bounce buffering. */ + VMMDevHGCMParmType_SizeHack = 0x7fffffff +} HGCMFunctionParameterType; +AssertCompileSize(HGCMFunctionParameterType, 4); + + +# ifdef VBOX_WITH_64_BITS_GUESTS +/** + * HGCM function parameter, 32-bit client. + */ +# pragma pack(4) /* We force structure dword packing here for hysterical raisins. Saves us 4 bytes, at the cost of + misaligning the value64 member of every other parameter structure. */ +typedef struct HGCMFunctionParameter32 +{ + HGCMFunctionParameterType type; + union + { + uint32_t value32; + uint64_t value64; + struct + { + uint32_t size; + + union + { + RTGCPHYS32 physAddr; + RTGCPTR32 linearAddr; + } u; + } Pointer; + struct + { + uint32_t cb; + RTGCPTR32 uAddr; + } LinAddr; /**< Shorter version of the above Pointer structure. */ + struct + { + uint32_t size; /**< Size of the buffer described by the page list. */ + uint32_t offset; /**< Relative to the request header of a HGCMPageListInfo structure, valid if size != 0. */ + } PageList; + struct + { + uint32_t fFlags : 8; /**< VBOX_HGCM_F_PARM_*. */ + uint32_t offData : 24; /**< Relative to the request header, valid if cb != 0. */ + uint32_t cbData; /**< The buffer size. */ + } Embedded; + } u; +# ifdef __cplusplus + void SetUInt32(uint32_t u32) + { + type = VMMDevHGCMParmType_32bit; + u.value64 = 0; /* init unused bits to 0 */ + u.value32 = u32; + } + + int GetUInt32(uint32_t RT_FAR *pu32) + { + if (type == VMMDevHGCMParmType_32bit) + { + *pu32 = u.value32; + return VINF_SUCCESS; + } + return VERR_INVALID_PARAMETER; + } + + void SetUInt64(uint64_t u64) + { + type = VMMDevHGCMParmType_64bit; + u.value64 = u64; + } + + int GetUInt64(uint64_t RT_FAR *pu64) + { + if (type == VMMDevHGCMParmType_64bit) + { + *pu64 = u.value64; + return VINF_SUCCESS; + } + return VERR_INVALID_PARAMETER; + } + + void SetPtr(void RT_FAR *pv, uint32_t cb) + { + type = VMMDevHGCMParmType_LinAddr; + u.Pointer.size = cb; + u.Pointer.u.linearAddr = (RTGCPTR32)(uintptr_t)pv; + } +# endif /* __cplusplus */ +} HGCMFunctionParameter32; +# pragma pack() +AssertCompileSize(HGCMFunctionParameter32, 4+8); + +/** + * HGCM function parameter, 64-bit client. + */ +# pragma pack(4)/* We force structure dword packing here for hysterical raisins. Saves us 4 bytes, + at the cost of misaligning the value64 members. */ +typedef struct HGCMFunctionParameter64 +{ + HGCMFunctionParameterType type; + union + { + uint32_t value32; + uint64_t value64; + struct + { + uint32_t size; + + union + { + RTGCPHYS64 physAddr; + RTGCPTR64 linearAddr; + } u; + } Pointer; + struct + { + uint32_t cb; + RTGCPTR64 uAddr; + } LinAddr; /**< Shorter version of the above Pointer structure. */ + struct + { + uint32_t size; /**< Size of the buffer described by the page list. */ + uint32_t offset; /**< Relative to the request header, valid if size != 0. */ + } PageList; + struct + { + uint32_t fFlags : 8; /**< VBOX_HGCM_F_PARM_*. */ + uint32_t offData : 24; /**< Relative to the request header, valid if cb != 0. */ + uint32_t cbData; /**< The buffer size. */ + } Embedded; + } u; +# ifdef __cplusplus + void SetUInt32(uint32_t u32) + { + type = VMMDevHGCMParmType_32bit; + u.value64 = 0; /* init unused bits to 0 */ + u.value32 = u32; + } + + int GetUInt32(uint32_t RT_FAR *pu32) + { + if (type == VMMDevHGCMParmType_32bit) + { + *pu32 = u.value32; + return VINF_SUCCESS; + } + return VERR_INVALID_PARAMETER; + } + + void SetUInt64(uint64_t u64) + { + type = VMMDevHGCMParmType_64bit; + u.value64 = u64; + } + + int GetUInt64(uint64_t RT_FAR *pu64) + { + if (type == VMMDevHGCMParmType_64bit) + { + *pu64 = u.value64; + return VINF_SUCCESS; + } + return VERR_INVALID_PARAMETER; + } + + void SetPtr(void RT_FAR *pv, uint32_t cb) + { + type = VMMDevHGCMParmType_LinAddr; + u.Pointer.size = cb; + u.Pointer.u.linearAddr = (uintptr_t)pv; + } +# endif /** __cplusplus */ +} HGCMFunctionParameter64; +# pragma pack() +AssertCompileSize(HGCMFunctionParameter64, 4+12); + +/* Redefine the structure type for the guest code. */ +# ifndef VBOX_HGCM_HOST_CODE +# if ARCH_BITS == 64 +# define HGCMFunctionParameter HGCMFunctionParameter64 +# elif ARCH_BITS == 32 || ARCH_BITS == 16 +# define HGCMFunctionParameter HGCMFunctionParameter32 +# else +# error "Unsupported sizeof (void *)" +# endif +# endif /* !VBOX_HGCM_HOST_CODE */ + +# else /* !VBOX_WITH_64_BITS_GUESTS */ + +/** + * HGCM function parameter, 32-bit client. + * + * @todo If this is the same as HGCMFunctionParameter32, why the duplication? + */ +# pragma pack(4) /* We force structure dword packing here for hysterical raisins. Saves us 4 bytes, at the cost of + misaligning the value64 member of every other parameter structure. */ +typedef struct +{ + HGCMFunctionParameterType type; + union + { + uint32_t value32; + uint64_t value64; + struct + { + uint32_t size; + + union + { + RTGCPHYS32 physAddr; + RTGCPTR32 linearAddr; + } u; + } Pointer; + struct + { + uint32_t cb; + RTGCPTR32 uAddr; + } LinAddr; /**< Shorter version of the above Pointer structure. */ + struct + { + uint32_t size; /**< Size of the buffer described by the page list. */ + uint32_t offset; /**< Relative to the request header, valid if size != 0. */ + } PageList; + struct + { + uint32_t fFlags : 8; /**< VBOX_HGCM_F_PARM_*. */ + uint32_t offData : 24; /**< Relative to the request header (must be a valid offset even if cbData is zero). */ + uint32_t cbData; /**< The buffer size. */ + } Embedded; + } u; +# ifdef __cplusplus + void SetUInt32(uint32_t u32) + { + type = VMMDevHGCMParmType_32bit; + u.value64 = 0; /* init unused bits to 0 */ + u.value32 = u32; + } + + int GetUInt32(uint32_t *pu32) + { + AssertMsgReturnStmt(type == VMMDevHGCMParmType_32bit, ("type=-%d\n", type), + *pu32 = UINT32_MAX /* shut up gcc */, VERR_WRONG_PARAMETER_TYPE) + *pu32 = u.value32; + return VINF_SUCCESS; + } + + void SetUInt64(uint64_t u64) + { + type = VMMDevHGCMParmType_64bit; + u.value64 = u64; + } + + int GetUInt64(uint64_t *pu64) + { + AssertMsgReturnStmt(type == VMMDevHGCMParmType_64bit, ("type=%d\n", type), + *pu64 = UINT32_MAX /* shut up gcc */, VERR_WRONG_PARAMETER_TYPE); + *pu64 = u.value64; + return VINF_SUCCESS; + } + + void SetPtr(void *pv, uint32_t cb) + { + type = VMMDevHGCMParmType_LinAddr; + u.Pointer.size = cb; + u.Pointer.u.linearAddr = (uintptr_t)pv; + } +# endif /* __cplusplus */ +} HGCMFunctionParameter; +# pragma pack() +AssertCompileSize(HGCMFunctionParameter, 4+8); +# endif /* !VBOX_WITH_64_BITS_GUESTS */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_VMMDevCoreTypes_h */ + diff --git a/include/VBox/VMMDevTesting.h b/include/VBox/VMMDevTesting.h new file mode 100644 index 00000000..d68d9c1b --- /dev/null +++ b/include/VBox/VMMDevTesting.h @@ -0,0 +1,272 @@ +/* $Id: VMMDevTesting.h $ */ +/** @file + * VMMDev - Testing Extensions. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_VMMDevTesting_h +#define VBOX_INCLUDED_VMMDevTesting_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/** @defgroup grp_vmmdev_testing VMM Device Testing + * @ingroup grp_vmmdev + * @{ + */ + +/** The base address of the MMIO range used for testing. + * @remarks This used to be at 0x101000 but moved to 0xdf000 so that it would + * work better with prototype NEM code. This also means enabling A20 + * is not a requirement. */ +#define VMMDEV_TESTING_MMIO_BASE UINT32_C(0x000df000) +/** The size of the MMIO range used for testing. */ +#define VMMDEV_TESTING_MMIO_SIZE UINT32_C(0x00001000) + +/** MMIO offset: The NOP register - 1248 RW. */ +#define VMMDEV_TESTING_MMIO_OFF_NOP (0x000) +/** MMIO offset: The go-to-ring-3-NOP register - 1248 RW. */ +#define VMMDEV_TESTING_MMIO_OFF_NOP_R3 (0x008) +/** MMIO offset: The readback registers - 64 bytes of read/write "memory". */ +#define VMMDEV_TESTING_MMIO_OFF_READBACK (0x040) +/** MMIO offset: Readback register view that always goes to ring-3. */ +#define VMMDEV_TESTING_MMIO_OFF_READBACK_R3 (0x080) +/** The size of the MMIO readback registers. */ +#define VMMDEV_TESTING_READBACK_SIZE (0x40) + +/** Default address of VMMDEV_TESTING_MMIO_OFF_NOP. */ +#define VMMDEV_TESTING_MMIO_NOP (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_NOP) +/** Default address of VMMDEV_TESTING_MMIO_OFF_NOP_R3. */ +#define VMMDEV_TESTING_MMIO_NOP_R3 (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_NOP_R3) +/** Default address of VMMDEV_TESTING_MMIO_OFF_READBACK. */ +#define VMMDEV_TESTING_MMIO_READBACK (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_READBACK) +/** Default address of VMMDEV_TESTING_MMIO_OFF_READBACK_R3. */ +#define VMMDEV_TESTING_MMIO_READBACK_R3 (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_READBACK_R3) + +/** The real mode selector to use. */ +#define VMMDEV_TESTING_MMIO_RM_SEL 0xdf00 +/** Calculate the real mode offset of a MMIO register. */ +#define VMMDEV_TESTING_MMIO_RM_OFF(val) ((val) - VMMDEV_TESTING_MMIO_BASE) +/** Calculate the real mode offset of a MMIO register offset. */ +#define VMMDEV_TESTING_MMIO_RM_OFF2(off) (off) + +/** The base port of the I/O range used for testing. */ +#define VMMDEV_TESTING_IOPORT_BASE 0x0510 +/** The number of I/O ports reserved for testing. */ +#define VMMDEV_TESTING_IOPORT_COUNT 0x0010 +/** The NOP I/O port - 1,2,4 RW. */ +#define VMMDEV_TESTING_IOPORT_NOP (VMMDEV_TESTING_IOPORT_BASE + 0) +/** The low nanosecond timestamp - 4 RO. */ +#define VMMDEV_TESTING_IOPORT_TS_LOW (VMMDEV_TESTING_IOPORT_BASE + 1) +/** The high nanosecond timestamp - 4 RO. Read this after the low one! */ +#define VMMDEV_TESTING_IOPORT_TS_HIGH (VMMDEV_TESTING_IOPORT_BASE + 2) +/** Command register usually used for preparing the data register - 4/2 WO. */ +#define VMMDEV_TESTING_IOPORT_CMD (VMMDEV_TESTING_IOPORT_BASE + 3) +/** Data register which use depends on the current command - 1s, 4 WO. */ +#define VMMDEV_TESTING_IOPORT_DATA (VMMDEV_TESTING_IOPORT_BASE + 4) +/** The go-to-ring-3-NOP I/O port - 1,2,4 RW. */ +#define VMMDEV_TESTING_IOPORT_NOP_R3 (VMMDEV_TESTING_IOPORT_BASE + 5) +/** Take the VMMDev lock in arrival context and return - 1,2,4 RW. + * Writing configures counter action by a thread taking the lock to trigger + * contention: + * - bits 15:0: Number of microseconds thread should hold lock. + * - bits 31:16: Number of microseconds thread should wait before locking + * again. */ +#define VMMDEV_TESTING_IOPORT_LOCKED_LO (VMMDEV_TESTING_IOPORT_BASE + 6) +/** Take the VMMDev lock in arrival context and return - 1,2,4 RW. + * Writing configures counter action by a thread taking the lock to trigger + * contention: + * - bits 19:0: Number of kilo (1024) ticks the EMT should hold lock. + * - bits 25:20: Reserved, must be zero. + * - bit 26: Thread takes lock in shared mode when set, exclusive when clear. + * - bit 27: EMT takes lock in shared mode when set, exclusive when clear. + * - bit 28: Use read/write critical section when set, device section if clear. + * - bit 29: EMT passes VINF_SUCCESS as rcBusy when set. + * - bit 30: Makes thread poke all EMTs before release lock. + * - bit 31: Enables the thread. */ +#define VMMDEV_TESTING_IOPORT_LOCKED_HI (VMMDEV_TESTING_IOPORT_BASE + 7) + +/** @name Commands. + * @{ */ +/** Initialize test, sending name (zero terminated string). (RTTestCreate) */ +#define VMMDEV_TESTING_CMD_INIT UINT32_C(0xcab1e000) +/** Test done, sending 32-bit total error count with it. (RTTestSummaryAndDestroy) */ +#define VMMDEV_TESTING_CMD_TERM UINT32_C(0xcab1e001) +/** Start a new sub-test, sending name (zero terminated string). (RTTestSub) */ +#define VMMDEV_TESTING_CMD_SUB_NEW UINT32_C(0xcab1e002) +/** Sub-test is done, sending 32-bit error count for it. (RTTestDone) */ +#define VMMDEV_TESTING_CMD_SUB_DONE UINT32_C(0xcab1e003) +/** Report a failure, sending reason (zero terminated string). (RTTestFailed) */ +#define VMMDEV_TESTING_CMD_FAILED UINT32_C(0xcab1e004) +/** Report a value, sending the 64-bit value (2x4), the 32-bit unit (4), and + * finally the name (zero terminated string). (RTTestValue) */ +#define VMMDEV_TESTING_CMD_VALUE UINT32_C(0xcab1e005) +/** Report a failure, sending reason (zero terminated string). (RTTestSkipped) */ +#define VMMDEV_TESTING_CMD_SKIPPED UINT32_C(0xcab1e006) +/** Report a value found in a VMM register, sending a string on the form + * "value-name:register-name". */ +#define VMMDEV_TESTING_CMD_VALUE_REG UINT32_C(0xcab1e007) +/** Print string, sending a string including newline. (RTTestPrintf) */ +#define VMMDEV_TESTING_CMD_PRINT UINT32_C(0xcab1e008) +/** Query a config value, sending a 16-bit word (VMMDEV_TESTING_CFG_XXX) to the + * DATA port and reading back the result. */ +#define VMMDEV_TESTING_CMD_QUERY_CFG UINT32_C(0xcab1e009) + +/** The magic part of the command. */ +#define VMMDEV_TESTING_CMD_MAGIC UINT32_C(0xcab1e000) +/** The magic part of the command. */ +#define VMMDEV_TESTING_CMD_MAGIC_MASK UINT32_C(0xffffff00) +/** The magic high word automatically supplied to 16-bit CMD writes. */ +#define VMMDEV_TESTING_CMD_MAGIC_HI_WORD UINT32_C(0xcab10000) +/** @} */ + +/** @name Value units + * @note Same as RTTESTUNIT, see rules here for adding new units. + * @{ */ +#define VMMDEV_TESTING_UNIT_PCT UINT8_C(0x01) /**< Percentage. */ +#define VMMDEV_TESTING_UNIT_BYTES UINT8_C(0x02) /**< Bytes. */ +#define VMMDEV_TESTING_UNIT_BYTES_PER_SEC UINT8_C(0x03) /**< Bytes per second. */ +#define VMMDEV_TESTING_UNIT_KILOBYTES UINT8_C(0x04) /**< Kilobytes. */ +#define VMMDEV_TESTING_UNIT_KILOBYTES_PER_SEC UINT8_C(0x05) /**< Kilobytes per second. */ +#define VMMDEV_TESTING_UNIT_MEGABYTES UINT8_C(0x06) /**< Megabytes. */ +#define VMMDEV_TESTING_UNIT_MEGABYTES_PER_SEC UINT8_C(0x07) /**< Megabytes per second. */ +#define VMMDEV_TESTING_UNIT_PACKETS UINT8_C(0x08) /**< Packets. */ +#define VMMDEV_TESTING_UNIT_PACKETS_PER_SEC UINT8_C(0x09) /**< Packets per second. */ +#define VMMDEV_TESTING_UNIT_FRAMES UINT8_C(0x0a) /**< Frames. */ +#define VMMDEV_TESTING_UNIT_FRAMES_PER_SEC UINT8_C(0x0b) /**< Frames per second. */ +#define VMMDEV_TESTING_UNIT_OCCURRENCES UINT8_C(0x0c) /**< Occurrences. */ +#define VMMDEV_TESTING_UNIT_OCCURRENCES_PER_SEC UINT8_C(0x0d) /**< Occurrences per second. */ +#define VMMDEV_TESTING_UNIT_CALLS UINT8_C(0x0e) /**< Calls. */ +#define VMMDEV_TESTING_UNIT_CALLS_PER_SEC UINT8_C(0x0f) /**< Calls per second. */ +#define VMMDEV_TESTING_UNIT_ROUND_TRIP UINT8_C(0x10) /**< Round trips. */ +#define VMMDEV_TESTING_UNIT_SECS UINT8_C(0x11) /**< Seconds. */ +#define VMMDEV_TESTING_UNIT_MS UINT8_C(0x12) /**< Milliseconds. */ +#define VMMDEV_TESTING_UNIT_NS UINT8_C(0x13) /**< Nanoseconds. */ +#define VMMDEV_TESTING_UNIT_NS_PER_CALL UINT8_C(0x14) /**< Nanoseconds per call. */ +#define VMMDEV_TESTING_UNIT_NS_PER_FRAME UINT8_C(0x15) /**< Nanoseconds per frame. */ +#define VMMDEV_TESTING_UNIT_NS_PER_OCCURRENCE UINT8_C(0x16) /**< Nanoseconds per occurrence. */ +#define VMMDEV_TESTING_UNIT_NS_PER_PACKET UINT8_C(0x17) /**< Nanoseconds per frame. */ +#define VMMDEV_TESTING_UNIT_NS_PER_ROUND_TRIP UINT8_C(0x18) /**< Nanoseconds per round trip. */ +#define VMMDEV_TESTING_UNIT_INSTRS UINT8_C(0x19) /**< Instructions. */ +#define VMMDEV_TESTING_UNIT_INSTRS_PER_SEC UINT8_C(0x1a) /**< Instructions per second. */ +#define VMMDEV_TESTING_UNIT_NONE UINT8_C(0x1b) /**< No unit. */ +#define VMMDEV_TESTING_UNIT_PP1K UINT8_C(0x1c) /**< Parts per thousand (10^-3). */ +#define VMMDEV_TESTING_UNIT_PP10K UINT8_C(0x1d) /**< Parts per ten thousand (10^-4). */ +#define VMMDEV_TESTING_UNIT_PPM UINT8_C(0x1e) /**< Parts per million (10^-6). */ +#define VMMDEV_TESTING_UNIT_PPB UINT8_C(0x1f) /**< Parts per billion (10^-9). */ +#define VMMDEV_TESTING_UNIT_TICKS UINT8_C(0x20) /**< CPU ticks. */ +#define VMMDEV_TESTING_UNIT_TICKS_PER_CALL UINT8_C(0x21) /**< CPU ticks per call. */ +#define VMMDEV_TESTING_UNIT_TICKS_PER_OCCURENCE UINT8_C(0x22) /**< CPU ticks per occurence. */ +#define VMMDEV_TESTING_UNIT_PAGES UINT8_C(0x23) /**< Page count. */ +#define VMMDEV_TESTING_UNIT_PAGES_PER_SEC UINT8_C(0x24) /**< Pages per second. */ +#define VMMDEV_TESTING_UNIT_TICKS_PER_PAGE UINT8_C(0x25) /**< CPU ticks per page. */ +#define VMMDEV_TESTING_UNIT_NS_PER_PAGE UINT8_C(0x26) /**< Nanoseconds per page. */ +#define VMMDEV_TESTING_UNIT_PS UINT8_C(0x27) /**< Picoseconds. */ +#define VMMDEV_TESTING_UNIT_PS_PER_CALL UINT8_C(0x28) /**< Picoseconds per call. */ +#define VMMDEV_TESTING_UNIT_PS_PER_FRAME UINT8_C(0x29) /**< Picoseconds per frame. */ +#define VMMDEV_TESTING_UNIT_PS_PER_OCCURRENCE UINT8_C(0x2a) /**< Picoseconds per occurrence. */ +#define VMMDEV_TESTING_UNIT_PS_PER_PACKET UINT8_C(0x2b) /**< Picoseconds per frame. */ +#define VMMDEV_TESTING_UNIT_PS_PER_ROUND_TRIP UINT8_C(0x2c) /**< Picoseconds per round trip. */ +#define VMMDEV_TESTING_UNIT_PS_PER_PAGE UINT8_C(0x2d) /**< Picoseconds per page. */ +/** @} */ + +/** What the NOP accesses returns. */ +#define VMMDEV_TESTING_NOP_RET UINT32_C(0x64726962) /* bird */ + +/** @name Low and High Locking Control Dwords + * @{ */ +/** Low Locking Control: Thread lock hold interval in microseconds. */ +#define VMMDEV_TESTING_LOCKED_LO_HOLD_MASK UINT32_C(0x0000ffff) +/** Low Locking Control: Thread wait time in microseconds between locking + * attempts. */ +#define VMMDEV_TESTING_LOCKED_LO_WAIT_MASK UINT32_C(0xffff0000) +/** Low Locking Control: Thread wait time shift count. */ +#define VMMDEV_TESTING_LOCKED_LO_WAIT_SHIFT 16 +/** High Locking Control: Kilo (1024) ticks the EMT should hold the lock. */ +#define VMMDEV_TESTING_LOCKED_HI_TICKS_MASK UINT32_C(0x000fffff) +/** High Locking Control: Must be zero. */ +#define VMMDEV_TESTING_LOCKED_HI_MBZ_MASK UINT32_C(0x03f00000) +/** High Locking Control: Thread takes lock in shared mode when set, exclusive + * when clear. */ +#define VMMDEV_TESTING_LOCKED_HI_THREAD_SHARED UINT32_C(0x04000000) +/** High Locking Control: EMT takes lock in shared mode when set, exclusive + * when clear. */ +#define VMMDEV_TESTING_LOCKED_HI_EMT_SHARED UINT32_C(0x08000000) +/** High Locking Control: Use read/write critical section instead of regular. */ +#define VMMDEV_TESTING_LOCKED_HI_TYPE_RW UINT32_C(0x10000000) +/** High Locking Control: EMT takes lock with rcBusy set to VINF_SUCCESS. */ +#define VMMDEV_TESTING_LOCKED_HI_BUSY_SUCCESS UINT32_C(0x20000000) +/** High Locking Control: Thread pokes EMTs before releasing lock. */ +#define VMMDEV_TESTING_LOCKED_HI_POKE UINT32_C(0x40000000) +/** High Locking Control: Thread enabled. */ +#define VMMDEV_TESTING_LOCKED_HI_ENABLED UINT32_C(0x80000000) +/** @} */ + +/** @name VMMDEV_TESTING_CFG_XXX - Configuration values that can be queried. + * @{ */ +/** Generic 32-bit value \#0 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD0 UINT16_C(0x0000) +/** Generic 32-bit value \#1 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD1 UINT16_C(0x0001) +/** Generic 32-bit value \#2 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD2 UINT16_C(0x0002) +/** Generic 32-bit value \#3 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD3 UINT16_C(0x0003) +/** Generic 32-bit value \#4 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD4 UINT16_C(0x0004) +/** Generic 32-bit value \#5 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD5 UINT16_C(0x0005) +/** Generic 32-bit value \#6 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD6 UINT16_C(0x0006) +/** Generic 32-bit value \#7 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD7 UINT16_C(0x0007) +/** Generic 32-bit value \#8 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD8 UINT16_C(0x0008) +/** Generic 32-bit value \#9 - testcase defined meaning. */ +#define VMMDEV_TESTING_CFG_DWORD9 UINT16_C(0x0009) + +/** Boolean (8-bit): Running in NEM on Linux? */ +#define VMMDEV_TESTING_CFG_IS_NEM_LINUX UINT16_C(0x0100) +/** Boolean (8-bit): Running in NEM on Windows? */ +#define VMMDEV_TESTING_CFG_IS_NEM_WINDOWS UINT16_C(0x0101) +/** Boolean (8-bit): Running in NEM on Darwin? */ +#define VMMDEV_TESTING_CFG_IS_NEM_DARWIN UINT16_C(0x0102) +/** @} */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_VMMDevTesting_h */ + diff --git a/include/VBox/VMMDevTesting.mac b/include/VBox/VMMDevTesting.mac new file mode 100644 index 00000000..79434866 --- /dev/null +++ b/include/VBox/VMMDevTesting.mac @@ -0,0 +1,148 @@ +; $Id: VMMDevTesting.mac $ ;/ +;; @file +; VMMDev - Testing Extensions. +; Automatically generated by various.sed. DO NOT EDIT! + +; +; Copyright (C) 2010-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef VBOX_INCLUDED_VMMDevTesting_h +%define VBOX_INCLUDED_VMMDevTesting_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%define VMMDEV_TESTING_MMIO_BASE 0x000df000 +%define VMMDEV_TESTING_MMIO_SIZE 0x00001000 +%define VMMDEV_TESTING_MMIO_OFF_NOP (0x000) +%define VMMDEV_TESTING_MMIO_OFF_NOP_R3 (0x008) +%define VMMDEV_TESTING_MMIO_OFF_READBACK (0x040) +%define VMMDEV_TESTING_MMIO_OFF_READBACK_R3 (0x080) +%define VMMDEV_TESTING_READBACK_SIZE (0x40) +%define VMMDEV_TESTING_MMIO_NOP (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_NOP) +%define VMMDEV_TESTING_MMIO_NOP_R3 (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_NOP_R3) +%define VMMDEV_TESTING_MMIO_READBACK (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_READBACK) +%define VMMDEV_TESTING_MMIO_READBACK_R3 (VMMDEV_TESTING_MMIO_BASE + VMMDEV_TESTING_MMIO_OFF_READBACK_R3) +%define VMMDEV_TESTING_MMIO_RM_SEL 0xdf00 +%define VMMDEV_TESTING_MMIO_RM_OFF(val) ((val) - VMMDEV_TESTING_MMIO_BASE) +%define VMMDEV_TESTING_MMIO_RM_OFF2(off) (off) +%define VMMDEV_TESTING_IOPORT_BASE 0x0510 +%define VMMDEV_TESTING_IOPORT_COUNT 0x0010 +%define VMMDEV_TESTING_IOPORT_NOP (VMMDEV_TESTING_IOPORT_BASE + 0) +%define VMMDEV_TESTING_IOPORT_TS_LOW (VMMDEV_TESTING_IOPORT_BASE + 1) +%define VMMDEV_TESTING_IOPORT_TS_HIGH (VMMDEV_TESTING_IOPORT_BASE + 2) +%define VMMDEV_TESTING_IOPORT_CMD (VMMDEV_TESTING_IOPORT_BASE + 3) +%define VMMDEV_TESTING_IOPORT_DATA (VMMDEV_TESTING_IOPORT_BASE + 4) +%define VMMDEV_TESTING_IOPORT_NOP_R3 (VMMDEV_TESTING_IOPORT_BASE + 5) +%define VMMDEV_TESTING_IOPORT_LOCKED_LO (VMMDEV_TESTING_IOPORT_BASE + 6) +%define VMMDEV_TESTING_IOPORT_LOCKED_HI (VMMDEV_TESTING_IOPORT_BASE + 7) +%define VMMDEV_TESTING_CMD_INIT 0xcab1e000 +%define VMMDEV_TESTING_CMD_TERM 0xcab1e001 +%define VMMDEV_TESTING_CMD_SUB_NEW 0xcab1e002 +%define VMMDEV_TESTING_CMD_SUB_DONE 0xcab1e003 +%define VMMDEV_TESTING_CMD_FAILED 0xcab1e004 +%define VMMDEV_TESTING_CMD_VALUE 0xcab1e005 +%define VMMDEV_TESTING_CMD_SKIPPED 0xcab1e006 +%define VMMDEV_TESTING_CMD_VALUE_REG 0xcab1e007 +%define VMMDEV_TESTING_CMD_PRINT 0xcab1e008 +%define VMMDEV_TESTING_CMD_QUERY_CFG 0xcab1e009 +%define VMMDEV_TESTING_CMD_MAGIC 0xcab1e000 +%define VMMDEV_TESTING_CMD_MAGIC_MASK 0xffffff00 +%define VMMDEV_TESTING_CMD_MAGIC_HI_WORD 0xcab10000 +%define VMMDEV_TESTING_UNIT_PCT 0x01 +%define VMMDEV_TESTING_UNIT_BYTES 0x02 +%define VMMDEV_TESTING_UNIT_BYTES_PER_SEC 0x03 +%define VMMDEV_TESTING_UNIT_KILOBYTES 0x04 +%define VMMDEV_TESTING_UNIT_KILOBYTES_PER_SEC 0x05 +%define VMMDEV_TESTING_UNIT_MEGABYTES 0x06 +%define VMMDEV_TESTING_UNIT_MEGABYTES_PER_SEC 0x07 +%define VMMDEV_TESTING_UNIT_PACKETS 0x08 +%define VMMDEV_TESTING_UNIT_PACKETS_PER_SEC 0x09 +%define VMMDEV_TESTING_UNIT_FRAMES 0x0a +%define VMMDEV_TESTING_UNIT_FRAMES_PER_SEC 0x0b +%define VMMDEV_TESTING_UNIT_OCCURRENCES 0x0c +%define VMMDEV_TESTING_UNIT_OCCURRENCES_PER_SEC 0x0d +%define VMMDEV_TESTING_UNIT_CALLS 0x0e +%define VMMDEV_TESTING_UNIT_CALLS_PER_SEC 0x0f +%define VMMDEV_TESTING_UNIT_ROUND_TRIP 0x10 +%define VMMDEV_TESTING_UNIT_SECS 0x11 +%define VMMDEV_TESTING_UNIT_MS 0x12 +%define VMMDEV_TESTING_UNIT_NS 0x13 +%define VMMDEV_TESTING_UNIT_NS_PER_CALL 0x14 +%define VMMDEV_TESTING_UNIT_NS_PER_FRAME 0x15 +%define VMMDEV_TESTING_UNIT_NS_PER_OCCURRENCE 0x16 +%define VMMDEV_TESTING_UNIT_NS_PER_PACKET 0x17 +%define VMMDEV_TESTING_UNIT_NS_PER_ROUND_TRIP 0x18 +%define VMMDEV_TESTING_UNIT_INSTRS 0x19 +%define VMMDEV_TESTING_UNIT_INSTRS_PER_SEC 0x1a +%define VMMDEV_TESTING_UNIT_NONE 0x1b +%define VMMDEV_TESTING_UNIT_PP1K 0x1c +%define VMMDEV_TESTING_UNIT_PP10K 0x1d +%define VMMDEV_TESTING_UNIT_PPM 0x1e +%define VMMDEV_TESTING_UNIT_PPB 0x1f +%define VMMDEV_TESTING_UNIT_TICKS 0x20 +%define VMMDEV_TESTING_UNIT_TICKS_PER_CALL 0x21 +%define VMMDEV_TESTING_UNIT_TICKS_PER_OCCURENCE 0x22 +%define VMMDEV_TESTING_UNIT_PAGES 0x23 +%define VMMDEV_TESTING_UNIT_PAGES_PER_SEC 0x24 +%define VMMDEV_TESTING_UNIT_TICKS_PER_PAGE 0x25 +%define VMMDEV_TESTING_UNIT_NS_PER_PAGE 0x26 +%define VMMDEV_TESTING_UNIT_PS 0x27 +%define VMMDEV_TESTING_UNIT_PS_PER_CALL 0x28 +%define VMMDEV_TESTING_UNIT_PS_PER_FRAME 0x29 +%define VMMDEV_TESTING_UNIT_PS_PER_OCCURRENCE 0x2a +%define VMMDEV_TESTING_UNIT_PS_PER_PACKET 0x2b +%define VMMDEV_TESTING_UNIT_PS_PER_ROUND_TRIP 0x2c +%define VMMDEV_TESTING_UNIT_PS_PER_PAGE 0x2d +%define VMMDEV_TESTING_NOP_RET 0x64726962 +%define VMMDEV_TESTING_LOCKED_LO_HOLD_MASK 0x0000ffff +%define VMMDEV_TESTING_LOCKED_LO_WAIT_MASK 0xffff0000 +%define VMMDEV_TESTING_LOCKED_LO_WAIT_SHIFT 16 +%define VMMDEV_TESTING_LOCKED_HI_TICKS_MASK 0x000fffff +%define VMMDEV_TESTING_LOCKED_HI_MBZ_MASK 0x03f00000 +%define VMMDEV_TESTING_LOCKED_HI_THREAD_SHARED 0x04000000 +%define VMMDEV_TESTING_LOCKED_HI_EMT_SHARED 0x08000000 +%define VMMDEV_TESTING_LOCKED_HI_TYPE_RW 0x10000000 +%define VMMDEV_TESTING_LOCKED_HI_BUSY_SUCCESS 0x20000000 +%define VMMDEV_TESTING_LOCKED_HI_POKE 0x40000000 +%define VMMDEV_TESTING_LOCKED_HI_ENABLED 0x80000000 +%define VMMDEV_TESTING_CFG_DWORD0 0x0000 +%define VMMDEV_TESTING_CFG_DWORD1 0x0001 +%define VMMDEV_TESTING_CFG_DWORD2 0x0002 +%define VMMDEV_TESTING_CFG_DWORD3 0x0003 +%define VMMDEV_TESTING_CFG_DWORD4 0x0004 +%define VMMDEV_TESTING_CFG_DWORD5 0x0005 +%define VMMDEV_TESTING_CFG_DWORD6 0x0006 +%define VMMDEV_TESTING_CFG_DWORD7 0x0007 +%define VMMDEV_TESTING_CFG_DWORD8 0x0008 +%define VMMDEV_TESTING_CFG_DWORD9 0x0009 +%define VMMDEV_TESTING_CFG_IS_NEM_LINUX 0x0100 +%define VMMDEV_TESTING_CFG_IS_NEM_WINDOWS 0x0101 +%define VMMDEV_TESTING_CFG_IS_NEM_DARWIN 0x0102 +%endif diff --git a/include/VBox/apic.h b/include/VBox/apic.h new file mode 100644 index 00000000..e6f213f4 --- /dev/null +++ b/include/VBox/apic.h @@ -0,0 +1,493 @@ +/** @file + * X86 (and AMD64) Local APIC registers (VMM,++). + * + * apic.mac is generated from this file by running 'kmk incs' in the root. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_apic_h +#define VBOX_INCLUDED_apic_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +/** @todo These are defines used by CPUM and perhaps some assembly code. Remove + * these and use the XAPIC counterpart defines below later. */ +#define APIC_REG_VERSION 0x0030 +#define APIC_REG_VERSION_GET_VER(u32) (u32 & 0xff) +#define APIC_REG_VERSION_GET_MAX_LVT(u32) ((u32 & 0xff0000) >> 16) + +/* Defines according to Figure 10-8 of the Intel Software Developers Manual Vol 3A */ +#define APIC_REG_LVT_LINT0 0x0350 +#define APIC_REG_LVT_LINT1 0x0360 +#define APIC_REG_LVT_ERR 0x0370 +#define APIC_REG_LVT_PC 0x0340 +#define APIC_REG_LVT_THMR 0x0330 +#define APIC_REG_LVT_CMCI 0x02F0 +#define APIC_REG_EILVT0 0x0500 +#define APIC_REG_EILVT1 0x0510 +#define APIC_REG_EILVT2 0x0520 +#define APIC_REG_EILVT3 0x0530 +#define APIC_REG_LVT_MODE_MASK (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +#define APIC_REG_LVT_MODE_FIXED 0 +#define APIC_REG_LVT_MODE_NMI RT_BIT(10) +#define APIC_REG_LVT_MODE_EXTINT (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +#define APIC_REG_LVT_PIN_POLARIY RT_BIT(13) +#define APIC_REG_LVT_REMOTE_IRR RT_BIT(14) +#define APIC_REG_LVT_LEVEL_TRIGGER RT_BIT(15) +#define APIC_REG_LVT_MASKED RT_BIT(16) + +/** The APIC hardware version number for Pentium 4. */ +#define XAPIC_HARDWARE_VERSION_P4 UINT8_C(0x14) +/** Maximum number of LVT entries for Pentium 4. */ +#define XAPIC_MAX_LVT_ENTRIES_P4 UINT8_C(6) +/** Size of the APIC ID bits for Pentium 4. */ +#define XAPIC_APIC_ID_BIT_COUNT_P4 UINT8_C(8) + +/** The APIC hardware version number for Pentium 6. */ +#define XAPIC_HARDWARE_VERSION_P6 UINT8_C(0x10) +/** Maximum number of LVT entries for Pentium 6. */ +#define XAPIC_MAX_LVT_ENTRIES_P6 UINT8_C(4) +/** Size of the APIC ID bits for Pentium 6. */ +#define XAPIC_APIC_ID_BIT_COUNT_P6 UINT8_C(4) + +/** Illegal APIC vector value start. */ +#define XAPIC_ILLEGAL_VECTOR_START UINT8_C(0) +/** Illegal APIC vector value end (inclusive). */ +#define XAPIC_ILLEGAL_VECTOR_END UINT8_C(15) +/** Reserved APIC vector value start. */ +#define XAPIC_RSVD_VECTOR_START UINT8_C(16) +/** Reserved APIC vector value end (inclusive). */ +#define XAPIC_RSVD_VECTOR_END UINT8_C(31) + +/** ESR - Send checksum error for Pentium 6. */ +# define XAPIC_ESR_SEND_CHKSUM_ERROR_P6 RT_BIT(0) +/** ESR - Send accept error for Pentium 6. */ +# define XAPIC_ESR_RECV_CHKSUM_ERROR_P6 RT_BIT(1) +/** ESR - Send accept error for Pentium 6. */ +# define XAPIC_ESR_SEND_ACCEPT_ERROR_P6 RT_BIT(2) +/** ESR - Receive accept error for Pentium 6. */ +# define XAPIC_ESR_RECV_ACCEPT_ERROR_P6 RT_BIT(3) + +/** ESR - Redirectable IPI. */ +#define XAPIC_ESR_REDIRECTABLE_IPI RT_BIT(4) +/** ESR - Send accept error. */ +#define XAPIC_ESR_SEND_ILLEGAL_VECTOR RT_BIT(5) +/** ESR - Send accept error. */ +#define XAPIC_ESR_RECV_ILLEGAL_VECTOR RT_BIT(6) +/** ESR - Send accept error. */ +#define XAPIC_ESR_ILLEGAL_REG_ADDRESS RT_BIT(7) +/** ESR - Valid write-only bits. */ +#define XAPIC_ESR_WO_VALID UINT32_C(0x0) + +/** TPR - Valid bits. */ +#define XAPIC_TPR_VALID UINT32_C(0xff) +/** TPR - Task-priority class. */ +#define XAPIC_TPR_TP UINT32_C(0xf0) +/** TPR - Task-priority subclass. */ +#define XAPIC_TPR_TP_SUBCLASS UINT32_C(0x0f) +/** TPR - Gets the task-priority class. */ +#define XAPIC_TPR_GET_TP(a_Tpr) ((a_Tpr) & XAPIC_TPR_TP) +/** TPR - Gets the task-priority subclass. */ +#define XAPIC_TPR_GET_TP_SUBCLASS(a_Tpr) ((a_Tpr) & XAPIC_TPR_TP_SUBCLASS) + +/** PPR - Valid bits. */ +#define XAPIC_PPR_VALID UINT32_C(0xff) +/** PPR - Processor-priority class. */ +#define XAPIC_PPR_PP UINT32_C(0xf0) +/** PPR - Processor-priority subclass. */ +#define XAPIC_PPR_PP_SUBCLASS UINT32_C(0x0f) +/** PPR - Get the processor-priority class. */ +#define XAPIC_PPR_GET_PP(a_Ppr) ((a_Ppr) & XAPIC_PPR_PP) +/** PPR - Get the processor-priority subclass. */ +#define XAPIC_PPR_GET_PP_SUBCLASS(a_Ppr) ((a_Ppr) & XAPIC_PPR_PP_SUBCLASS) + +/** Timer mode - One-shot. */ +#define XAPIC_TIMER_MODE_ONESHOT UINT32_C(0) +/** Timer mode - Periodic. */ +#define XAPIC_TIMER_MODE_PERIODIC UINT32_C(1) +/** Timer mode - TSC deadline. */ +#define XAPIC_TIMER_MODE_TSC_DEADLINE UINT32_C(2) + +/** LVT - The vector. */ +#define XAPIC_LVT_VECTOR UINT32_C(0xff) +/** LVT - Gets the vector from an LVT entry. */ +#define XAPIC_LVT_GET_VECTOR(a_Lvt) ((a_Lvt) & XAPIC_LVT_VECTOR) +/** LVT - The mask. */ +#define XAPIC_LVT_MASK RT_BIT(16) +/** LVT - Is the LVT masked? */ +#define XAPIC_LVT_IS_MASKED(a_Lvt) RT_BOOL((a_Lvt) & XAPIC_LVT_MASK) +/** LVT - Timer mode. */ +#define XAPIC_LVT_TIMER_MODE RT_BIT(17) +/** LVT - Timer TSC-deadline timer mode. */ +#define XAPIC_LVT_TIMER_TSCDEADLINE RT_BIT(18) +/** LVT - Gets the timer mode. */ +#define XAPIC_LVT_GET_TIMER_MODE(a_Lvt) (XAPICTIMERMODE)(((a_Lvt) >> 17) & UINT32_C(3)) +/** LVT - Delivery mode. */ +#define XAPIC_LVT_DELIVERY_MODE (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +/** LVT - Gets the delivery mode. */ +#define XAPIC_LVT_GET_DELIVERY_MODE(a_Lvt) (XAPICDELIVERYMODE)(((a_Lvt) >> 8) & UINT32_C(7)) +/** LVT - Delivery status. */ +#define XAPIC_LVT_DELIVERY_STATUS RT_BIT(12) +/** LVT - Trigger mode. */ +#define XAPIC_LVT_TRIGGER_MODE RT_BIT(15) +/** LVT - Gets the trigger mode. */ +#define XAPIC_LVT_GET_TRIGGER_MODE(a_Lvt) (XAPICTRIGGERMODE)(((a_Lvt) >> 15) & UINT32_C(1)) +/** LVT - Remote IRR. */ +#define XAPIC_LVT_REMOTE_IRR RT_BIT(14) +/** LVT - Gets the Remote IRR. */ +#define XAPIC_LVT_GET_REMOTE_IRR(a_Lvt) (((a_Lvt) >> 14) & 1) +/** LVT - Interrupt Input Pin Polarity. */ +#define XAPIC_LVT_POLARITY RT_BIT(13) +/** LVT - Gets the Interrupt Input Pin Polarity. */ +#define XAPIC_LVT_GET_POLARITY(a_Lvt) (((a_Lvt) >> 13) & 1) +/** LVT - Valid bits common to all LVTs. */ +#define XAPIC_LVT_COMMON_VALID (XAPIC_LVT_VECTOR | XAPIC_LVT_DELIVERY_STATUS | XAPIC_LVT_MASK) +/** LVT CMCI - Valid bits. */ +#define XAPIC_LVT_CMCI_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE) +/** LVT Timer - Valid bits. */ +#define XAPIC_LVT_TIMER_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_TIMER_MODE | XAPIC_LVT_TIMER_TSCDEADLINE) +/** LVT Thermal - Valid bits. */ +#define XAPIC_LVT_THERMAL_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE) +/** LVT Perf - Valid bits. */ +#define XAPIC_LVT_PERF_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE) +/** LVT LINTx - Valid bits. */ +#define XAPIC_LVT_LINT_VALID ( XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE | XAPIC_LVT_DELIVERY_STATUS \ + | XAPIC_LVT_POLARITY | XAPIC_LVT_REMOTE_IRR | XAPIC_LVT_TRIGGER_MODE) +/** LVT Error - Valid bits. */ +#define XAPIC_LVT_ERROR_VALID (XAPIC_LVT_COMMON_VALID) + +/** SVR - The vector. */ +#define XAPIC_SVR_VECTOR UINT32_C(0xff) +/** SVR - APIC Software enable. */ +#define XAPIC_SVR_SOFTWARE_ENABLE RT_BIT(8) +/** SVR - Supress EOI broadcast. */ +#define XAPIC_SVR_SUPRESS_EOI_BROADCAST RT_BIT(12) +/** SVR - Valid bits for Pentium 4. */ +# define XAPIC_SVR_VALID_P4 (XAPIC_SVR_VECTOR | XAPIC_SVR_SOFTWARE_ENABLE) +/** @todo SVR - Valid bits for Pentium 6. */ + +/** DFR - Valid bits. */ +#define XAPIC_DFR_VALID UINT32_C(0xf0000000) +/** DFR - Reserved bits that must always remain set. */ +#define XAPIC_DFR_RSVD_MB1 UINT32_C(0x0fffffff) +/** DFR - The model. */ +#define XAPIC_DFR_MODEL UINT32_C(0xf) +/** DFR - Gets the destination model. */ +#define XAPIC_DFR_GET_MODEL(a_uReg) (((a_uReg) >> 28) & XAPIC_DFR_MODEL) + +/** LDR - Valid bits. */ +#define XAPIC_LDR_VALID UINT32_C(0xff000000) +/** LDR - Cluster ID mask (x2APIC). */ +#define X2APIC_LDR_CLUSTER_ID UINT32_C(0xffff0000) +/** LDR - Mask of the LDR cluster ID (x2APIC). */ +#define X2APIC_LDR_GET_CLUSTER_ID(a_uReg) ((a_uReg) & X2APIC_LDR_CLUSTER_ID) +/** LDR - Mask of the LDR logical ID (x2APIC). */ +#define X2APIC_LDR_LOGICAL_ID UINT32_C(0x0000ffff) + +/** LDR - Flat mode logical ID mask. */ +#define XAPIC_LDR_FLAT_LOGICAL_ID UINT32_C(0xff) +/** LDR - Clustered mode cluster ID mask. */ +#define XAPIC_LDR_CLUSTERED_CLUSTER_ID UINT32_C(0xf0) +/** LDR - Clustered mode logical ID mask. */ +#define XAPIC_LDR_CLUSTERED_LOGICAL_ID UINT32_C(0x0f) +/** LDR - Gets the clustered mode cluster ID. */ +#define XAPIC_LDR_CLUSTERED_GET_CLUSTER_ID(a_uReg) ((a_uReg) & XAPIC_LDR_CLUSTERED_CLUSTER_ID) + + +/** EOI - Valid write-only bits. */ +#define XAPIC_EOI_WO_VALID UINT32_C(0x0) +/** Timer ICR - Valid bits. */ +#define XAPIC_TIMER_ICR_VALID UINT32_C(0xffffffff) +/** Timer DCR - Valid bits. */ +#define XAPIC_TIMER_DCR_VALID (RT_BIT(0) | RT_BIT(1) | RT_BIT(3)) + +/** Self IPI - Valid bits. */ +#define XAPIC_SELF_IPI_VALID UINT32_C(0xff) +/** Self IPI - The vector. */ +#define XAPIC_SELF_IPI_VECTOR UINT32_C(0xff) +/** Self IPI - Gets the vector. */ +#define XAPIC_SELF_IPI_GET_VECTOR(a_uReg) ((a_uReg) & XAPIC_SELF_IPI_VECTOR) + +/** ICR Low - The Vector. */ +#define XAPIC_ICR_LO_VECTOR UINT32_C(0xff) +/** ICR Low - Gets the vector. */ +#define XAPIC_ICR_LO_GET_VECTOR(a_uIcr) ((a_uIcr) & XAPIC_ICR_LO_VECTOR) +/** ICR Low - The delivery mode. */ +#define XAPIC_ICR_LO_DELIVERY_MODE (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +/** ICR Low - The destination mode. */ +#define XAPIC_ICR_LO_DEST_MODE RT_BIT(11) +/** ICR Low - The delivery status. */ +#define XAPIC_ICR_LO_DELIVERY_STATUS RT_BIT(12) +/** ICR Low - The level. */ +#define XAPIC_ICR_LO_LEVEL RT_BIT(14) +/** ICR Low - The trigger mode. */ +#define XAPIC_ICR_TRIGGER_MODE RT_BIT(15) +/** ICR Low - The destination shorthand. */ +#define XAPIC_ICR_LO_DEST_SHORTHAND (RT_BIT(18) | RT_BIT(19)) +/** ICR Low - Valid write bits. */ +#define XAPIC_ICR_LO_WR_VALID ( XAPIC_ICR_LO_VECTOR | XAPIC_ICR_LO_DELIVERY_MODE | XAPIC_ICR_LO_DEST_MODE \ + | XAPIC_ICR_LO_LEVEL | XAPIC_ICR_TRIGGER_MODE | XAPIC_ICR_LO_DEST_SHORTHAND) + +/** ICR High - The destination field. */ +#define XAPIC_ICR_HI_DEST UINT32_C(0xff000000) +/** ICR High - Get the destination field. */ +#define XAPIC_ICR_HI_GET_DEST(a_u32IcrHi) (((a_u32IcrHi) >> 24) & XAPIC_ICR_HI_DEST) +/** ICR High - Valid write bits in xAPIC mode. */ +#define XAPIC_ICR_HI_WR_VALID XAPIC_ICR_HI_DEST + +/** APIC ID broadcast mask - x2APIC mode. */ +#define X2APIC_ID_BROADCAST_MASK UINT32_C(0xffffffff) +/** APIC ID broadcast mask - xAPIC mode for Pentium 4. */ +# define XAPIC_ID_BROADCAST_MASK_P4 UINT32_C(0xff) +/** @todo Broadcast mask for Pentium 6. */ + +/** Get an xAPIC page offset for an x2APIC MSR value. */ +#define X2APIC_GET_XAPIC_OFF(a_uMsr) ((((a_uMsr) - MSR_IA32_X2APIC_START) << 4) & UINT32_C(0xff0)) +/** Get an x2APIC MSR for an xAPIC page offset. */ +#define XAPIC_GET_X2APIC_MSR(a_offReg) ((((a_offReg) & UINT32_C(0xff0)) >> 4) | MSR_IA32_X2APIC_START) + +/** @name xAPIC and x2APIC register offsets. + * See Intel spec. 10.4.1 "The Local APIC Block Diagram". + * @{ */ +/** Offset of APIC ID Register. */ +#define XAPIC_OFF_ID 0x020 +/** Offset of APIC Version Register. */ +#define XAPIC_OFF_VERSION 0x030 +/** Offset of Task Priority Register. */ +#define XAPIC_OFF_TPR 0x080 +/** Offset of Arbitrartion Priority register. */ +#define XAPIC_OFF_APR 0x090 +/** Offset of Processor Priority register. */ +#define XAPIC_OFF_PPR 0x0A0 +/** Offset of End Of Interrupt register. */ +#define XAPIC_OFF_EOI 0x0B0 +/** Offset of Remote Read Register. */ +#define XAPIC_OFF_RRD 0x0C0 +/** Offset of Logical Destination Register. */ +#define XAPIC_OFF_LDR 0x0D0 +/** Offset of Destination Format Register. */ +#define XAPIC_OFF_DFR 0x0E0 +/** Offset of Spurious Interrupt Vector Register. */ +#define XAPIC_OFF_SVR 0x0F0 +/** Offset of In-service Register (bits 31:0). */ +#define XAPIC_OFF_ISR0 0x100 +/** Offset of In-service Register (bits 63:32). */ +#define XAPIC_OFF_ISR1 0x110 +/** Offset of In-service Register (bits 95:64). */ +#define XAPIC_OFF_ISR2 0x120 +/** Offset of In-service Register (bits 127:96). */ +#define XAPIC_OFF_ISR3 0x130 +/** Offset of In-service Register (bits 159:128). */ +#define XAPIC_OFF_ISR4 0x140 +/** Offset of In-service Register (bits 191:160). */ +#define XAPIC_OFF_ISR5 0x150 +/** Offset of In-service Register (bits 223:192). */ +#define XAPIC_OFF_ISR6 0x160 +/** Offset of In-service Register (bits 255:224). */ +#define XAPIC_OFF_ISR7 0x170 +/** Offset of Trigger Mode Register (bits 31:0). */ +#define XAPIC_OFF_TMR0 0x180 +/** Offset of Trigger Mode Register (bits 63:32). */ +#define XAPIC_OFF_TMR1 0x190 +/** Offset of Trigger Mode Register (bits 95:64). */ +#define XAPIC_OFF_TMR2 0x1A0 +/** Offset of Trigger Mode Register (bits 127:96). */ +#define XAPIC_OFF_TMR3 0x1B0 +/** Offset of Trigger Mode Register (bits 159:128). */ +#define XAPIC_OFF_TMR4 0x1C0 +/** Offset of Trigger Mode Register (bits 191:160). */ +#define XAPIC_OFF_TMR5 0x1D0 +/** Offset of Trigger Mode Register (bits 223:192). */ +#define XAPIC_OFF_TMR6 0x1E0 +/** Offset of Trigger Mode Register (bits 255:224). */ +#define XAPIC_OFF_TMR7 0x1F0 +/** Offset of Interrupt Request Register (bits 31:0). */ +#define XAPIC_OFF_IRR0 0x200 +/** Offset of Interrupt Request Register (bits 63:32). */ +#define XAPIC_OFF_IRR1 0x210 +/** Offset of Interrupt Request Register (bits 95:64). */ +#define XAPIC_OFF_IRR2 0x220 +/** Offset of Interrupt Request Register (bits 127:96). */ +#define XAPIC_OFF_IRR3 0x230 +/** Offset of Interrupt Request Register (bits 159:128). */ +#define XAPIC_OFF_IRR4 0x240 +/** Offset of Interrupt Request Register (bits 191:160). */ +#define XAPIC_OFF_IRR5 0x250 +/** Offset of Interrupt Request Register (bits 223:192). */ +#define XAPIC_OFF_IRR6 0x260 +/** Offset of Interrupt Request Register (bits 255:224). */ +#define XAPIC_OFF_IRR7 0x270 +/** Offset of Error Status Register. */ +#define XAPIC_OFF_ESR 0x280 +/** Offset of LVT CMCI Register. */ +#define XAPIC_OFF_LVT_CMCI 0x2F0 +/** Offset of Interrupt Command Register - Lo. */ +#define XAPIC_OFF_ICR_LO 0x300 +/** Offset of Interrupt Command Register - Hi. */ +#define XAPIC_OFF_ICR_HI 0x310 +/** Offset of LVT Timer Register. */ +#define XAPIC_OFF_LVT_TIMER 0x320 +/** Offset of LVT Thermal Sensor Register. */ +#define XAPIC_OFF_LVT_THERMAL 0x330 +/** Offset of LVT Performance Counter Register. */ +#define XAPIC_OFF_LVT_PERF 0x340 +/** Offset of LVT LINT0 Register. */ +#define XAPIC_OFF_LVT_LINT0 0x350 +/** Offset of LVT LINT1 Register. */ +#define XAPIC_OFF_LVT_LINT1 0x360 +/** Offset of LVT Error Register . */ +#define XAPIC_OFF_LVT_ERROR 0x370 +/** Offset of Timer Initial Count Register. */ +#define XAPIC_OFF_TIMER_ICR 0x380 +/** Offset of Timer Current Count Register. */ +#define XAPIC_OFF_TIMER_CCR 0x390 +/** Offset of Timer Divide Configuration Register. */ +#define XAPIC_OFF_TIMER_DCR 0x3E0 +/** Offset of Self-IPI Register (x2APIC only). */ +#define X2APIC_OFF_SELF_IPI 0x3F0 + +/** Offset of LVT range start. */ +#define XAPIC_OFF_LVT_START XAPIC_OFF_LVT_TIMER +/** Offset of LVT range end (inclusive). */ +#define XAPIC_OFF_LVT_END XAPIC_OFF_LVT_ERROR +/** Offset of LVT extended range start. */ +#define XAPIC_OFF_LVT_EXT_START XAPIC_OFF_LVT_CMCI +/** Offset of LVT extended range end (inclusive). */ +#define XAPIC_OFF_LVT_EXT_END XAPIC_OFF_LVT_CMCI +/** Offset of the last register (incl. reserved) in the xAPIC/x2APIC range. */ +#define XAPIC_OFF_END 0x3F0 +/** @} */ + +/** @name xAPIC Destination Format Register bits. + * See Intel spec. 10.6.2.2 "Logical Destination Mode". + * @{ */ +typedef enum XAPICDESTFORMAT +{ + XAPICDESTFORMAT_FLAT = 0xf, + XAPICDESTFORMAT_CLUSTER = 0 +} XAPICDESTFORMAT; +/** @} */ + +/** @name xAPIC Timer Mode bits. + * See Intel spec. 10.5.1 "Local Vector Table". + * @{ */ +typedef enum XAPICTIMERMODE +{ + XAPICTIMERMODE_ONESHOT = XAPIC_TIMER_MODE_ONESHOT, + XAPICTIMERMODE_PERIODIC = XAPIC_TIMER_MODE_PERIODIC, + XAPICTIMERMODE_TSC_DEADLINE = XAPIC_TIMER_MODE_TSC_DEADLINE +} XAPICTIMERMODE; +/** @} */ + +/** @name xAPIC Interrupt Command Register bits. + * See Intel spec. 10.6.1 "Interrupt Command Register (ICR)". + * See Intel spec. 10.5.1 "Local Vector Table". + * @{ */ +/** + * xAPIC destination shorthand. + */ +typedef enum XAPICDESTSHORTHAND +{ + XAPICDESTSHORTHAND_NONE = 0, + XAPICDESTSHORTHAND_SELF, + XAPIDDESTSHORTHAND_ALL_INCL_SELF, + XAPICDESTSHORTHAND_ALL_EXCL_SELF +} XAPICDESTSHORTHAND; + +/** + * xAPIC INIT level de-assert delivery mode. + */ +typedef enum XAPICINITLEVEL +{ + XAPICINITLEVEL_DEASSERT = 0, + XAPICINITLEVEL_ASSERT +} XAPICLEVEL; + +/** + * xAPIC destination mode. + */ +typedef enum XAPICDESTMODE +{ + XAPICDESTMODE_PHYSICAL = 0, + XAPICDESTMODE_LOGICAL +} XAPICDESTMODE; + +/** + * xAPIC delivery mode type. + */ +typedef enum XAPICDELIVERYMODE +{ + XAPICDELIVERYMODE_FIXED = 0, + XAPICDELIVERYMODE_LOWEST_PRIO = 1, + XAPICDELIVERYMODE_SMI = 2, + XAPICDELIVERYMODE_NMI = 4, + XAPICDELIVERYMODE_INIT = 5, + XAPICDELIVERYMODE_STARTUP = 6, + XAPICDELIVERYMODE_EXTINT = 7 +} XAPICDELIVERYMODE; + +/** + * xAPIC trigger mode. + */ +typedef enum XAPICTRIGGERMODE +{ + XAPICTRIGGERMODE_EDGE = 0, + XAPICTRIGGERMODE_LEVEL +} XAPICTRIGGERMODE; +/** @} */ + + +DECLINLINE(uint32_t) ApicRegRead(void *pvBase, uint32_t offReg) +{ + return *(const volatile uint32_t *)((uintptr_t)pvBase + offReg); +} + + +#ifdef IPRT_INCLUDED_asm_amd64_x86_h +/** + * Reads an X2APIC register. + * + * @param offReg MMIO offset, APIC_REG_XXX. + */ +DECLINLINE(uint32_t) ApicX2RegRead32(uint32_t offReg) +{ + return ASMRdMsr((offReg >> 4) + MSR_IA32_X2APIC_START); +} +#endif + +#endif /* !VBOX_INCLUDED_apic_h */ + diff --git a/include/VBox/apic.mac b/include/VBox/apic.mac new file mode 100644 index 00000000..db4ba7d7 --- /dev/null +++ b/include/VBox/apic.mac @@ -0,0 +1,213 @@ +;; @file +; X86 (and AMD64) Local APIC registers (VMM,++). +; +; Automatically generated by various.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2010-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef VBOX_INCLUDED_apic_h +%define VBOX_INCLUDED_apic_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%define APIC_REG_VERSION 0x0030 +%define APIC_REG_VERSION_GET_VER(u32) (u32 & 0xff) +%define APIC_REG_VERSION_GET_MAX_LVT(u32) ((u32 & 0xff0000) >> 16) +%define APIC_REG_LVT_LINT0 0x0350 +%define APIC_REG_LVT_LINT1 0x0360 +%define APIC_REG_LVT_ERR 0x0370 +%define APIC_REG_LVT_PC 0x0340 +%define APIC_REG_LVT_THMR 0x0330 +%define APIC_REG_LVT_CMCI 0x02F0 +%define APIC_REG_EILVT0 0x0500 +%define APIC_REG_EILVT1 0x0510 +%define APIC_REG_EILVT2 0x0520 +%define APIC_REG_EILVT3 0x0530 +%define APIC_REG_LVT_MODE_MASK (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +%define APIC_REG_LVT_MODE_FIXED 0 +%define APIC_REG_LVT_MODE_NMI RT_BIT(10) +%define APIC_REG_LVT_MODE_EXTINT (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +%define APIC_REG_LVT_PIN_POLARIY RT_BIT(13) +%define APIC_REG_LVT_REMOTE_IRR RT_BIT(14) +%define APIC_REG_LVT_LEVEL_TRIGGER RT_BIT(15) +%define APIC_REG_LVT_MASKED RT_BIT(16) +%define XAPIC_HARDWARE_VERSION_P4 0x14 +%define XAPIC_MAX_LVT_ENTRIES_P4 6 +%define XAPIC_APIC_ID_BIT_COUNT_P4 8 +%define XAPIC_HARDWARE_VERSION_P6 0x10 +%define XAPIC_MAX_LVT_ENTRIES_P6 4 +%define XAPIC_APIC_ID_BIT_COUNT_P6 4 +%define XAPIC_ILLEGAL_VECTOR_START 0 +%define XAPIC_ILLEGAL_VECTOR_END 15 +%define XAPIC_RSVD_VECTOR_START 16 +%define XAPIC_RSVD_VECTOR_END 31 + %define XAPIC_ESR_SEND_CHKSUM_ERROR_P6 RT_BIT(0) + %define XAPIC_ESR_RECV_CHKSUM_ERROR_P6 RT_BIT(1) + %define XAPIC_ESR_SEND_ACCEPT_ERROR_P6 RT_BIT(2) + %define XAPIC_ESR_RECV_ACCEPT_ERROR_P6 RT_BIT(3) +%define XAPIC_ESR_REDIRECTABLE_IPI RT_BIT(4) +%define XAPIC_ESR_SEND_ILLEGAL_VECTOR RT_BIT(5) +%define XAPIC_ESR_RECV_ILLEGAL_VECTOR RT_BIT(6) +%define XAPIC_ESR_ILLEGAL_REG_ADDRESS RT_BIT(7) +%define XAPIC_ESR_WO_VALID 0x0 +%define XAPIC_TPR_VALID 0xff +%define XAPIC_TPR_TP 0xf0 +%define XAPIC_TPR_TP_SUBCLASS 0x0f +%define XAPIC_TPR_GET_TP(a_Tpr) ((a_Tpr) & XAPIC_TPR_TP) +%define XAPIC_TPR_GET_TP_SUBCLASS(a_Tpr) ((a_Tpr) & XAPIC_TPR_TP_SUBCLASS) +%define XAPIC_PPR_VALID 0xff +%define XAPIC_PPR_PP 0xf0 +%define XAPIC_PPR_PP_SUBCLASS 0x0f +%define XAPIC_PPR_GET_PP(a_Ppr) ((a_Ppr) & XAPIC_PPR_PP) +%define XAPIC_PPR_GET_PP_SUBCLASS(a_Ppr) ((a_Ppr) & XAPIC_PPR_PP_SUBCLASS) +%define XAPIC_TIMER_MODE_ONESHOT 0 +%define XAPIC_TIMER_MODE_PERIODIC 1 +%define XAPIC_TIMER_MODE_TSC_DEADLINE 2 +%define XAPIC_LVT_VECTOR 0xff +%define XAPIC_LVT_GET_VECTOR(a_Lvt) ((a_Lvt) & XAPIC_LVT_VECTOR) +%define XAPIC_LVT_MASK RT_BIT(16) +%define XAPIC_LVT_IS_MASKED(a_Lvt) RT_BOOL((a_Lvt) & XAPIC_LVT_MASK) +%define XAPIC_LVT_TIMER_MODE RT_BIT(17) +%define XAPIC_LVT_TIMER_TSCDEADLINE RT_BIT(18) +%define XAPIC_LVT_GET_TIMER_MODE(a_Lvt) (XAPICTIMERMODE)(((a_Lvt) >> 17) & 3) +%define XAPIC_LVT_DELIVERY_MODE (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +%define XAPIC_LVT_GET_DELIVERY_MODE(a_Lvt) (XAPICDELIVERYMODE)(((a_Lvt) >> 8) & 7) +%define XAPIC_LVT_DELIVERY_STATUS RT_BIT(12) +%define XAPIC_LVT_TRIGGER_MODE RT_BIT(15) +%define XAPIC_LVT_GET_TRIGGER_MODE(a_Lvt) (XAPICTRIGGERMODE)(((a_Lvt) >> 15) & 1) +%define XAPIC_LVT_REMOTE_IRR RT_BIT(14) +%define XAPIC_LVT_GET_REMOTE_IRR(a_Lvt) (((a_Lvt) >> 14) & 1) +%define XAPIC_LVT_POLARITY RT_BIT(13) +%define XAPIC_LVT_GET_POLARITY(a_Lvt) (((a_Lvt) >> 13) & 1) +%define XAPIC_LVT_COMMON_VALID (XAPIC_LVT_VECTOR | XAPIC_LVT_DELIVERY_STATUS | XAPIC_LVT_MASK) +%define XAPIC_LVT_CMCI_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE) +%define XAPIC_LVT_TIMER_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_TIMER_MODE | XAPIC_LVT_TIMER_TSCDEADLINE) +%define XAPIC_LVT_THERMAL_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE) +%define XAPIC_LVT_PERF_VALID (XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE) +%define XAPIC_LVT_LINT_VALID ( XAPIC_LVT_COMMON_VALID | XAPIC_LVT_DELIVERY_MODE | XAPIC_LVT_DELIVERY_STATUS \ + | XAPIC_LVT_POLARITY | XAPIC_LVT_REMOTE_IRR | XAPIC_LVT_TRIGGER_MODE) +%define XAPIC_LVT_ERROR_VALID (XAPIC_LVT_COMMON_VALID) +%define XAPIC_SVR_VECTOR 0xff +%define XAPIC_SVR_SOFTWARE_ENABLE RT_BIT(8) +%define XAPIC_SVR_SUPRESS_EOI_BROADCAST RT_BIT(12) + %define XAPIC_SVR_VALID_P4 (XAPIC_SVR_VECTOR | XAPIC_SVR_SOFTWARE_ENABLE) +%define XAPIC_DFR_VALID 0xf0000000 +%define XAPIC_DFR_RSVD_MB1 0x0fffffff +%define XAPIC_DFR_MODEL 0xf +%define XAPIC_DFR_GET_MODEL(a_uReg) (((a_uReg) >> 28) & XAPIC_DFR_MODEL) +%define XAPIC_LDR_VALID 0xff000000 +%define X2APIC_LDR_CLUSTER_ID 0xffff0000 +%define X2APIC_LDR_GET_CLUSTER_ID(a_uReg) ((a_uReg) & X2APIC_LDR_CLUSTER_ID) +%define X2APIC_LDR_LOGICAL_ID 0x0000ffff +%define XAPIC_LDR_FLAT_LOGICAL_ID 0xff +%define XAPIC_LDR_CLUSTERED_CLUSTER_ID 0xf0 +%define XAPIC_LDR_CLUSTERED_LOGICAL_ID 0x0f +%define XAPIC_LDR_CLUSTERED_GET_CLUSTER_ID(a_uReg) ((a_uReg) & XAPIC_LDR_CLUSTERED_CLUSTER_ID) +%define XAPIC_EOI_WO_VALID 0x0 +%define XAPIC_TIMER_ICR_VALID 0xffffffff +%define XAPIC_TIMER_DCR_VALID (RT_BIT(0) | RT_BIT(1) | RT_BIT(3)) +%define XAPIC_SELF_IPI_VALID 0xff +%define XAPIC_SELF_IPI_VECTOR 0xff +%define XAPIC_SELF_IPI_GET_VECTOR(a_uReg) ((a_uReg) & XAPIC_SELF_IPI_VECTOR) +%define XAPIC_ICR_LO_VECTOR 0xff +%define XAPIC_ICR_LO_GET_VECTOR(a_uIcr) ((a_uIcr) & XAPIC_ICR_LO_VECTOR) +%define XAPIC_ICR_LO_DELIVERY_MODE (RT_BIT(8) | RT_BIT(9) | RT_BIT(10)) +%define XAPIC_ICR_LO_DEST_MODE RT_BIT(11) +%define XAPIC_ICR_LO_DELIVERY_STATUS RT_BIT(12) +%define XAPIC_ICR_LO_LEVEL RT_BIT(14) +%define XAPIC_ICR_TRIGGER_MODE RT_BIT(15) +%define XAPIC_ICR_LO_DEST_SHORTHAND (RT_BIT(18) | RT_BIT(19)) +%define XAPIC_ICR_LO_WR_VALID ( XAPIC_ICR_LO_VECTOR | XAPIC_ICR_LO_DELIVERY_MODE | XAPIC_ICR_LO_DEST_MODE \ + | XAPIC_ICR_LO_LEVEL | XAPIC_ICR_TRIGGER_MODE | XAPIC_ICR_LO_DEST_SHORTHAND) +%define XAPIC_ICR_HI_DEST 0xff000000 +%define XAPIC_ICR_HI_GET_DEST(a_u32IcrHi) (((a_u32IcrHi) >> 24) & XAPIC_ICR_HI_DEST) +%define XAPIC_ICR_HI_WR_VALID XAPIC_ICR_HI_DEST +%define X2APIC_ID_BROADCAST_MASK 0xffffffff + %define XAPIC_ID_BROADCAST_MASK_P4 0xff +%define X2APIC_GET_XAPIC_OFF(a_uMsr) ((((a_uMsr) - MSR_IA32_X2APIC_START) << 4) & 0xff0) +%define XAPIC_GET_X2APIC_MSR(a_offReg) ((((a_offReg) & 0xff0) >> 4) | MSR_IA32_X2APIC_START) +%define XAPIC_OFF_ID 0x020 +%define XAPIC_OFF_VERSION 0x030 +%define XAPIC_OFF_TPR 0x080 +%define XAPIC_OFF_APR 0x090 +%define XAPIC_OFF_PPR 0x0A0 +%define XAPIC_OFF_EOI 0x0B0 +%define XAPIC_OFF_RRD 0x0C0 +%define XAPIC_OFF_LDR 0x0D0 +%define XAPIC_OFF_DFR 0x0E0 +%define XAPIC_OFF_SVR 0x0F0 +%define XAPIC_OFF_ISR0 0x100 +%define XAPIC_OFF_ISR1 0x110 +%define XAPIC_OFF_ISR2 0x120 +%define XAPIC_OFF_ISR3 0x130 +%define XAPIC_OFF_ISR4 0x140 +%define XAPIC_OFF_ISR5 0x150 +%define XAPIC_OFF_ISR6 0x160 +%define XAPIC_OFF_ISR7 0x170 +%define XAPIC_OFF_TMR0 0x180 +%define XAPIC_OFF_TMR1 0x190 +%define XAPIC_OFF_TMR2 0x1A0 +%define XAPIC_OFF_TMR3 0x1B0 +%define XAPIC_OFF_TMR4 0x1C0 +%define XAPIC_OFF_TMR5 0x1D0 +%define XAPIC_OFF_TMR6 0x1E0 +%define XAPIC_OFF_TMR7 0x1F0 +%define XAPIC_OFF_IRR0 0x200 +%define XAPIC_OFF_IRR1 0x210 +%define XAPIC_OFF_IRR2 0x220 +%define XAPIC_OFF_IRR3 0x230 +%define XAPIC_OFF_IRR4 0x240 +%define XAPIC_OFF_IRR5 0x250 +%define XAPIC_OFF_IRR6 0x260 +%define XAPIC_OFF_IRR7 0x270 +%define XAPIC_OFF_ESR 0x280 +%define XAPIC_OFF_LVT_CMCI 0x2F0 +%define XAPIC_OFF_ICR_LO 0x300 +%define XAPIC_OFF_ICR_HI 0x310 +%define XAPIC_OFF_LVT_TIMER 0x320 +%define XAPIC_OFF_LVT_THERMAL 0x330 +%define XAPIC_OFF_LVT_PERF 0x340 +%define XAPIC_OFF_LVT_LINT0 0x350 +%define XAPIC_OFF_LVT_LINT1 0x360 +%define XAPIC_OFF_LVT_ERROR 0x370 +%define XAPIC_OFF_TIMER_ICR 0x380 +%define XAPIC_OFF_TIMER_CCR 0x390 +%define XAPIC_OFF_TIMER_DCR 0x3E0 +%define X2APIC_OFF_SELF_IPI 0x3F0 +%define XAPIC_OFF_LVT_START XAPIC_OFF_LVT_TIMER +%define XAPIC_OFF_LVT_END XAPIC_OFF_LVT_ERROR +%define XAPIC_OFF_LVT_EXT_START XAPIC_OFF_LVT_CMCI +%define XAPIC_OFF_LVT_EXT_END XAPIC_OFF_LVT_CMCI +%define XAPIC_OFF_END 0x3F0 +%ifdef IPRT_INCLUDED_asm_amd64_x86_h +%endif +%endif diff --git a/include/VBox/asmdefs.mac b/include/VBox/asmdefs.mac new file mode 100644 index 00000000..0e167033 --- /dev/null +++ b/include/VBox/asmdefs.mac @@ -0,0 +1,785 @@ +;; @file +; VirtualBox YASM/NASM macros, structs, etc. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_asmdefs_mac +%define ___VBox_asmdefs_mac + +;; @def VBOX_WITH_STATISTICS +; When defined all statistics will be included in the build. +; This is enabled by default in all debug builds. +%ifndef VBOX_WITH_STATISTICS + %ifdef DEBUG + %define VBOX_WITH_STATISTICS + %endif +%endif + +%include "iprt/asmdefs.mac" + +;; @def VBOX_STRICT +; Enables strict checks in the VBox code. +; This is enabled by default in all debug builds and when RT_STRICT is enabled. +%ifndef VBOX_STRICT + %ifdef DEBUG + %define VBOX_STRICT + %endif + %ifdef RT_STRICT + %define VBOX_STRICT + %endif +%endif + + +%ifndef VBOX_UART_BASE + %ifndef IPRT_UART_BASE + %define VBOX_UART_BASE 3f8h ; COM1 (see src/VBox/Runtime/common/log/logcom.cpp) + %else + %define VBOX_UART_BASE IPRT_UART_BASE + %endif +%endif +%ifndef VBOX_UART_RATE + %define VBOX_UART_RATE 12 ; 9600 bps +%endif +%ifndef VBOX_UART_PARAMS + %define VBOX_UART_PARAMS 00000011b ; 8n1 +%endif + + +;; +; Initializes the com port to 9600 baud 8n1. +; al and dx are wasted. +; @todo comport init doesn't quite work - therefore we no longer use this! :-/ +; @todo test again, it might work now... +%macro COM_INIT 0 + push eax + push edx + + mov dx, VBOX_UART_BASE + 2 + mov al, 0 + out dx, al ; Disable the fifos (old software relies on it) + + mov dx, VBOX_UART_BASE + 3 + mov al, 80h + out dx, al ; make DL register accessible + + mov dx, VBOX_UART_BASE + mov ax, VBOX_UART_RATE + out dx, al ; write low bps rate divisor + + mov dx, VBOX_UART_BASE+1 + xchg al, ah + out dx, al ; write high bps rate divisor + + mov dx, VBOX_UART_BASE + 3 + mov al, VBOX_UART_PARAMS + out dx, al ; write parameters & lock divisor + + mov dx, VBOX_UART_BASE + 4 ; disconnect the UART from the int line + mov al, 0 + out dx, al + + mov dx, VBOX_UART_BASE + 1 ; disable UART ints + out dx, al + + mov dx, VBOX_UART_BASE + in al, dx ; clear receiver + mov dx, VBOX_UART_BASE + 5 + in al, dx ; clear line status + inc dx + in al, dx ; clear modem status + mov dx, VBOX_UART_BASE + 2 + in al, dx ; clear interrupts (IIR) + + pop edx + pop eax +%endmacro + + +;; +; writes string to comport +; trashes nothing (uses stack though) + +%macro COM32_S_PRINT 1+ + push esi + push ecx + push eax + mov ecx, edx + shl ecx, 16 + + call %%stringend +%%string: db %1 +%%stringend: + pop esi + mov cx, %%stringend - %%string +%%status: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status + + mov al, [esi] + mov dx, VBOX_UART_BASE + out dx, al + inc esi + dec cx + jnz short %%status + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + shr ecx, 16 + mov dx, cx + pop eax + pop ecx + pop esi +%endmacro + +%macro COM64_S_PRINT 1+ + push rsi + push rdx + push rcx + push rax + + jmp %%stringend +%%string: db %1 +%%stringend: + lea rsi, [%%string wrt rip] + mov cx, %%stringend - %%string +%%status: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status + + mov al, [rsi] + mov dx, VBOX_UART_BASE + out dx, al + inc rsi + dec cx + jnz short %%status + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + pop rax + pop rcx + pop rdx + pop rsi +%endmacro + +%macro COM_S_PRINT 1+ +%ifdef RT_ARCH_AMD64 + COM64_S_PRINT %1 +%else + COM32_S_PRINT %1 +%endif +%endmacro + + +;; Write char. +; trashes esi +%macro COM_CHAR 1 + mov esi, eax + shl esi, 16 + mov si, dx + +%%status: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status + + mov al, %1 + mov dx, VBOX_UART_BASE + out dx, al + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + mov dx, si + shr esi, 16 + mov ax, si +%endmacro + + +;; Write char. +; trashes nothing (uses stack though) + +%macro COM32_S_CHAR 1 + push eax + push edx + +%%status: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status + + mov al, %1 + mov dx, VBOX_UART_BASE + out dx, al + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + pop edx + pop eax +%endmacro + +%macro COM64_S_CHAR 1 + push rax + push rdx + +%%status: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status + + mov al, %1 + mov dx, VBOX_UART_BASE + out dx, al + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + pop rdx + pop rax +%endmacro + +%macro COM_S_CHAR 1 +%ifdef RT_ARCH_AMD64 + COM64_S_CHAR %1 +%else + COM32_S_CHAR %1 +%endif +%endmacro + + +;; Writes newline +; trashes esi +%macro COM_NEWLINE 0 + mov esi, eax + shl esi, 16 + mov si, dx + +%%status1: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status1 + + mov al, 13 + mov dx, VBOX_UART_BASE + out dx, al + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + mov al, 10 + mov dx, VBOX_UART_BASE + out dx, al + +%%status3: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status3 + + mov dx, si + shr esi, 16 + mov ax, si +%endmacro + + +;; Writes newline +; trashes nothing (uses stack though) + +%macro COM32_S_NEWLINE 0 + push edx + push eax + +%%status1: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status1 + + mov al, 13 + mov dx, VBOX_UART_BASE + out dx, al + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + mov al, 10 + mov dx, VBOX_UART_BASE + out dx, al + +%%status3: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status3 + + pop eax + pop edx +%endmacro + +%macro COM64_S_NEWLINE 0 + push rdx + push rax + +%%status1: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status1 + + mov al, 13 + mov dx, VBOX_UART_BASE + out dx, al + +%%status2: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status2 + + mov al, 10 + mov dx, VBOX_UART_BASE + out dx, al + +%%status3: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status3 + + pop rax + pop rdx +%endmacro + +%macro COM_S_NEWLINE 0 +%ifdef RT_ARCH_AMD64 + COM64_S_NEWLINE +%else + COM32_S_NEWLINE +%endif +%endmacro + + +;; Writes a dword from register to com port. +; trashes esi, edi +; edi cannot be used as input register +%macro COM_DWORD_REG 1 + mov edi, ebx ; save ebx + mov ebx, %1 ; get value we're supposed to print + mov esi, eax ; save ax + shl esi, 16 ; save dx + mov si, dx + + mov ah, 8 ; loop counter. +%%daloop: + rol ebx, 4 ; shift next digit to the front + +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + dec ah + jnz short %%daloop ; loop + + mov dx, si ; restore dx + shr esi, 16 + mov ax, si ; restore ax + mov ebx, edi ; restore ebx +%endmacro + + +;; Writes a dword from register to com port. +; trashes nothing (uses stack though) + +%macro COM32_S_DWORD_REG 1 + push edx + push eax + push ebx + + mov ebx, %1 ; get value we're supposed to print + + mov ah, 8 ; loop counter. +%%daloop: + rol ebx, 4 ; shift next digit to the front + +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + dec ah + jnz short %%daloop ; loop + + pop ebx + pop eax + pop edx +%endmacro + +%macro COM64_S_DWORD_REG 1 + push rdx + push rax + push rbx + + mov ebx, %1 ; get value we're supposed to print + + mov ah, 8 ; loop counter. +%%daloop: + rol ebx, 4 ; shift next digit to the front + +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + dec ah + jnz short %%daloop ; loop + + pop rbx + pop rax + pop rdx +%endmacro + +%macro COM_S_DWORD_REG 1 +%ifdef RT_ARCH_AMD64 + COM64_S_DWORD_REG %1 +%else + COM32_S_DWORD_REG %1 +%endif +%endmacro + + +;; Writes a qword from register to com port. +; trashes nothing (uses stack though) +%macro COM64_S_QWORD_REG 1 + push rdx + push rax + push rbx + + mov rbx, %1 ; get value we're supposed to print + + mov ah, 16 ; loop counter. +%%daloop: + rol rbx, 4 ; shift next digit to the front + +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + dec ah + jnz short %%daloop ; loop + + pop rbx + pop rax + pop rdx +%endmacro + + +;; Writes a byte from register to com port. +; trashes nothing (uses stack though) + +%macro COM32_S_BYTE_REG 1 + push edx + push eax + push ebx + + mov ebx, %1 ; get value we're supposed to print + + mov ah, 2 ; loop counter. + ror ebx, 8 ; shift next digit to the front +%%daloop: + rol ebx, 4 ; shift next digit to the front + +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + dec ah + jnz short %%daloop ; loop + + pop ebx + pop eax + pop edx +%endmacro + +%macro COM64_S_BYTE_REG 1 + push rdx + push rax + push rbx + + mov ebx, %1 ; get value we're supposed to print + + mov ah, 2 ; loop counter. + ror ebx, 8 ; shift next digit to the front +%%daloop: + rol ebx, 4 ; shift next digit to the front + +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + dec ah + jnz short %%daloop ; loop + + pop rbx + pop rax + pop rdx +%endmacro + +%macro COM_S_BYTE_REG 1 +%ifdef RT_ARCH_AMD64 + COM64_S_BYTE_REG %1 +%else + COM32_S_BYTE_REG %1 +%endif +%endmacro + + + +;; Writes a single hex digit from register to com port. +; trashes nothing (uses stack though) + +%macro COM32_S_DIGIT_REG 1 + push edx + push eax + push ebx + + mov ebx, %1 ; get value we're supposed to print +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + pop ebx + pop eax + pop edx +%endmacro + +%macro COM64_S_DIGIT_REG 1 + push rdx + push rax + push rbx + + mov ebx, %1 ; get value we're supposed to print +%%status0: + mov dx, VBOX_UART_BASE + 5 + in al, dx + test al, 20h + jz short %%status0 + + mov al, bl ; get next char + and al, 0fh + cmp al, 10 + jae short %%hex ; yasm BUG! It sometimes generate a near jump here. YASMCHECK! + add al, '0' + jmp short %%print +%%hex: + add al, 'a' - 10 +%%print: + mov dx, VBOX_UART_BASE + out dx, al + + pop rbx + pop rax + pop rdx +%endmacro + +%macro COM_S_DIGIT_REG 1 +%ifdef RT_ARCH_AMD64 + COM64_S_DIGIT_REG %1 +%else + COM32_S_DIGIT_REG %1 +%endif +%endmacro + + +;; +; Loops for a while. +; ecx is trashed. +%macro LOOP_A_WHILE 0 + + xor ecx, ecx + dec ecx + shr ecx, 1 +%%looplabel: + nop + nop + nop + dec ecx + jnz short %%looplabel + +%endmacro + + +;; +; Loops for a short while. +; ecx is trashed. +%macro LOOP_SHORT_WHILE 0 + + xor ecx, ecx + dec ecx + shr ecx, 4 +%%looplabel: + nop + nop + dec ecx + jnz short %%looplabel + +%endmacro + +%endif + diff --git a/include/VBox/ata.h b/include/VBox/ata.h new file mode 100644 index 00000000..3a8be20f --- /dev/null +++ b/include/VBox/ata.h @@ -0,0 +1,222 @@ +/* $Id: ata.h $ */ +/** @file + * VBox storage devices: ATA/ATAPI declarations + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_ata_h +#define VBOX_INCLUDED_ata_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/* Bits of HD_STATUS */ +#define ATA_STAT_ERR 0x01 +#define ATA_STAT_INDEX 0x02 +#define ATA_STAT_ECC 0x04 /* Corrected error */ +#define ATA_STAT_DRQ 0x08 +#define ATA_STAT_SEEK 0x10 +#define ATA_STAT_SRV 0x10 +#define ATA_STAT_WRERR 0x20 +#define ATA_STAT_READY 0x40 +#define ATA_STAT_BUSY 0x80 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define MCR_ERR 0x08 /* media change request */ +#define ID_ERR 0x10 /* ID field not found */ +#define MC_ERR 0x20 /* media changed */ +#define ECC_ERR 0x40 /* Uncorrectable ECC error */ +#define BBD_ERR 0x80 /* pre-EIDE meaning: block marked bad */ +#define ICRC_ERR 0x80 /* new meaning: CRC error during transfer */ + +/* Bits for uATARegDevCtl. */ +#define ATA_DEVCTL_DISABLE_IRQ 0x02 +#define ATA_DEVCTL_RESET 0x04 +#define ATA_DEVCTL_HOB 0x80 + + +/* ATA/ATAPI Commands (as of ATA/ATAPI-8 draft T13/1699D Revision 3a). + * Please keep this in sync with g_apszATACmdNames. */ +typedef enum ATACMD +{ + ATA_NOP = 0x00, + ATA_CFA_REQUEST_EXTENDED_ERROR_CODE = 0x03, + ATA_DATA_SET_MANAGEMENT = 0x06, + ATA_DEVICE_RESET = 0x08, + ATA_RECALIBRATE = 0x10, + ATA_READ_SECTORS = 0x20, + ATA_READ_SECTORS_WITHOUT_RETRIES = 0x21, + ATA_READ_LONG = 0x22, + ATA_READ_LONG_WITHOUT_RETRIES = 0x23, + ATA_READ_SECTORS_EXT = 0x24, + ATA_READ_DMA_EXT = 0x25, + ATA_READ_DMA_QUEUED_EXT = 0x26, + ATA_READ_NATIVE_MAX_ADDRESS_EXT = 0x27, + ATA_READ_MULTIPLE_EXT = 0x29, + ATA_READ_STREAM_DMA_EXT = 0x2a, + ATA_READ_STREAM_EXT = 0x2b, + ATA_READ_LOG_EXT = 0x2f, + ATA_WRITE_SECTORS = 0x30, + ATA_WRITE_SECTORS_WITHOUT_RETRIES = 0x31, + ATA_WRITE_LONG = 0x32, + ATA_WRITE_LONG_WITHOUT_RETRIES = 0x33, + ATA_WRITE_SECTORS_EXT = 0x34, + ATA_WRITE_DMA_EXT = 0x35, + ATA_WRITE_DMA_QUEUED_EXT = 0x36, + ATA_SET_MAX_ADDRESS_EXT = 0x37, + ATA_CFA_WRITE_SECTORS_WITHOUT_ERASE = 0x38, + ATA_WRITE_MULTIPLE_EXT = 0x39, + ATA_WRITE_STREAM_DMA_EXT = 0x3a, + ATA_WRITE_STREAM_EXT = 0x3b, + ATA_WRITE_VERIFY = 0x3c, + ATA_WRITE_DMA_FUA_EXT = 0x3d, + ATA_WRITE_DMA_QUEUED_FUA_EXT = 0x3e, + ATA_WRITE_LOG_EXT = 0x3f, + ATA_READ_VERIFY_SECTORS = 0x40, + ATA_READ_VERIFY_SECTORS_WITHOUT_RETRIES = 0x41, + ATA_READ_VERIFY_SECTORS_EXT = 0x42, + ATA_WRITE_UNCORRECTABLE_EXT = 0x45, + ATA_READ_LOG_DMA_EXT = 0x47, + ATA_FORMAT_TRACK = 0x50, + ATA_CONFIGURE_STREAM = 0x51, + ATA_WRITE_LOG_DMA_EXT = 0x57, + ATA_TRUSTED_RECEIVE = 0x5c, + ATA_TRUSTED_RECEIVE_DMA = 0x5d, + ATA_TRUSTED_SEND = 0x5e, + ATA_TRUSTED_SEND_DMA = 0x5f, + ATA_READ_FPDMA_QUEUED = 0x60, + ATA_WRITE_FPDMA_QUEUED = 0x61, + ATA_SEEK = 0x70, + ATA_CFA_TRANSLATE_SECTOR = 0x87, + ATA_EXECUTE_DEVICE_DIAGNOSTIC = 0x90, + ATA_INITIALIZE_DEVICE_PARAMETERS = 0x91, + ATA_DOWNLOAD_MICROCODE = 0x92, + ATA_STANDBY_IMMEDIATE__ALT = 0x94, + ATA_IDLE_IMMEDIATE__ALT = 0x95, + ATA_STANDBY__ALT = 0x96, + ATA_IDLE__ALT = 0x97, + ATA_CHECK_POWER_MODE__ALT = 0x98, + ATA_SLEEP__ALT = 0x99, + ATA_PACKET = 0xa0, + ATA_IDENTIFY_PACKET_DEVICE = 0xa1, + ATA_SERVICE = 0xa2, + ATA_SMART = 0xb0, + ATA_DEVICE_CONFIGURATION_OVERLAY = 0xb1, + ATA_NV_CACHE = 0xb6, + ATA_CFA_ERASE_SECTORS = 0xc0, + ATA_READ_MULTIPLE = 0xc4, + ATA_WRITE_MULTIPLE = 0xc5, + ATA_SET_MULTIPLE_MODE = 0xc6, + ATA_READ_DMA_QUEUED = 0xc7, + ATA_READ_DMA = 0xc8, + ATA_READ_DMA_WITHOUT_RETRIES = 0xc9, + ATA_WRITE_DMA = 0xca, + ATA_WRITE_DMA_WITHOUT_RETRIES = 0xcb, + ATA_WRITE_DMA_QUEUED = 0xcc, + ATA_CFA_WRITE_MULTIPLE_WITHOUT_ERASE = 0xcd, + ATA_WRITE_MULTIPLE_FUA_EXT = 0xce, + ATA_CHECK_MEDIA_CARD_TYPE = 0xd1, + ATA_GET_MEDIA_STATUS = 0xda, + ATA_ACKNOWLEDGE_MEDIA_CHANGE = 0xdb, + ATA_BOOT_POST_BOOT = 0xdc, + ATA_BOOT_PRE_BOOT = 0xdd, + ATA_MEDIA_LOCK = 0xde, + ATA_MEDIA_UNLOCK = 0xdf, + ATA_STANDBY_IMMEDIATE = 0xe0, + ATA_IDLE_IMMEDIATE = 0xe1, + ATA_STANDBY = 0xe2, + ATA_IDLE = 0xe3, + ATA_READ_BUFFER = 0xe4, + ATA_CHECK_POWER_MODE = 0xe5, + ATA_SLEEP = 0xe6, + ATA_FLUSH_CACHE = 0xe7, + ATA_WRITE_BUFFER = 0xe8, + ATA_WRITE_SAME = 0xe9, + ATA_FLUSH_CACHE_EXT = 0xea, + ATA_IDENTIFY_DEVICE = 0xec, + ATA_MEDIA_EJECT = 0xed, + ATA_IDENTIFY_DMA = 0xee, + ATA_SET_FEATURES = 0xef, + ATA_SECURITY_SET_PASSWORD = 0xf1, + ATA_SECURITY_UNLOCK = 0xf2, + ATA_SECURITY_ERASE_PREPARE = 0xf3, + ATA_SECURITY_ERASE_UNIT = 0xf4, + ATA_SECURITY_FREEZE_LOCK = 0xf5, + ATA_SECURITY_DISABLE_PASSWORD = 0xf6, + ATA_READ_NATIVE_MAX_ADDRESS = 0xf8, + ATA_SET_MAX = 0xf9 +} ATACMD; + + +#define ATA_MODE_MDMA 0x20 +#define ATA_MODE_UDMA 0x40 + + +#define ATA_TRANSFER_ID(thismode, maxspeed, currmode) \ + ( ((1 << (maxspeed + 1)) - 1) \ + | ((((thismode ^ currmode) & 0xf8) == 0) ? 1 << ((currmode & 0x07) + 8) : 0)) + +/** + * Length of the ATA VPD data (without termination) + */ +#define ATA_SERIAL_NUMBER_LENGTH 20 +#define ATA_FIRMWARE_REVISION_LENGTH 8 +#define ATA_MODEL_NUMBER_LENGTH 40 + +/** Mask to get the LBA value from a LBA range. */ +#define ATA_RANGE_LBA_MASK UINT64_C(0xffffffffffff) +/** Mas to get the length value from a LBA range. */ +#define ATA_RANGE_LENGTH_MASK UINT64_C(0xffff000000000000) +/** Returns the length of the range in sectors. */ +#define ATA_RANGE_LENGTH_GET(val) (((val) & ATA_RANGE_LENGTH_MASK) >> 48) + +/* ATAPI defines */ + +#define ATAPI_PACKET_SIZE 12 + + +#define ATAPI_INT_REASON_CD 0x01 /* 0 = data transfer */ +#define ATAPI_INT_REASON_IO 0x02 /* 1 = transfer to the host */ +#define ATAPI_INT_REASON_REL 0x04 +#define ATAPI_INT_REASON_TAG_MASK 0xf8 + +#if defined(LOG_ENABLED) && defined(IN_RING3) +const char * ATACmdText(uint8_t uCmd); +#endif + +#endif /* !VBOX_INCLUDED_ata_h */ + diff --git a/include/VBox/bios.h b/include/VBox/bios.h new file mode 100644 index 00000000..9b75ab3f --- /dev/null +++ b/include/VBox/bios.h @@ -0,0 +1,56 @@ +/** @file + * X86 (and AMD64) Local APIC registers (VMM,++). + * + * bios.mac is generated from this file by running 'kmk -f Maintenance.kmk incs'. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_bios_h +#define VBOX_INCLUDED_bios_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/** The BIOS shutdown port. + * You write "Shutdown" byte by byte to shutdown the VM. + * @sa VBOX_BIOS_OLD_SHUTDOWN_PORT */ +#define VBOX_BIOS_SHUTDOWN_PORT 0x040f + +/** The old shutdown port number. + * Older versions of VirtualBox uses this as does Bochs. + * @sa VBOX_BIOS_SHUTDOWN_PORT */ +#define VBOX_BIOS_OLD_SHUTDOWN_PORT 0x8900 + + +#endif /* !VBOX_INCLUDED_bios_h */ + diff --git a/include/VBox/bios.mac b/include/VBox/bios.mac new file mode 100644 index 00000000..a38627ad --- /dev/null +++ b/include/VBox/bios.mac @@ -0,0 +1,44 @@ +;; @file +; X86 (and AMD64) Local APIC registers (VMM,++). +; +; Automatically generated by various.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2017-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef VBOX_INCLUDED_bios_h +%define VBOX_INCLUDED_bios_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%define VBOX_BIOS_SHUTDOWN_PORT 0x040f +%define VBOX_BIOS_OLD_SHUTDOWN_PORT 0x8900 +%endif diff --git a/include/VBox/bioslogo.h b/include/VBox/bioslogo.h new file mode 100644 index 00000000..4738f1ef --- /dev/null +++ b/include/VBox/bioslogo.h @@ -0,0 +1,108 @@ +/* $Id: bioslogo.h $ */ +/** @file + * BiosLogo - The Private BIOS Logo Interface. (DEV) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_bioslogo_h +#define VBOX_INCLUDED_bioslogo_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef VBOX_PC_BIOS +# include +# include +#endif + +/** @defgroup grp_bios_logo The Private BIOS Logo Interface. + * @ingroup grp_devdrv + * @internal + * + * @remark All this is currently duplicated in logo.c. + * + * @{ + */ + +/** The extra port which is used to show the BIOS logo. */ +#define LOGO_IO_PORT 0x3b8 + +/** The BIOS logo fade in/fade out steps. */ +#define LOGO_SHOW_STEPS 16 + +/** @name The BIOS logo commands. + * @{ + */ +#define LOGO_CMD_NOP 0 +#define LOGO_CMD_SET_OFFSET 0x100 +#define LOGO_CMD_SHOW_BMP 0x200 +/** @} */ + +/** + * PC Bios logo data structure. + */ +typedef struct LOGOHDR +{ + /** Signature (LOGO_HDR_MAGIC/0x66BB). */ + uint16_t u16Signature; + /** Logo time (msec). */ + uint16_t u16LogoMillies; + /** Fade in - boolean. */ + uint8_t fu8FadeIn; + /** Fade out - boolean. */ + uint8_t fu8FadeOut; + /** Show setup - boolean. */ + uint8_t fu8ShowBootMenu; + /** Reserved / padding. */ + uint8_t u8Reserved; + /** Logo file size. */ + uint32_t cbLogo; +} LOGOHDR; +#ifndef VBOX_PC_BIOS +AssertCompileSize(LOGOHDR, 12); +#endif +/** Pointer to a PC BIOS logo header. */ +typedef LOGOHDR *PLOGOHDR; +/** Pointer to a const PC BIOS logo header. */ +typedef LOGOHDR const *PCLOGOHDR; + +/** The value of the LOGOHDR::u16Signature field. */ +#define LOGO_HDR_MAGIC 0x66BB + +/** The value which will switch you the default logo. */ +#define LOGO_DEFAULT_LOGO 0xFFFF + +/** @} */ + +#endif /* !VBOX_INCLUDED_bioslogo_h */ + diff --git a/include/VBox/cdefs.h b/include/VBox/cdefs.h new file mode 100644 index 00000000..a77389d6 --- /dev/null +++ b/include/VBox/cdefs.h @@ -0,0 +1,493 @@ +/** @file + * VirtualBox - Common C and C++ definition. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_cdefs_h +#define VBOX_INCLUDED_cdefs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/** @defgroup grp_vbox_cdefs VBox Common Defintions and Macros + * @{ + */ + +/** @def VBOX_WITH_STATISTICS + * When defined all statistics will be included in the build. + * This is enabled by default in all debug builds. + */ +#ifndef VBOX_WITH_STATISTICS +# ifdef DEBUG +# define VBOX_WITH_STATISTICS +# endif +#endif + +/** @def VBOX_STRICT + * Alias for RT_STRICT. + */ +#ifdef RT_STRICT +# ifndef VBOX_STRICT +# define VBOX_STRICT +# endif +#endif + +/** @def VBOX_STRICT_GUEST + * Be strict on guest input. This can be overriden on the compiler command line + * or per source file by defining VBOX_NO_STRICT_GUEST. + * + * @sa VBox/assert.h and its ASSERT_GUEST_XXXX macros. + */ +#ifndef VBOX_STRICT_GUEST +# ifdef VBOX_STRICT +# define VBOX_STRICT_GUEST +# endif +#endif +/** @def VBOX_NO_STRICT_GUEST + * Define to override VBOX_STRICT_GUEST, disabling asserting on guest input. */ +#ifdef VBOX_NO_STRICT_GUEST +# undef VBOX_STRICT_GUEST +#endif + + +/* + * Shut up DOXYGEN warnings and guide it properly thru the code. + */ +#ifdef DOXYGEN_RUNNING +#define VBOX_WITH_STATISTICS +#define VBOX_STRICT +#define VBOX_STRICT_GUEST +#define VBOX_NO_STRICT_GUEST +#define IN_DBG +#define IN_DIS +#define IN_INTNET_R0 +#define IN_INTNET_R3 +#define IN_PCIRAW_R0 +#define IN_PCIRAW_R3 +#define IN_REM_R3 +#define IN_SUP_R0 +#define IN_SUP_R3 +#define IN_SUP_RC +#define IN_SUP_STATIC +#define IN_USBLIB +#define IN_VBOXDDU +#define IN_VMM_RC +#define IN_VMM_R0 +#define IN_VMM_R3 +#define IN_VMM_STATIC +#endif + + + + +/** @def VBOXCALL + * The standard calling convention for VBOX interfaces. + */ +#define VBOXCALL RTCALL + + + +/** @def IN_DIS + * Used to indicate whether we're inside the same link module as the + * disassembler. + */ +/** @def DISDECL(type) + * Disassembly export or import declaration. + * @param type The return type of the function declaration. + */ +#if defined(IN_DIS) +# ifdef IN_DIS_STATIC +# define DISDECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define DISDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +# endif +#else +# define DISDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_DBG + * Used to indicate whether we're inside the same link module as the debugger + * console, gui, and related things (ring-3). + */ +/** @def DBGDECL(type) + * Debugger module export or import declaration. + * Functions declared using this exists only in R3 since the + * debugger modules is R3 only. + * @param type The return type of the function declaration. + */ +#if defined(IN_DBG_R3) || defined(IN_DBG) +# define DBGDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define DBGDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_INTNET_R3 + * Used to indicate whether we're inside the same link module as the Ring-3 + * Internal Networking Service. + */ +/** @def INTNETR3DECL(type) + * Internal Networking Service export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_INTNET_R3 +# define INTNETR3DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define INTNETR3DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + +/** @def IN_INTNET_R0 + * Used to indicate whether we're inside the same link module as the R0 + * Internal Network Service. + */ +/** @def INTNETR0DECL(type) + * Internal Networking Service export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_INTNET_R0 +# define INTNETR0DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define INTNETR0DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_PCIRAW_R3 + * Used to indicate whether we're inside the same link module as the Ring-3 + * PCI passthrough support. + */ +/** @def PCIRAWR3DECL(type) + * PCI passthrough export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_PCIRAW_R3 +# define PCIRAWR3DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define PCIRAWR3DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + +/** @def IN_PCIRAW_R0 + * Used to indicate whether we're inside the same link module as the R0 + * PCI passthrough support. + */ +/** @def PCIRAWR0DECL(type) + * PCI passthroug export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_PCIRAW_R0 +# define PCIRAWR0DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define PCIRAWR0DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_REM_R3 + * Used to indicate whether we're inside the same link module as + * the HC Ring-3 Recompiled Execution Manager. + */ +/** @def REMR3DECL(type) + * Recompiled Execution Manager HC Ring-3 export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_REM_R3 +# define REMR3DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define REMR3DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_SUP_R3 + * Used to indicate whether we're inside the same link module as the Ring-3 + * Support Library or not. + */ +/** @def SUPR3DECL(type) + * Support library export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_SUP_R3 +# ifdef IN_SUP_STATIC +# define SUPR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define SUPR3DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +# endif +#else +# ifdef IN_SUP_STATIC +# define SUPR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define SUPR3DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +# endif +#endif + +/** @def IN_SUP_R0 + * Used to indicate whether we're inside the same link module as the Ring-0 + * Support Library or not. + */ +/** @def IN_SUP_STATIC + * Used to indicate that the Support Library is built or used as a static + * library. + */ +/** @def SUPR0DECL(type) + * Support library export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_SUP_R0 +# ifdef IN_SUP_STATIC +# define SUPR0DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define SUPR0DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +# endif +#else +# ifdef IN_SUP_STATIC +# define SUPR0DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define SUPR0DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +# endif +#endif + +/** @def IN_SUP_RC + * Used to indicate whether we're inside the same link module as the RC Support + * Library or not. + */ +/** @def SUPRCDECL(type) + * Support library export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_SUP_RC +# define SUPRCDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define SUPRCDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + +/** @def IN_SUP_R0 + * Used to indicate whether we're inside the same link module as the Ring-0 + * Support Library or not. + */ +/** @def SUPR0DECL(type) + * Support library export or import declaration. + * @param type The return type of the function declaration. + */ +#if defined(IN_SUP_R0) || defined(IN_SUP_R3) || defined(IN_SUP_RC) +# define SUPDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define SUPDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_USBLIB + * Used to indicate whether we're inside the same link module as the USBLib. + */ +/** @def USBLIB_DECL + * USBLIB export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_RING0 +# define USBLIB_DECL(type) type VBOXCALL +#elif defined(IN_USBLIB) +# define USBLIB_DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define USBLIB_DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + + + +/** @def IN_VMM_STATIC + * Used to indicate that the virtual machine monitor is built or used as a + * static library. + */ +/** @def IN_VMM_R3 + * Used to indicate whether we're inside the same link module as the ring 3 part of the + * virtual machine monitor or not. + */ +/** @def VMMR3DECL + * Ring-3 VMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_R3 +# ifdef IN_VMM_STATIC +# define VMMR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define VMMR3DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +# endif +#elif defined(IN_RING3) +# ifdef IN_VMM_STATIC +# define VMMR3DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +# else +# define VMMR3DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +# endif +#else +# define VMMR3DECL(type) DECL_INVALID(type) +#endif + +/** @def IN_VMM_R0 + * Used to indicate whether we're inside the same link module as the ring-0 part + * of the virtual machine monitor or not. + */ +/** @def VMMR0DECL + * Ring-0 VMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_R0 +# define VMMR0DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#elif defined(IN_RING0) +# define VMMR0DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#else +# define VMMR0DECL(type) DECL_INVALID(type) +#endif + +/** @def IN_VMM_RC + * Used to indicate whether we're inside the same link module as the raw-mode + * context part of the virtual machine monitor or not. + */ +/** @def VMMRCDECL + * Raw-mode context VMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_RC +# define VMMRCDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#elif defined(IN_RC) +# define VMMRCDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#else +# define VMMRCDECL(type) DECL_INVALID(type) +#endif + +/** @def VMMRZDECL + * Ring-0 and Raw-mode context VMM export or import declaration. + * @param type The return type of the function declaration. + */ +#if defined(IN_VMM_R0) || defined(IN_VMM_RC) +# define VMMRZDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#elif defined(IN_RING0) || defined(IN_RZ) +# define VMMRZDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#else +# define VMMRZDECL(type) DECL_INVALID(type) +#endif + +/** @def VMMDECL + * VMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_STATIC +# define VMMDECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +#elif defined(IN_VMM_R3) || defined(IN_VMM_R0) || defined(IN_VMM_RC) +# define VMMDECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +#else +# define VMMDECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + +/** @def VMM_INT_DECL + * VMM internal function. + * @param type The return type of the function declaration. + */ +#if defined(IN_VMM_R3) || defined(IN_VMM_R0) || defined(IN_VMM_RC) +# define VMM_INT_DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +#else +# define VMM_INT_DECL(type) DECL_INVALID(type) +#endif + +/** @def VMMR3_INT_DECL + * VMM internal function, ring-3. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_R3 +# define VMMR3_INT_DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +#else +# define VMMR3_INT_DECL(type) DECL_INVALID(type) +#endif + +/** @def VMMR0_INT_DECL + * VMM internal function, ring-0. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_R0 +# define VMMR0_INT_DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +#else +# define VMMR0_INT_DECL(type) DECL_INVALID(type) +#endif + +/** @def VMMRC_INT_DECL + * VMM internal function, raw-mode context. + * @param type The return type of the function declaration. + */ +#ifdef IN_VMM_RC +# define VMMRC_INT_DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +#else +# define VMMRC_INT_DECL(type) DECL_INVALID(type) +#endif + +/** @def VMMRZ_INT_DECL + * VMM internal function, ring-0 + raw-mode context. + * @param type The return type of the function declaration. + */ +#if defined(IN_VMM_RC) || defined(IN_VMM_R0) +# define VMMRZ_INT_DECL(type) DECL_HIDDEN_NOTHROW(type) VBOXCALL +#else +# define VMMRZ_INT_DECL(type) DECL_INVALID(type) +#endif + + + +/** @def IN_VBOXDDU + * Used to indicate whether we're inside the VBoxDDU shared object. + */ +/** @def VBOXDDU_DECL(type) + * VBoxDDU export or import (ring-3). + * @param type The return type of the function declaration. + */ +#ifdef IN_VBOXDDU +# ifdef IN_VBOXDDU_STATIC +# define VBOXDDU_DECL(type) type +# else +# define VBOXDDU_DECL(type) DECL_EXPORT_NOTHROW(type) VBOXCALL +# endif +#else +# define VBOXDDU_DECL(type) DECL_IMPORT_NOTHROW(type) VBOXCALL +#endif + +/** @} */ + + +/** @defgroup grp_devdrv Device Emulations and Drivers + * @{ */ +/** @} */ + +#endif /* !VBOX_INCLUDED_cdefs_h */ + diff --git a/include/VBox/com/AutoLock.h b/include/VBox/com/AutoLock.h new file mode 100644 index 00000000..344c4a29 --- /dev/null +++ b/include/VBox/com/AutoLock.h @@ -0,0 +1,704 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Automatic locks, implementation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_AutoLock_h +#define VBOX_INCLUDED_com_AutoLock_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/** @defgroup grp_com_autolock Automatic Locks + * @ingroup grp_com + * @{ + */ + +// macros for automatic lock validation; these will amount to nothing +// unless lock validation is enabled for the runtime +#if defined(RT_LOCK_STRICT) +# define VBOX_WITH_MAIN_LOCK_VALIDATION +# define COMMA_LOCKVAL_SRC_POS , RT_SRC_POS +# define LOCKVAL_SRC_POS_DECL RT_SRC_POS_DECL +# define COMMA_LOCKVAL_SRC_POS_DECL , RT_SRC_POS_DECL +# define LOCKVAL_SRC_POS_ARGS RT_SRC_POS_ARGS +# define COMMA_LOCKVAL_SRC_POS_ARGS , RT_SRC_POS_ARGS +#else +# define COMMA_LOCKVAL_SRC_POS +# define LOCKVAL_SRC_POS_DECL +# define COMMA_LOCKVAL_SRC_POS_DECL +# define LOCKVAL_SRC_POS_ARGS +# define COMMA_LOCKVAL_SRC_POS_ARGS +#endif + +namespace util +{ + +//////////////////////////////////////////////////////////////////////////////// +// +// Order classes for lock validation +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * IPRT now has a sophisticated system of run-time locking classes to validate + * locking order. Since the Main code is handled by simpler minds, we want + * compile-time constants for simplicity, and we'll look up the run-time classes + * in AutoLock.cpp transparently. These are passed to the constructors of the + * LockHandle classes. + */ +enum VBoxLockingClass +{ + LOCKCLASS_NONE = 0, + LOCKCLASS_WEBSERVICE = 1, // highest order: webservice locks + LOCKCLASS_VIRTUALBOXOBJECT = 2, // highest order within Main itself: VirtualBox object lock + LOCKCLASS_HOSTOBJECT = 3, // Host object lock + LOCKCLASS_LISTOFMACHINES = 4, // list of machines in VirtualBox object + LOCKCLASS_MACHINEOBJECT = 5, // Machine object lock + LOCKCLASS_SNAPSHOTOBJECT = 6, // snapshot object locks + // (the snapshots tree, including the child pointers in Snapshot, + // is protected by the normal Machine object lock) + LOCKCLASS_MEDIUMQUERY = 7, // lock used to protect Machine::queryInfo + LOCKCLASS_LISTOFMEDIA = 8, // list of media (hard disks, DVDs, floppies) in VirtualBox object + LOCKCLASS_LISTOFOTHEROBJECTS = 9, // any other list of objects + LOCKCLASS_OTHEROBJECT = 10, // any regular object member variable lock + LOCKCLASS_PROGRESSLIST = 11, // list of progress objects in VirtualBox; no other object lock + // may be held after this! + LOCKCLASS_OBJECTSTATE = 12, // object state lock (handled by AutoCaller classes) + LOCKCLASS_TRANSLATOR = 13 // translator internal lock +}; + +void InitAutoLockSystem(); + +/** + * Check whether the current thread holds any locks in the given class + * + * @return true if any such locks are held, false otherwise. If the lock + * validator is not compiled in, always returns false. + * @param lockClass Which lock class to check. + */ +bool AutoLockHoldsLocksInClass(VBoxLockingClass lockClass); + +//////////////////////////////////////////////////////////////////////////////// +// +// LockHandle and friends +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Abstract base class for semaphore handles (RWLockHandle and WriteLockHandle). + * Don't use this directly, but this implements lock validation for them. + */ +class LockHandle +{ +public: + LockHandle() + {} + + virtual ~LockHandle() + {} + + /** + * Returns @c true if the current thread holds a write lock on this + * read/write semaphore. Intended for debugging only. + */ + virtual bool isWriteLockOnCurrentThread() const = 0; + + /** + * Returns @c true if the current thread holds a read lock on this + * read/write semaphore. Intended for debugging only as it isn't always + * accurate given @a fWannaHear. + */ + virtual bool isReadLockedOnCurrentThread(bool fWannaHear = true) const = 0; + + /** + * Returns the current write lock level of this semaphore. The lock level + * determines the number of nested #lockWrite() calls on the given + * semaphore handle. + * + * Note that this call is valid only when the current thread owns a write + * lock on the given semaphore handle and will assert otherwise. + */ + virtual uint32_t writeLockLevel() const = 0; + + virtual void lockWrite(LOCKVAL_SRC_POS_DECL) = 0; + virtual void unlockWrite() = 0; + virtual void lockRead(LOCKVAL_SRC_POS_DECL) = 0; + virtual void unlockRead() = 0; + +#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + virtual const char* describe() const = 0; +#endif + +private: + // prohibit copy + assignment + LockHandle(const LockHandle&); + LockHandle& operator=(const LockHandle&); +}; + +/** + * Full-featured read/write semaphore handle implementation. + * + * This is an auxiliary base class for classes that need full-featured + * read/write locking as described in the AutoWriteLock class documentation. + * Instances of classes inherited from this class can be passed as arguments to + * the AutoWriteLock and AutoReadLock constructors. + */ +class RWLockHandle : public LockHandle +{ +public: + RWLockHandle(VBoxLockingClass lockClass); + virtual ~RWLockHandle(); + + virtual bool isWriteLockOnCurrentThread() const; + virtual bool isReadLockedOnCurrentThread(bool fWannaHear = true) const; + + virtual void lockWrite(LOCKVAL_SRC_POS_DECL); + virtual void unlockWrite(); + virtual void lockRead(LOCKVAL_SRC_POS_DECL); + virtual void unlockRead(); + + virtual uint32_t writeLockLevel() const; + +#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + virtual const char* describe() const; +#endif + +private: + struct Data; + Data *m; + + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(RWLockHandle); /* Shuts up MSC warning C4625. */ +}; + +/** + * Write-only semaphore handle implementation. + * + * This is an auxiliary base class for classes that need write-only (exclusive) + * locking and do not need read (shared) locking. This implementation uses a + * cheap and fast critical section for both lockWrite() and lockRead() methods + * which makes a lockRead() call fully equivalent to the lockWrite() call and + * therefore makes it pointless to use instahces of this class with + * AutoReadLock instances -- shared locking will not be possible anyway and + * any call to lock() will block if there are lock owners on other threads. + * + * Use with care only when absolutely sure that shared locks are not necessary. + */ +class WriteLockHandle : public LockHandle +{ +public: + WriteLockHandle(VBoxLockingClass lockClass); + virtual ~WriteLockHandle(); + virtual bool isWriteLockOnCurrentThread() const; + virtual bool isReadLockedOnCurrentThread(bool fWannaHear = true) const; + + virtual void lockWrite(LOCKVAL_SRC_POS_DECL); + virtual void unlockWrite(); + virtual void lockRead(LOCKVAL_SRC_POS_DECL); + virtual void unlockRead(); + virtual uint32_t writeLockLevel() const; + +#ifdef VBOX_WITH_MAIN_LOCK_VALIDATION + virtual const char* describe() const; +#endif + +private: + struct Data; + Data *m; + + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(WriteLockHandle); /* Shuts up MSC warning C4625. */ +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// Lockable +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Lockable interface. + * + * This is an abstract base for classes that need read/write locking. Unlike + * RWLockHandle and other classes that makes the read/write semaphore a part of + * class data, this class allows subclasses to decide which semaphore handle to + * use. + */ +class Lockable +{ +public: + virtual ~Lockable() { } /* To make VC++ 2019 happy. */ + + /** + * Returns a pointer to a LockHandle used by AutoWriteLock/AutoReadLock + * for locking. Subclasses are allowed to return @c NULL -- in this case, + * the AutoWriteLock/AutoReadLock object constructed using an instance of + * such subclass will simply turn into no-op. + */ + virtual LockHandle *lockHandle() const = 0; + + /** + * Equivalent to #lockHandle()->isWriteLockOnCurrentThread(). + * Returns @c false if lockHandle() returns @c NULL. + */ + bool isWriteLockOnCurrentThread() + { + LockHandle *h = lockHandle(); + return h ? h->isWriteLockOnCurrentThread() : false; + } + + /** + * Equivalent to #lockHandle()->isReadLockedOnCurrentThread(). + * Returns @c false if lockHandle() returns @c NULL. + * @note Use with care, simple debug assertions and similar only. + */ + bool isReadLockedOnCurrentThread(bool fWannaHear = true) const + { + LockHandle *h = lockHandle(); + return h ? h->isReadLockedOnCurrentThread(fWannaHear) : false; + } +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoLockBase +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Abstract base class for all autolocks. + * + * This cannot be used directly. Use AutoReadLock or AutoWriteLock or AutoMultiWriteLock2/3 + * which directly and indirectly derive from this. + * + * In the implementation, the instance data contains a list of lock handles. + * The class provides some utility functions to help locking and unlocking + * them. + */ + +class AutoLockBase +{ +protected: + AutoLockBase(uint32_t cHandles + COMMA_LOCKVAL_SRC_POS_DECL); + AutoLockBase(uint32_t cHandles, + LockHandle *pHandle + COMMA_LOCKVAL_SRC_POS_DECL); + virtual ~AutoLockBase(); + + struct Data; + Data *m; + + virtual void callLockImpl(LockHandle &l) = 0; + virtual void callUnlockImpl(LockHandle &l) = 0; + + void callLockOnAllHandles(); + void callUnlockOnAllHandles(); + + void cleanup(); + +public: + void acquire(); + void release(); + +private: + // prohibit copy + assignment + AutoLockBase(const AutoLockBase&); + AutoLockBase& operator=(const AutoLockBase&); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoReadLock +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Automatic read lock. Use this with a RWLockHandle to request a read/write + * semaphore in read mode. You can also use this with a WriteLockHandle but + * that makes little sense since they treat read mode like write mode. + * + * If constructed with a RWLockHandle or an instance of Lockable (which in + * practice means any VirtualBoxBase derivative), it autoamtically requests + * the lock in read mode and releases the read lock in the destructor. + */ +class AutoReadLock : public AutoLockBase +{ +public: + + /** + * Constructs a null instance that does not manage any read/write + * semaphore. + * + * Note that all method calls on a null instance are no-ops. This allows to + * have the code where lock protection can be selected (or omitted) at + * runtime. + */ + AutoReadLock(LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + NULL + COMMA_LOCKVAL_SRC_POS_ARGS) + { } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a read lock. + */ + AutoReadLock(LockHandle *aHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + aHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a read lock. + */ + AutoReadLock(LockHandle &aHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + &aHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a read lock. + */ + AutoReadLock(const Lockable &aLockable + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + aLockable.lockHandle() + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a read lock. + */ + AutoReadLock(const Lockable *aLockable + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(1, + aLockable ? aLockable->lockHandle() : NULL + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + virtual ~AutoReadLock(); + + virtual void callLockImpl(LockHandle &l); + virtual void callUnlockImpl(LockHandle &l); + +private: + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoReadLock); /* Shuts up MSC warning C4625. */ +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoWriteLockBase +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Base class for all auto write locks. + * + * This cannot be used directly. Use AutoWriteLock or AutoMultiWriteLock2/3 + * which derive from this. + * + * It has some utility methods for subclasses. + */ +class AutoWriteLockBase : public AutoLockBase +{ +protected: + AutoWriteLockBase(uint32_t cHandles + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(cHandles + COMMA_LOCKVAL_SRC_POS_ARGS) + { } + + AutoWriteLockBase(uint32_t cHandles, + LockHandle *pHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoLockBase(cHandles, + pHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { } + + virtual ~AutoWriteLockBase() + { } + + virtual void callLockImpl(LockHandle &l); + virtual void callUnlockImpl(LockHandle &l); + +private: + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoWriteLockBase); /* Shuts up MSC warning C4625. */ +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoWriteLock +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * Automatic write lock. Use this with a RWLockHandle to request a read/write + * semaphore in write mode. There can only ever be one writer of a read/write + * semaphore: while the lock is held in write mode, no other writer or reader + * can request the semaphore and will block. + * + * If constructed with a RWLockHandle or an instance of Lockable (which in + * practice means any VirtualBoxBase derivative), it autoamtically requests + * the lock in write mode and releases the write lock in the destructor. + * + * When used with a WriteLockHandle, it requests the semaphore contained therein + * exclusively. + */ +class AutoWriteLock : public AutoWriteLockBase +{ +public: + + /** + * Constructs a null instance that does not manage any read/write + * semaphore. + * + * Note that all method calls on a null instance are no-ops. This allows to + * have the code where lock protection can be selected (or omitted) at + * runtime. + */ + AutoWriteLock(LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + NULL + COMMA_LOCKVAL_SRC_POS_ARGS) + { } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(LockHandle *aHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + aHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(LockHandle &aHandle + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + &aHandle + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(const Lockable &aLockable + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + aLockable.lockHandle() + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(const Lockable *aLockable + COMMA_LOCKVAL_SRC_POS_DECL) + : AutoWriteLockBase(1, + aLockable ? aLockable->lockHandle() : NULL + COMMA_LOCKVAL_SRC_POS_ARGS) + { + acquire(); + } + + /** + * Constructs a new instance that will start managing the given read/write + * semaphore by requesting a write lock. + */ + AutoWriteLock(uint32_t cHandles, + LockHandle** pHandles + COMMA_LOCKVAL_SRC_POS_DECL); + + /** + * Release all write locks acquired by this instance through the #acquire() + * call and destroys the instance. + * + * Note that if there there are nested #acquire() calls without the + * corresponding number of #release() calls when the destructor is called, it + * will assert. This is because having an unbalanced number of nested locks + * is a program logic error which must be fixed. + */ + virtual ~AutoWriteLock() + { + cleanup(); + } + + void attach(LockHandle *aHandle); + + /** @see attach (LockHandle *) */ + void attach(LockHandle &aHandle) + { + attach(&aHandle); + } + + /** @see attach (LockHandle *) */ + void attach(const Lockable &aLockable) + { + attach(aLockable.lockHandle()); + } + + /** @see attach (LockHandle *) */ + void attach(const Lockable *aLockable) + { + attach(aLockable ? aLockable->lockHandle() : NULL); + } + + bool isWriteLockOnCurrentThread() const; + uint32_t writeLockLevel() const; + + bool isReadLockedOnCurrentThread(bool fWannaHear = true) const; + +private: + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoWriteLock); /* Shuts up MSC warning C4625. */ +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// AutoMultiWriteLock* +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * A multi-write-lock containing two other write locks. + * + */ +class AutoMultiWriteLock2 : public AutoWriteLockBase +{ +public: + AutoMultiWriteLock2(Lockable *pl1, + Lockable *pl2 + COMMA_LOCKVAL_SRC_POS_DECL); + AutoMultiWriteLock2(LockHandle *pl1, + LockHandle *pl2 + COMMA_LOCKVAL_SRC_POS_DECL); + + virtual ~AutoMultiWriteLock2() + { + cleanup(); + } + +private: + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoMultiWriteLock2); /* Shuts up MSC warning C4625. */ +}; + +/** + * A multi-write-lock containing three other write locks. + * + */ +class AutoMultiWriteLock3 : public AutoWriteLockBase +{ +public: + AutoMultiWriteLock3(Lockable *pl1, + Lockable *pl2, + Lockable *pl3 + COMMA_LOCKVAL_SRC_POS_DECL); + AutoMultiWriteLock3(LockHandle *pl1, + LockHandle *pl2, + LockHandle *pl3 + COMMA_LOCKVAL_SRC_POS_DECL); + + virtual ~AutoMultiWriteLock3() + { + cleanup(); + } + +private: + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoMultiWriteLock3); /* Shuts up MSC warning C4625. */ +}; + +/** + * A multi-write-lock containing four other write locks. + * + */ +class AutoMultiWriteLock4 : public AutoWriteLockBase +{ +public: + AutoMultiWriteLock4(Lockable *pl1, + Lockable *pl2, + Lockable *pl3, + Lockable *pl4 + COMMA_LOCKVAL_SRC_POS_DECL); + AutoMultiWriteLock4(LockHandle *pl1, + LockHandle *pl2, + LockHandle *pl3, + LockHandle *pl4 + COMMA_LOCKVAL_SRC_POS_DECL); + + virtual ~AutoMultiWriteLock4() + { + cleanup(); + } + +private: + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(AutoMultiWriteLock4); /* Shuts up MSC warning C4625. */ +}; + +} /* namespace util */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_AutoLock_h */ + +/* vi: set tabstop=4 shiftwidth=4 expandtab: */ diff --git a/include/VBox/com/ErrorInfo.h b/include/VBox/com/ErrorInfo.h new file mode 100644 index 00000000..fd6e786c --- /dev/null +++ b/include/VBox/com/ErrorInfo.h @@ -0,0 +1,545 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - ErrorInfo class declaration. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_ErrorInfo_h +#define VBOX_INCLUDED_com_ErrorInfo_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBox/com/ptr.h" +#include "VBox/com/string.h" +#include "VBox/com/Guid.h" +#include "VBox/com/assert.h" + + +/** @defgroup grp_com_errinfo ErrorInfo Classes + * @ingroup grp_com + * @{ + */ + +COM_STRUCT_OR_CLASS(IProgress); +COM_STRUCT_OR_CLASS(IVirtualBoxErrorInfo); + +namespace com +{ + +/** + * General discussion: + * + * In COM all errors are stored on a per thread basis. In general this means + * only _one_ active error is possible per thread. A new error will overwrite + * the previous one. To prevent this use MultiResult or ErrorInfoKeeper (see + * below). The implementations in MSCOM/XPCOM differ slightly, but the details + * are handled by this glue code. + * + * We have different classes which are involved in the error management. I try + * to describe them separately to make clear what they are there for. + * + * ErrorInfo: + * + * This class is able to retrieve the per thread error and store it into its + * member variables. This class can also handle non-VirtualBox errors (like + * standard COM errors). + * + * ProgressErrorInfo: + * + * This is just a simple wrapper class to get the ErrorInfo stored within an + * IProgress object. That is the error which was stored when the progress + * object was in use and not an error produced by IProgress itself. + * + * IVirtualBoxErrorInfo: + * + * The VirtualBox interface class for accessing error information from Main + * clients. This class is also used for storing the error information in the + * thread context. + * + * ErrorInfoKeeper: + * + * A helper class which stores the current per thread info internally. After + * calling methods which may produce other errors it is possible to restore + * the previous error and therefore restore the situation before calling the + * other methods. + * + * MultiResult: + * + * Creating an instance of MultiResult turns error chain saving on. All errors + * which follow will be saved in a chain for later access. + * + * COMErrorInfo (Qt/Gui only): + * + * The Qt GUI does some additional work for saving errors. Because we create + * wrappers for _every_ COM call, it is possible to automatically save the + * error info after the execution. This allow some additional info like saving + * the callee. Please note that this error info is saved on the client side + * and therefore locally to the object instance. See COMBaseWithEI, + * COMErrorInfo and the generated COMWrappers.cpp in the GUI. + * + * Errors itself are set in VirtualBoxBase::setErrorInternal. First a + * IVirtualBoxErrorInfo object is created and the given error is saved within. + * If MultiResult is active the current per thread error is fetched and + * attached to the new created IVirtualBoxErrorInfo object. Next this object is + * set as the new per thread error. + * + * Some general hints: + * + * - Always use setError, especially when you are working in an asynchronous thread + * to indicate an error. Otherwise the error information itself will not make + * it into the client. + * + */ + +/** + * The ErrorInfo class provides a convenient way to retrieve error + * information set by the most recent interface method, that was invoked on + * the current thread and returned an unsuccessful result code. + * + * Once the instance of this class is created, the error information for + * the current thread is cleared. + * + * There is no sense to use instances of this class after the last + * invoked interface method returns a success. + * + * The class usage pattern is as follows: + * + * IFoo *foo; + * ... + * HRESULT rc = foo->SomeMethod(); + * if (FAILED(rc)) { + * ErrorInfo info(foo); + * if (info.isFullAvailable()) { + * printf("error message = %ls\n", info.getText().raw()); + * } + * } + * + * + * This class fetches error information using the IErrorInfo interface on + * Win32 (MS COM) or the nsIException interface on other platforms (XPCOM), + * or the extended IVirtualBoxErrorInfo interface when when it is available + * (i.e. a given IErrorInfo or nsIException instance implements it). + * Currently, IVirtualBoxErrorInfo is only available for VirtualBox components. + * + * ErrorInfo::isFullAvailable() and ErrorInfo::isBasicAvailable() determine + * what level of error information is available. If #isBasicAvailable() + * returns true, it means that only IErrorInfo or nsIException is available as + * the source of information (depending on the platform), but not + * IVirtualBoxErrorInfo. If #isFullAvailable() returns true, it means that all + * three interfaces are available. If both methods return false, no error info + * is available at all. + * + * Here is a table of correspondence between this class methods and + * and IErrorInfo/nsIException/IVirtualBoxErrorInfo attributes/methods: + * + * ErrorInfo IErrorInfo nsIException IVirtualBoxErrorInfo + * -------------------------------------------------------------------- + * getResultCode -- result resultCode + * getIID GetGUID -- interfaceID + * getComponent GetSource -- component + * getText GetDescription message text + * + * '--' means that this interface does not provide the corresponding portion + * of information, therefore it is useless to query it if only + * #isBasicAvailable() returns true. As it can be seen, the amount of + * information provided at the basic level, depends on the platform + * (MS COM or XPCOM). + */ +class ErrorInfo +{ +public: + + /** + * Constructs a new, "interfaceless" ErrorInfo instance that takes + * the error information possibly set on the current thread by an + * interface method of some COM component or by the COM subsystem. + * + * This constructor is useful, for example, after an unsuccessful attempt + * to instantiate (create) a component, so there is no any valid interface + * pointer available. + */ + explicit ErrorInfo() + : mIsBasicAvailable(false), + mIsFullAvailable(false), + mResultCode(S_OK), + mResultDetail(0), + m_pNext(NULL) + { + init(); + } + + ErrorInfo(IUnknown *pObj, const GUID &aIID) + : mIsBasicAvailable(false), + mIsFullAvailable(false), + mResultCode(S_OK), + mResultDetail(0), + m_pNext(NULL) + { + init(pObj, aIID); + } + + /** Specialization for the IVirtualBoxErrorInfo smart pointer */ + ErrorInfo(const ComPtr &aPtr) + : mIsBasicAvailable(false), mIsFullAvailable(false) + , mResultCode(S_OK), mResultDetail(0) + { init(aPtr); } + + /** + * Constructs a new ErrorInfo instance from the IVirtualBoxErrorInfo + * interface pointer. If this pointer is not NULL, both #isFullAvailable() + * and #isBasicAvailable() will return |true|. + * + * @param aInfo pointer to the IVirtualBoxErrorInfo interface that + * holds error info to be fetched by this instance + */ + ErrorInfo(IVirtualBoxErrorInfo *aInfo) + : mIsBasicAvailable(false), mIsFullAvailable(false) + , mResultCode(S_OK), mResultDetail(0) + { init(aInfo); } + + ErrorInfo(const ErrorInfo &x) + { + copyFrom(x); + } + + virtual ~ErrorInfo() + { + cleanup(); + } + + ErrorInfo& operator=(const ErrorInfo& x) + { + cleanup(); + copyFrom(x); + return *this; + } + + /** + * Returns whether basic error info is actually available for the current + * thread. If the instance was created from an interface pointer that + * supports basic error info and successfully provided it, or if it is an + * "interfaceless" instance and there is some error info for the current + * thread, the returned value will be true. + * + * See the class description for details about the basic error info level. + * + * The appropriate methods of this class provide meaningful info only when + * this method returns true (otherwise they simply return NULL-like values). + */ + bool isBasicAvailable() const + { + return mIsBasicAvailable; + } + + /** + * Returns whether full error info is actually available for the current + * thread. If the instance was created from an interface pointer that + * supports full error info and successfully provided it, or if it is an + * "interfaceless" instance and there is some error info for the current + * thread, the returned value will be true. + * + * See the class description for details about the full error info level. + * + * The appropriate methods of this class provide meaningful info only when + * this method returns true (otherwise they simply return NULL-like values). + */ + bool isFullAvailable() const + { + return mIsFullAvailable; + } + + /** + * Returns the COM result code of the failed operation. + */ + HRESULT getResultCode() const + { + return mResultCode; + } + + /** + * Returns the (optional) result detail code of the failed operation. + */ + LONG getResultDetail() const + { + return mResultDetail; + } + + /** + * Returns the IID of the interface that defined the error. + */ + const Guid& getInterfaceID() const + { + return mInterfaceID; + } + + /** + * Returns the name of the component that generated the error. + */ + const Bstr& getComponent() const + { + return mComponent; + } + + /** + * Returns the textual description of the error. + */ + const Bstr& getText() const + { + return mText; + } + + /** + * Returns the next error information object or @c NULL if there is none. + */ + const ErrorInfo* getNext() const + { + return m_pNext; + } + + /** + * Returns the name of the interface that defined the error + */ + const Bstr& getInterfaceName() const + { + return mInterfaceName; + } + + /** + * Returns the IID of the interface that returned the error. + * + * This method returns a non-null IID only if the instance was created + * using template \ ErrorInfo(I *i) or + * template \ ErrorInfo(const ComPtr &i) constructor. + * + * @todo broken ErrorInfo documentation links, possibly misleading. + */ + const Guid& getCalleeIID() const + { + return mCalleeIID; + } + + /** + * Returns the name of the interface that returned the error + * + * This method returns a non-null name only if the instance was created + * using template \ ErrorInfo(I *i) or + * template \ ErrorInfo(const ComPtr &i) constructor. + * + * @todo broken ErrorInfo documentation links, possibly misleading. + */ + const Bstr& getCalleeName() const + { + return mCalleeName; + } + + HRESULT getVirtualBoxErrorInfo(ComPtr &pVirtualBoxErrorInfo); + + /** + * Resets all collected error information. #isBasicAvailable() and + * #isFullAvailable will return @c true after this method is called. + */ + void setNull() + { + cleanup(); + } + +protected: + + ErrorInfo(bool /* aDummy */) + : mIsBasicAvailable(false), + mIsFullAvailable(false), + mResultCode(S_OK), + m_pNext(NULL) + { } + + void copyFrom(const ErrorInfo &x); + void cleanup(); + + void init(bool aKeepObj = false); + void init(IUnknown *aUnk, const GUID &aIID, bool aKeepObj = false); + void init(IVirtualBoxErrorInfo *aInfo); + + bool mIsBasicAvailable : 1; + bool mIsFullAvailable : 1; + + HRESULT mResultCode; + LONG mResultDetail; + Guid mInterfaceID; + Bstr mComponent; + Bstr mText; + + ErrorInfo *m_pNext; + + Bstr mInterfaceName; + Guid mCalleeIID; + Bstr mCalleeName; + + ComPtr mErrorInfo; +}; + +/** + * A convenience subclass of ErrorInfo that, given an IProgress interface + * pointer, reads its errorInfo attribute and uses the returned + * IVirtualBoxErrorInfo instance to construct itself. + */ +class ProgressErrorInfo : public ErrorInfo +{ +public: + + /** + * Constructs a new instance by fetching error information from the + * IProgress interface pointer. If the progress object is not NULL, + * its completed attribute is true, resultCode represents a failure, + * and the errorInfo attribute returns a valid IVirtualBoxErrorInfo pointer, + * both #isFullAvailable() and #isBasicAvailable() will return true. + * + * @param progress the progress object representing a failed operation + */ + ProgressErrorInfo(IProgress *progress); +}; + +/** + * A convenience subclass of ErrorInfo that allows to preserve the current + * error info. Instances of this class fetch an error info object set on the + * current thread and keep a reference to it, which allows to restore it + * later using the #restore() method. This is useful to preserve error + * information returned by some method for the duration of making another COM + * call that may set its own error info and overwrite the existing + * one. Preserving and restoring error information makes sense when some + * method wants to return error information set by other call as its own + * error information while it still needs to make another call before return. + * + * Instead of calling #restore() explicitly you may let the object destructor + * do it for you, if you correctly limit the object's lifetime. + * + * The usage pattern is: + * + * rc = foo->method(); + * if (FAILED(rc)) + * { + * ErrorInfoKeeper eik; + * ... + * // bar may return error info as well + * bar->method(); + * ... + * // no need to call #restore() explicitly here because the eik's + * // destructor will restore error info fetched after the failed + * // call to foo before returning to the caller + * return rc; + * } + * + */ +class ErrorInfoKeeper : public ErrorInfo +{ +public: + + /** + * Constructs a new instance that will fetch the current error info if + * @a aIsNull is @c false (by default) or remain uninitialized (null) + * otherwise. + * + * @param aIsNull @c true to prevent fetching error info and leave + * the instance uninitialized. + */ + ErrorInfoKeeper(bool aIsNull = false) + : ErrorInfo(false), mForgot(aIsNull) + { + if (!aIsNull) + init(true /* aKeepObj */); + } + + /** + * Constructs a new instance from an ErrorInfo object, to inject a full + * error info created elsewhere. + * + * @param aInfo @c true to prevent fetching error info and leave + * the instance uninitialized. + */ + ErrorInfoKeeper(const ErrorInfo &aInfo) + : ErrorInfo(false), mForgot(false) + { + copyFrom(aInfo); + } + + /** + * Destroys this instance and automatically calls #restore() which will + * either restore error info fetched by the constructor or do nothing + * if #forget() was called before destruction. + */ + ~ErrorInfoKeeper() { if (!mForgot) restore(); } + + /** + * Tries to (re-)fetch error info set on the current thread. On success, + * the previous error information, if any, will be overwritten with the + * new error information. On failure, or if there is no error information + * available, this instance will be reset to null. + */ + void fetch() + { + setNull(); + mForgot = false; + init(true /* aKeepObj */); + } + + /** + * Restores error info fetched by the constructor and forgets it + * afterwards. Does nothing if the error info was forgotten by #forget(). + * + * @return COM result of the restore operation. + */ + HRESULT restore(); + + /** + * Forgets error info fetched by the constructor to prevent it from + * being restored by #restore() or by the destructor. + */ + void forget() { mForgot = true; } + + /** + * Forgets error info fetched by the constructor to prevent it from + * being restored by #restore() or by the destructor, and returns the + * stored error info object to the caller. + */ + ComPtr takeError() { mForgot = true; return mErrorInfo; } + +private: + + bool mForgot : 1; +}; + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_ErrorInfo_h */ + diff --git a/include/VBox/com/EventQueue.h b/include/VBox/com/EventQueue.h new file mode 100644 index 00000000..ef101377 --- /dev/null +++ b/include/VBox/com/EventQueue.h @@ -0,0 +1,151 @@ +/* $Id: EventQueue.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - Event queue class declaration. + */ + +/* + * Copyright (C) 2013-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_EventQueue_h +#define VBOX_INCLUDED_com_EventQueue_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#include +#include + +#include +#include + + +/** @defgroup grp_com_evtqueue Event Queue Classes + * @ingroup grp_com + * @{ + */ + +namespace com +{ + +class EventQueue; + +/** + * Base class for all events. Intended to be subclassed to introduce new + * events and handlers for them. + * + * Subclasses usually reimplement virtual #handler() (that does nothing by + * default) and add new data members describing the event. + */ +class Event +{ +public: + + Event(void) : + mRefCount(0) { } + virtual ~Event(void) { AssertMsg(!mRefCount, + ("Reference count of event=%p not 0 on destruction (is %RU32)\n", + this, mRefCount)); } +public: + + uint32_t AddRef(void) { return ASMAtomicIncU32(&mRefCount); } + void Release(void) + { + Assert(mRefCount); + uint32_t cRefs = ASMAtomicDecU32(&mRefCount); + if (!cRefs) + delete this; + } + +protected: + + /** + * Event handler. Called in the context of the event queue's thread. + * Always reimplemented by subclasses + * + * @return reserved, should be NULL. + */ + virtual void *handler(void) { return NULL; } + + friend class EventQueue; + +protected: + + /** The event's reference count. */ + uint32_t mRefCount; +}; + +typedef std::list< Event* > EventQueueList; +typedef std::list< Event* >::iterator EventQueueListIterator; +typedef std::list< Event* >::const_iterator EventQueueListIteratorConst; + +/** + * Simple event queue. + */ +class EventQueue +{ +public: + + EventQueue(void); + virtual ~EventQueue(void); + +public: + + BOOL postEvent(Event *event); + int processEventQueue(RTMSINTERVAL cMsTimeout); + int processPendingEvents(size_t cNumEvents); + int interruptEventQueueProcessing(); + +private: + + /** Critical section for serializing access to this + * event queue. */ + RTCRITSECT mCritSect; + /** Number of concurrent users. At the moment we + * only support one concurrent user at a time when + calling processEventQueue(). */ + uint32_t mUserCnt; + /** Event semaphore for getting notified on new + * events being handled. */ + RTSEMEVENT mSemEvent; + /** The actual event queue, implemented as a list. */ + EventQueueList mEvents; + /** Shutdown indicator. */ + bool mShutdown; +}; + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_EventQueue_h */ + diff --git a/include/VBox/com/Guid.h b/include/VBox/com/Guid.h new file mode 100644 index 00000000..42663323 --- /dev/null +++ b/include/VBox/com/Guid.h @@ -0,0 +1,526 @@ +/* $Id: Guid.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - Guid class declaration. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_Guid_h +#define VBOX_INCLUDED_com_Guid_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Make sure all the stdint.h macros are included - must come first! */ +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#include "VBox/com/string.h" + +#include + + +/** @defgroup grp_com_guid GUID Class + * @ingroup grp_com + * @{ + */ + +namespace com +{ + +typedef enum GuidState_t +{ + GUID_ZERO, + GUID_NORMAL, + GUID_INVALID +} GuidState_t; + +/** + * Helper class that represents the UUID type and hides platform-specific + * implementation details. + */ +class Guid +{ +public: + + Guid() + { + clear(); + } + + Guid(const Guid &that) + { + mUuid = that.mUuid; + mGuidState = that.mGuidState; + dbg_refresh(); + } + + Guid(const RTUUID &that) + { + mUuid = that; + updateState(); + dbg_refresh(); + } + + Guid(const GUID &that) + { + AssertCompileSize(GUID, sizeof(RTUUID)); + ::memcpy(&mUuid, &that, sizeof(GUID)); + updateState(); + dbg_refresh(); + } + + /** + * Construct a GUID from a string. + * + * @param that The UUID string. Can be with or without the curly + * brackets. Empty strings are translated to a zero + * GUID, and strings which are not confirming to + * valid GUID string representations are marked as + * invalid. + */ + Guid(const char *that) + { + initString(that); + } + + /** + * Construct a GUID from a BSTR. + * + * @param that The UUID BSTR. Can be with or without the curly + * brackets. Empty strings are translated to a zero + * GUID, and strings which are not confirming to + * valid GUID string representations are marked as + * invalid. + */ + Guid(CBSTR that) + { + initBSTR(that); + } + + /** + * Construct a GUID from a Utf8Str. + * + * @param that The UUID Utf8Str. Can be with or without the curly + * brackets. Empty strings are translated to a zero + * GUID, and strings which are not confirming to + * valid GUID string representations are marked as + */ + Guid(const Utf8Str &that) + { + initString(that.c_str()); + } + + /** + * Construct a GUID from a RTCString. + * + * @param that The UUID RTCString. Can be with or without the curly + * brackets. Empty strings are translated to a zero + * GUID, and strings which are not confirming to + * valid GUID string representations are marked as + */ + Guid(const RTCString &that) + { + initString(that.c_str()); + } + + /** + * Construct a GUID from a Bstr. + * + * @param that The UUID Bstr. Can be with or without the curly + * brackets. Empty strings are translated to a zero + * GUID, and strings which are not confirming to + * valid GUID string representations are marked as + */ + Guid(const Bstr &that) + { + initBSTR(that.raw()); + } + + Guid& operator=(const Guid &that) + { + mUuid = that.mUuid; + mGuidState = that.mGuidState; + dbg_refresh(); + return *this; + } + + Guid& operator=(const RTUUID &guid) + { + mUuid = guid; + updateState(); + dbg_refresh(); + return *this; + } + + Guid& operator=(const GUID &guid) + { + AssertCompileSize(GUID, sizeof(RTUUID)); + ::memcpy(&mUuid, &guid, sizeof(GUID)); + updateState(); + dbg_refresh(); + return *this; + } + + Guid& operator=(const char *str) + { + initString(str); + return *this; + } + + Guid& operator=(CBSTR str) + { + initBSTR(str); + return *this; + } + + Guid& operator=(const Utf8Str &str) + { + return operator=(str.c_str()); + } + + Guid& operator=(const RTCString &str) + { + return operator=(str.c_str()); + } + + Guid& operator=(const Bstr &str) + { + return operator=(str.raw()); + } + + void create() + { + ::RTUuidCreate(&mUuid); + mGuidState = GUID_NORMAL; + dbg_refresh(); + } + + void clear() + { + makeClear(); + dbg_refresh(); + } + + /** + * Convert the GUID to a string. + * + * @returns String object containing the formatted GUID. + * @throws std::bad_alloc + */ + Utf8Str toString() const + { + if (mGuidState == GUID_INVALID) + { + /* What to return in case of wrong Guid */ + return Utf8Str("00000000-0000-0000-0000-00000000000"); + } + + char buf[RTUUID_STR_LENGTH]; + ::memset(buf, '\0', sizeof(buf)); + ::RTUuidToStr(&mUuid, buf, sizeof(buf)); + + return Utf8Str(buf); + } + + /** + * Like toString, but encloses the returned string in curly brackets. + * + * @returns String object containing the formatted GUID in curly brackets. + * @throws std::bad_alloc + */ + Utf8Str toStringCurly() const + { + if (mGuidState == GUID_INVALID) + { + /* What to return in case of wrong Guid */ + return Utf8Str("{00000000-0000-0000-0000-00000000000}"); + } + + char buf[RTUUID_STR_LENGTH + 2]; + ::memset(buf, '\0', sizeof(buf)); + ::RTUuidToStr(&mUuid, buf + 1, sizeof(buf) - 2); + buf[0] = '{'; + buf[sizeof(buf) - 2] = '}'; + + return Utf8Str(buf); + } + + /** + * Convert the GUID to a string. + * + * @returns Bstr object containing the formatted GUID. + * @throws std::bad_alloc + */ + Bstr toUtf16() const + { + if (mGuidState == GUID_INVALID) + { + /* What to return in case of wrong Guid */ + return Bstr("00000000-0000-0000-0000-00000000000"); + } + + RTUTF16 buf[RTUUID_STR_LENGTH]; + ::memset(buf, '\0', sizeof(buf)); + ::RTUuidToUtf16(&mUuid, buf, RT_ELEMENTS(buf)); + + return Bstr(buf); + } + + /** + * Convert the GUID to a C string. + * + * @returns See RTUuidToStr. + * @param pszUuid The output buffer + * @param cbUuid The size of the output buffer. Should be at least + * RTUUID_STR_LENGTH in length. + */ + int toString(char *pszUuid, size_t cbUuid) const + { + return ::RTUuidToStr(mGuidState != GUID_INVALID ? &mUuid : &Empty.mUuid, pszUuid, cbUuid); + } + + bool isValid() const + { + return mGuidState != GUID_INVALID; + } + + bool isZero() const + { + return mGuidState == GUID_ZERO; + } + + bool operator==(const Guid &that) const { return ::RTUuidCompare(&mUuid, &that.mUuid) == 0; } + bool operator==(const RTUUID &guid) const { return ::RTUuidCompare(&mUuid, &guid) == 0; } + bool operator==(const GUID &guid) const { return ::RTUuidCompare(&mUuid, (PRTUUID)&guid) == 0; } + bool operator!=(const Guid &that) const { return !operator==(that); } + bool operator!=(const GUID &guid) const { return !operator==(guid); } + bool operator!=(const RTUUID &guid) const { return !operator==(guid); } + bool operator<(const Guid &that) const { return ::RTUuidCompare(&mUuid, &that.mUuid) < 0; } + bool operator<(const GUID &guid) const { return ::RTUuidCompare(&mUuid, (PRTUUID)&guid) < 0; } + bool operator<(const RTUUID &guid) const { return ::RTUuidCompare(&mUuid, &guid) < 0; } + + /** Compare with a UUID string representation. + * @note Not an operator as that could lead to confusion. */ + bool equalsString(const char *pszUuid2) const { return ::RTUuidCompareStr(&mUuid, pszUuid2) == 0; } + + /** + * To directly copy the contents to a GUID, or for passing it as an input + * parameter of type (const GUID *), the compiler converts. */ + const GUID &ref() const + { + return *(const GUID *)&mUuid; + } + + /** + * To pass instances to printf-like functions. + */ + PCRTUUID raw() const + { + return (PCRTUUID)&mUuid; + } + +#if !defined(VBOX_WITH_XPCOM) + + /** To assign instances to OUT_GUID parameters from within the interface + * method. */ + const Guid &cloneTo(GUID *pguid) const + { + if (pguid) + ::memcpy(pguid, &mUuid, sizeof(GUID)); + return *this; + } + + /** To pass instances as OUT_GUID parameters to interface methods. */ + GUID *asOutParam() + { + return (GUID *)&mUuid; + } + +#else + + /** To assign instances to OUT_GUID parameters from within the + * interface method */ + const Guid &cloneTo(nsID **ppGuid) const + { + if (ppGuid) + *ppGuid = (nsID *)nsMemory::Clone(&mUuid, sizeof(nsID)); + + return *this; + } + + /** + * Internal helper class for asOutParam(). + * + * This takes a GUID reference in the constructor and copies the mUuid from + * the method to that instance in its destructor. + */ + class GuidOutParam + { + GuidOutParam(Guid &guid) + : ptr(0), + outer(guid) + { + outer.clear(); + } + + nsID *ptr; + Guid &outer; + GuidOutParam(const GuidOutParam &that); // disabled + GuidOutParam &operator=(const GuidOutParam &that); // disabled + public: + operator nsID**() { return &ptr; } + ~GuidOutParam() + { + if (ptr && outer.isZero()) + { + outer = *ptr; + outer.dbg_refresh(); + nsMemory::Free(ptr); + } + } + friend class Guid; + }; + + /** to pass instances as OUT_GUID parameters to interface methods */ + GuidOutParam asOutParam() { return GuidOutParam(*this); } + +#endif + + /** + * Static immutable empty (zero) object. May be used for comparison purposes. + */ + static const Guid Empty; + +private: + void makeClear() + { + ::RTUuidClear(&mUuid); + mGuidState = GUID_ZERO; + } + + void makeInvalid() + { + ::RTUuidClear(&mUuid); + mGuidState = GUID_INVALID; + } + + void updateState() + { + if (::RTUuidIsNull(&mUuid)) + mGuidState = GUID_ZERO; + else + mGuidState = GUID_NORMAL; + } + + void initString(const char *that) + { + if (!that || !*that) + { + makeClear(); + } + else + { + int rc = ::RTUuidFromStr(&mUuid, that); + if (RT_SUCCESS(rc)) + updateState(); + else + makeInvalid(); + } + dbg_refresh(); + } + + void initBSTR(CBSTR that) + { + if (!that || !*that) + { + makeClear(); + } + else + { + int rc = ::RTUuidFromUtf16(&mUuid, that); + if (RT_SUCCESS(rc)) + updateState(); + else + makeInvalid(); + } + dbg_refresh(); + } + + /** + * Refresh the debug-only UUID string. + * + * In debug code, refresh the UUID string representatino for debugging; + * must be called every time the internal uuid changes; compiles to nothing + * in release code. + */ + inline void dbg_refresh() + { +#ifdef DEBUG + switch (mGuidState) + { + case GUID_ZERO: + case GUID_NORMAL: + ::RTUuidToStr(&mUuid, mszUuid, RTUUID_STR_LENGTH); + break; + default: + ::memset(mszUuid, '\0', sizeof(mszUuid)); + ::RTStrCopy(mszUuid, sizeof(mszUuid), "INVALID"); + break; + } + m_pcszUUID = mszUuid; +#endif + } + + /** The UUID. */ + RTUUID mUuid; + + GuidState_t mGuidState; + +#ifdef DEBUG + /** String representation of mUuid for printing in the debugger. */ + char mszUuid[RTUUID_STR_LENGTH]; + /** Another string variant for the debugger, points to szUUID. */ + const char *m_pcszUUID; +#endif +}; + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_Guid_h */ + diff --git a/include/VBox/com/Makefile.kup b/include/VBox/com/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/VBox/com/MultiResult.h b/include/VBox/com/MultiResult.h new file mode 100644 index 00000000..c64ad58c --- /dev/null +++ b/include/VBox/com/MultiResult.h @@ -0,0 +1,278 @@ +/* $Id: MultiResult.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - MultiResult class declarations. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_MultiResult_h +#define VBOX_INCLUDED_com_MultiResult_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBox/com/defs.h" +#include "VBox/com/string.h" + +#include + +/** @defgroup grp_com_mr MultiResult Classes + * @ingroup grp_com + * @{ + */ + +namespace com +{ + +/** + * "First worst" result type. + * + * Variables of this class are used instead of HRESULT variables when it is + * desirable to memorize the "first worst" result code instead of the last + * assigned one. In other words, an assignment operation to a variable of this + * class will succeed only if the result code to assign has worse severity. The + * following table demonstrate this (the first column lists the previous result + * code stored in the variable, the first row lists the new result code being + * assigned, 'A' means the assignment will take place, '> S_OK' means a warning + * result code): + * + * {{{ + * FAILED > S_OK S_OK + * FAILED - - - + * > S_OK A - - + * S_OK A A - + * + * }}} + * + * In practice, you will need to use a FWResult variable when you call some COM + * method B after another COM method A fails and want to return the result code + * of A even if B also fails, but want to return the failed result code of B if + * A issues a warning or succeeds. + */ +class FWResult +{ + +public: + + /** + * Constructs a new variable. Note that by default this constructor sets the + * result code to E_FAIL to make sure a failure is returned to the caller if + * the variable is never assigned another value (which is considered as the + * improper use of this class). + */ + FWResult (HRESULT aRC = E_FAIL) : mRC (aRC) {} + + FWResult &operator= (HRESULT aRC) + { + if ((FAILED (aRC) && !FAILED (mRC)) || + (mRC == S_OK && aRC != S_OK)) + mRC = aRC; + + return *this; + } + + operator HRESULT() const { return mRC; } + + HRESULT *operator&() { return &mRC; } + +private: + + HRESULT mRC; +}; + +/** + * The MultiResult class is a com::FWResult enhancement that also acts as a + * switch to turn on multi-error mode for VirtualBoxBase::setError() and + * VirtualBoxBase::setWarning() calls. + * + * When an instance of this class is created, multi-error mode is turned on + * for the current thread and the turn-on counter is increased by one. In + * multi-error mode, a call to setError() or setWarning() does not + * overwrite the current error or warning info object possibly set on the + * current thread by other method calls, but instead it stores this old + * object in the IVirtualBoxErrorInfo::next attribute of the new error + * object being set. + * + * This way, error/warning objects are stacked together and form a chain of + * errors where the most recent error is the first one retrieved by the + * calling party, the preceding error is what the + * IVirtualBoxErrorInfo::next attribute of the first error points to, and so + * on, up to the first error or warning occurred which is the last in the + * chain. See IVirtualBoxErrorInfo documentation for more info. + * + * When the instance of the MultiResult class goes out of scope and gets + * destroyed, it automatically decreases the turn-on counter by one. If + * the counter drops to zero, multi-error mode for the current thread is + * turned off and the thread switches back to single-error mode where every + * next error or warning object overwrites the previous one. + * + * Note that the caller of a COM method uses a non-S_OK result code to + * decide if the method has returned an error (negative codes) or a warning + * (positive non-zero codes) and will query extended error info only in + * these two cases. However, since multi-error mode implies that the method + * doesn't return control return to the caller immediately after the first + * error or warning but continues its execution, the functionality provided + * by the base com::FWResult class becomes very useful because it allows to + * preserve the error or the warning result code even if it is later assigned + * a S_OK value multiple times. See com::FWResult for details. + * + * Here is the typical usage pattern: + * @code + HRESULT Bar::method() + { + // assume multi-errors are turned off here... + + if (something) + { + // Turn on multi-error mode and make sure severity is preserved + MultiResult rc = foo->method1(); + + // return on fatal error, but continue on warning or on success + CheckComRCReturnRC (rc); + + rc = foo->method2(); + // no matter what result, stack it and continue + + // ... + + // return the last worst result code (it will be preserved even if + // foo->method2() returns S_OK. + return rc; + } + + // multi-errors are turned off here again... + + return S_OK; + } + * @endcode + * + * @note This class is intended to be instantiated on the stack, therefore + * You cannot create them using new(). Although it is possible to copy + * instances of MultiResult or return them by value, please never do + * that as it is breaks the class semantics (and will assert); + */ +class MultiResult : public FWResult +{ +public: + + /** + * @copydoc FWResult::FWResult() + */ + MultiResult (HRESULT aRC = E_FAIL) : FWResult (aRC) { incCounter(); } + + MultiResult (const MultiResult &aThat) : FWResult (aThat) + { + /* We need this copy constructor only for GCC that wants to have + * it in case of expressions like |MultiResult rc = E_FAIL;|. But + * we assert since the optimizer should actually avoid the + * temporary and call the other constructor directly instead. */ + AssertFailed(); + } + + ~MultiResult() { decCounter(); } + + MultiResult &operator= (HRESULT aRC) + { + FWResult::operator= (aRC); + return *this; + } + + MultiResult &operator= (const MultiResult & /* aThat */) + { + /* We need this copy constructor only for GCC that wants to have + * it in case of expressions like |MultiResult rc = E_FAIL;|. But + * we assert since the optimizer should actually avoid the + * temporary and call the other constructor directly instead. */ + AssertFailed(); + return *this; + } + + /** + * Returns true if multi-mode is enabled for the current thread (i.e. at + * least one MultiResult instance exists on the stack somewhere). + * @return + */ + static bool isMultiEnabled(); + +private: + + DECLARE_CLS_NEW_DELETE_NOOP(MultiResult); + + static void incCounter(); + static void decCounter(); + + static RTTLS sCounter; + + friend class MultiResultRef; +}; + +/** + * The MultiResultRef class is equivalent to MultiResult except that it takes + * a reference to the existing HRESULT variable instead of maintaining its own + * one. + */ +class MultiResultRef +{ +public: + + MultiResultRef (HRESULT &aRC) : mRC (aRC) { MultiResult::incCounter(); } + + ~MultiResultRef() { MultiResult::decCounter(); } + + MultiResultRef &operator= (HRESULT aRC) + { + /* Copied from FWResult */ + if ((FAILED (aRC) && !FAILED (mRC)) || + (mRC == S_OK && aRC != S_OK)) + mRC = aRC; + + return *this; + } + + operator HRESULT() const { return mRC; } + + HRESULT *operator&() { return &mRC; } + +private: + + DECLARE_CLS_NEW_DELETE_NOOP(MultiResultRef); + + HRESULT &mRC; +}; + + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_MultiResult_h */ + diff --git a/include/VBox/com/NativeEventQueue.h b/include/VBox/com/NativeEventQueue.h new file mode 100644 index 00000000..240acfa3 --- /dev/null +++ b/include/VBox/com/NativeEventQueue.h @@ -0,0 +1,161 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Event and EventQueue class declaration. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_NativeEventQueue_h +#define VBOX_INCLUDED_com_NativeEventQueue_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef VBOX_WITH_XPCOM +# include +#else +# include +#endif + +#include +#include + + +/** @defgroup grp_com_evt Event and EventQueue Classes + * @ingroup grp_com + * @{ + */ + +namespace com +{ + +class MainEventQueue; + +/** + * Base class for all events. Intended to be subclassed to introduce new + * events and handlers for them. + * + * Subclasses usually reimplement virtual #handler() (that does nothing by + * default) and add new data members describing the event. + */ +class NativeEvent +{ +public: + + NativeEvent() {} + virtual ~NativeEvent() {}; + +protected: + + /** + * Event handler. Called in the context of the event queue's thread. + * Always reimplemented by subclasses + * + * @return reserved, should be NULL. + */ + virtual void *handler() { return NULL; } + + friend class NativeEventQueue; +}; + +/** + * Simple event queue. + * + * When using XPCOM, this will map onto the default XPCOM queue for the thread. + * So, if a queue is created on the main thread, it automatically processes + * XPCOM/IPC events while waiting. + * + * When using Windows, Darwin and OS/2, this will map onto the native thread + * queue/runloop. So, windows messages and what not will be processed while + * waiting for events. + * + * @note It is intentional that there is no way to retrieve arbitrary + * events and controlling their processing. There is no use case which + * warrants introducing the complexity of platform independent events. + */ +class NativeEventQueue +{ +public: + + NativeEventQueue(); + virtual ~NativeEventQueue(); + + BOOL postEvent(NativeEvent *event); + int processEventQueue(RTMSINTERVAL cMsTimeout); + int interruptEventQueueProcessing(); + int getSelectFD(); + static int init(); + static int uninit(); + static NativeEventQueue *getMainEventQueue(); + +#ifdef VBOX_WITH_XPCOM + already_AddRefed getIEventQueue() + { + return mEventQ.get(); + } +#else + static int dispatchMessageOnWindows(MSG const *pMsg, int rc); +#endif + +private: + static NativeEventQueue *sMainQueue; + +#ifndef VBOX_WITH_XPCOM + + /** The thread which the queue belongs to. */ + DWORD mThreadId; + /** Duplicated thread handle for MsgWaitForMultipleObjects. */ + HANDLE mhThread; + +#else // VBOX_WITH_XPCOM + + /** Whether it was created (and thus needs destroying) or if a queue already + * associated with the thread was used. */ + bool mEQCreated; + + /** Whether event processing should be interrupted. */ + bool mInterrupted; + + nsCOMPtr mEventQ; + nsCOMPtr mEventQService; + + static void *PR_CALLBACK plEventHandler(PLEvent *self); + static void PR_CALLBACK plEventDestructor(PLEvent *self); + +#endif // VBOX_WITH_XPCOM +}; + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_NativeEventQueue_h */ + diff --git a/include/VBox/com/VirtualBox.h b/include/VBox/com/VirtualBox.h new file mode 100644 index 00000000..ffaede31 --- /dev/null +++ b/include/VBox/com/VirtualBox.h @@ -0,0 +1,71 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - VirtualBox COM Library definitions. + * + * @note This is the main header file that COM/XPCOM clients include; however, + * it is only a wrapper around another platform-dependent include file + * that contains the real COM/XPCOM interface declarations. That other + * include file is generated automatically at build time from + * /src/VBox/Main/idl/VirtualBox.xidl, which contains all the VirtualBox + * interfaces; the include file is called VirtualBox.h on Windows hosts + * and VirtualBox_XPCOM.h on Linux hosts. The build process places it in + * out/{platform}/bin/sdk/include, from where it gets + * included by the rest of the VirtualBox code. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_VirtualBox_h +#define VBOX_INCLUDED_com_VirtualBox_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* For XPCOM/C++ enum hack checks. */ +#include + +/* Generated VirtualBox COM library definition file. */ +#if !defined(VBOXCOM_NOINCLUDE) +# if !defined(VBOX_WITH_XPCOM) +# include /* Included by VirtualBox.h via rpc.h, so include our wrapper with cleanups. */ +# include +# else +# define VBOX_WITH_XPCOM_CPP_ENUM_HACK +# include +# endif +#endif + +/* For convenience. */ +#include "VBox/com/defs.h" +#include "VBox/com/ptr.h" + +#endif /* !VBOX_INCLUDED_com_VirtualBox_h */ + diff --git a/include/VBox/com/array.h b/include/VBox/com/array.h new file mode 100644 index 00000000..33fc34e3 --- /dev/null +++ b/include/VBox/com/array.h @@ -0,0 +1,1833 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Safe array helper class declaration. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_array_h +#define VBOX_INCLUDED_com_array_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/** @defgroup grp_com_arrays COM/XPCOM Arrays + * @ingroup grp_com + * @{ + * + * The COM/XPCOM array support layer provides a cross-platform way to pass + * arrays to and from COM interface methods and consists of the com::SafeArray + * template and a set of ComSafeArray* macros part of which is defined in + * VBox/com/defs.h. + * + * This layer works with interface attributes and method parameters that have + * the 'safearray="yes"' attribute in the XIDL definition: + * @code + + + + + + + + + + + + * @endcode + * + * Methods generated from this and similar definitions are implemented in + * component classes using the following declarations: + * @code + + STDMETHOD(TestArrays)(ComSafeArrayIn(LONG, aIn), + ComSafeArrayOut(LONG, aOut), + ComSafeArrayOut(LONG, aRet)); + + * @endcode + * + * And the following function bodies: + * @code + + STDMETHODIMP Component::TestArrays(ComSafeArrayIn(LONG, aIn), + ComSafeArrayOut(LONG, aOut), + ComSafeArrayOut(LONG, aRet)) + { + if (ComSafeArrayInIsNull(aIn)) + return E_INVALIDARG; + if (ComSafeArrayOutIsNull(aOut)) + return E_POINTER; + if (ComSafeArrayOutIsNull(aRet)) + return E_POINTER; + + // Use SafeArray to access the input array parameter + + com::SafeArray in(ComSafeArrayInArg(aIn)); + + for (size_t i = 0; i < in.size(); ++ i) + LogFlow(("*** in[%u]=%d\n", i, in[i])); + + // Use SafeArray to create the return array (the same technique is used + // for output array parameters) + + SafeArray ret(in.size() * 2); + for (size_t i = 0; i < in.size(); ++ i) + { + ret[i] = in[i]; + ret[i + in.size()] = in[i] * 10; + } + + ret.detachTo(ComSafeArrayOutArg(aRet)); + + return S_OK; + } + + * @endcode + * + * Such methods can be called from the client code using the following pattern: + * @code + + ComPtr component; + + // ... + + com::SafeArray in(3); + in[0] = -1; + in[1] = -2; + in[2] = -3; + + com::SafeArray out; + com::SafeArray ret; + + HRESULT rc = component->TestArrays(ComSafeArrayAsInParam(in), + ComSafeArrayAsOutParam(out), + ComSafeArrayAsOutParam(ret)); + + if (SUCCEEDED(rc)) + for (size_t i = 0; i < ret.size(); ++ i) + printf("*** ret[%u]=%d\n", i, ret[i]); + + * @endcode + * + * For interoperability with standard C++ containers, there is a template + * constructor that takes such a container as argument and performs a deep copy + * of its contents. This can be used in method implementations like this: + * @code + + STDMETHODIMP Component::COMGETTER(Values)(ComSafeArrayOut(int, aValues)) + { + // ... assume there is a |std::list mValues| data member + + com::SafeArray values(mValues); + values.detachTo(ComSafeArrayOutArg(aValues)); + + return S_OK; + } + + * @endcode + * + * The current implementation of the SafeArray layer supports all types normally + * allowed in XIDL as array element types (including 'wstring' and 'uuid'). + * However, 'pointer-to-...' types (e.g. 'long *', 'wstring *') are not + * supported and therefore cannot be used as element types. + * + * Note that for GUID arrays you should use SafeGUIDArray and + * SafeConstGUIDArray, customized SafeArray<> specializations. + * + * Also note that in order to pass input BSTR array parameters declared + * using the ComSafeArrayIn(IN_BSTR, aParam) macro to the SafeArray<> + * constructor using the ComSafeArrayInArg() macro, you should use IN_BSTR + * as the SafeArray<> template argument, not just BSTR. + * + * Arrays of interface pointers are also supported but they require to use a + * special SafeArray implementation, com::SafeIfacePointer, which takes the + * interface class name as a template argument (e.g. + * com::SafeIfacePointer\). This implementation functions + * identically to com::SafeArray. + */ + +#ifdef VBOX_WITH_XPCOM +# include +#endif + +#include "VBox/com/defs.h" + +#if RT_GNUC_PREREQ(4, 6) || (defined(_MSC_VER) && (_MSC_VER >= 1600)) +/** @def VBOX_WITH_TYPE_TRAITS + * Type traits are a C++ 11 feature, so not available everywhere (yet). + * Only GCC 4.6 or newer and MSVC++ 16.0 (Visual Studio 2010) or newer. + */ +# define VBOX_WITH_TYPE_TRAITS +#endif + +#ifdef VBOX_WITH_TYPE_TRAITS +# include +#endif + +#include "VBox/com/ptr.h" +#include "VBox/com/assert.h" +#include "iprt/cpp/list.h" + +/** @def ComSafeArrayAsInParam + * Wraps the given com::SafeArray instance to generate an expression that is + * suitable for passing it to functions that take input safearray parameters + * declared using the ComSafeArrayIn macro. + * + * @param aArray com::SafeArray instance to pass as an input parameter. + */ + +/** @def ComSafeArrayAsOutParam + * Wraps the given com::SafeArray instance to generate an expression that is + * suitable for passing it to functions that take output safearray parameters + * declared using the ComSafeArrayOut macro. + * + * @param aArray com::SafeArray instance to pass as an output parameter. + */ + +/** @def ComSafeArrayNullInParam + * Helper for passing a NULL array parameter to a COM / XPCOM method. + */ + +#ifdef VBOX_WITH_XPCOM + +# define ComSafeArrayAsInParam(aArray) \ + (PRUint32)(aArray).size(), (aArray).__asInParam_Arr((aArray).raw()) + +# define ComSafeArrayAsOutParam(aArray) \ + (aArray).__asOutParam_Size(), (aArray).__asOutParam_Arr() + +# define ComSafeArrayNullInParam() 0, NULL + +#else /* !VBOX_WITH_XPCOM */ + +# define ComSafeArrayAsInParam(aArray) (aArray).__asInParam() + +# define ComSafeArrayAsOutParam(aArray) (aArray).__asOutParam() + +# define ComSafeArrayNullInParam() (NULL) + +#endif /* !VBOX_WITH_XPCOM */ + +/** + * + */ +namespace com +{ + +/** Used for dummy element access in com::SafeArray, avoiding crashes. */ +extern const char Zeroes[16]; + + +#ifdef VBOX_WITH_XPCOM + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Provides various helpers for SafeArray. + * + * @param T Type of array elements. + */ +template +struct SafeArrayTraits +{ +protected: + + /** Initializes memory for aElem. */ + static void Init(T &aElem) { aElem = (T)0; } + + /** Initializes memory occupied by aElem. */ + static void Uninit(T &aElem) { RT_NOREF(aElem); } + + /** Creates a deep copy of aFrom and stores it in aTo. */ + static void Copy(const T &aFrom, T &aTo) { aTo = aFrom; } + +public: + + /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard (that + * in particular forbid casts of 'char **' to 'const char **'). Then initial + * reason for this magic is that XPIDL declares input strings + * (char/PRUnichar pointers) as const but doesn't do so for pointers to + * arrays. */ + static T *__asInParam_Arr(T *aArr) { return aArr; } + static T *__asInParam_Arr(const T *aArr) { return const_cast(aArr); } +}; + +template +struct SafeArrayTraits +{ + // Arbitrary pointers are not supported +}; + +template<> +struct SafeArrayTraits +{ +protected: + + static void Init(PRUnichar * &aElem) { aElem = NULL; } + + static void Uninit(PRUnichar * &aElem) + { + if (aElem) + { + ::SysFreeString(aElem); + aElem = NULL; + } + } + + static void Copy(const PRUnichar * aFrom, PRUnichar * &aTo) + { + AssertCompile(sizeof(PRUnichar) == sizeof(OLECHAR)); + aTo = aFrom ? ::SysAllocString((const OLECHAR *)aFrom) : NULL; + } + +public: + + /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard */ + static const PRUnichar **__asInParam_Arr(PRUnichar **aArr) + { + return const_cast(aArr); + } + static const PRUnichar **__asInParam_Arr(const PRUnichar **aArr) { return aArr; } +}; + +template<> +struct SafeArrayTraits +{ +protected: + + static void Init(const PRUnichar * &aElem) { aElem = NULL; } + static void Uninit(const PRUnichar * &aElem) + { + if (aElem) + { + ::SysFreeString(const_cast(aElem)); + aElem = NULL; + } + } + + static void Copy(const PRUnichar * aFrom, const PRUnichar * &aTo) + { + AssertCompile(sizeof(PRUnichar) == sizeof(OLECHAR)); + aTo = aFrom ? ::SysAllocString((const OLECHAR *)aFrom) : NULL; + } + +public: + + /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard */ + static const PRUnichar **__asInParam_Arr(const PRUnichar **aArr) { return aArr; } +}; + +template<> +struct SafeArrayTraits +{ +protected: + + static void Init(nsID * &aElem) { aElem = NULL; } + + static void Uninit(nsID * &aElem) + { + if (aElem) + { + ::nsMemory::Free(aElem); + aElem = NULL; + } + } + + static void Copy(const nsID * aFrom, nsID * &aTo) + { + if (aFrom) + { + aTo = (nsID *) ::nsMemory::Alloc(sizeof(nsID)); + if (aTo) + *aTo = *aFrom; + } + else + aTo = NULL; + } + + /* This specification is also reused for SafeConstGUIDArray, so provide a + * no-op Init() and Uninit() which are necessary for SafeArray<> but should + * be never called in context of SafeConstGUIDArray. */ + + static void Init(const nsID * &aElem) { NOREF(aElem); AssertFailed(); } + static void Uninit(const nsID * &aElem) { NOREF(aElem); AssertFailed(); } + +public: + + /** Magic to workaround strict rules of par. 4.4.4 of the C++ standard. */ + static const nsID **__asInParam_Arr(nsID **aArr) + { + return const_cast(aArr); + } + static const nsID **__asInParam_Arr(const nsID **aArr) { return aArr; } +}; + +#else /* !VBOX_WITH_XPCOM */ + +//////////////////////////////////////////////////////////////////////////////// + +struct SafeArrayTraitsBase +{ +protected: + + static SAFEARRAY *CreateSafeArray(VARTYPE aVarType, SAFEARRAYBOUND *aBound) + { return SafeArrayCreate(aVarType, 1, aBound); } +}; + +/** + * Provides various helpers for SafeArray. + * + * @param T Type of array elements. + * + * Specializations of this template must provide the following methods: + * + // Returns the VARTYPE of COM SafeArray elements to be used for T + static VARTYPE VarType(); + + // Returns the number of VarType() elements necessary for aSize + // elements of T + static ULONG VarCount(size_t aSize); + + // Returns the number of elements of T that fit into the given number of + // VarType() elements (opposite to VarCount(size_t aSize)). + static size_t Size(ULONG aVarCount); + + // Creates a deep copy of aFrom and stores it in aTo + static void Copy(ULONG aFrom, ULONG &aTo); + */ +template +struct SafeArrayTraits : public SafeArrayTraitsBase +{ +protected: + + // Arbitrary types are treated as passed by value and each value is + // represented by a number of VT_Ix type elements where VT_Ix has the + // biggest possible bitness necessary to represent T w/o a gap. COM enums + // fall into this category. + + static VARTYPE VarType() + { +#ifdef VBOX_WITH_TYPE_TRAITS + if ( std::is_integral::value + && !std::is_signed::value) + { + if (sizeof(T) % 8 == 0) return VT_UI8; + if (sizeof(T) % 4 == 0) return VT_UI4; + if (sizeof(T) % 2 == 0) return VT_UI2; + return VT_UI1; + } +#endif + if (sizeof(T) % 8 == 0) return VT_I8; + if (sizeof(T) % 4 == 0) return VT_I4; + if (sizeof(T) % 2 == 0) return VT_I2; + return VT_I1; + } + + /* + * Fallback method in case type traits (VBOX_WITH_TYPE_TRAITS) + * are not available. Always returns unsigned types. + */ + static VARTYPE VarTypeUnsigned() + { + if (sizeof(T) % 8 == 0) return VT_UI8; + if (sizeof(T) % 4 == 0) return VT_UI4; + if (sizeof(T) % 2 == 0) return VT_UI2; + return VT_UI1; + } + + static ULONG VarCount(size_t aSize) + { + if (sizeof(T) % 8 == 0) return (ULONG)((sizeof(T) / 8) * aSize); + if (sizeof(T) % 4 == 0) return (ULONG)((sizeof(T) / 4) * aSize); + if (sizeof(T) % 2 == 0) return (ULONG)((sizeof(T) / 2) * aSize); + return (ULONG)(sizeof(T) * aSize); + } + + static size_t Size(ULONG aVarCount) + { + if (sizeof(T) % 8 == 0) return (size_t)(aVarCount * 8) / sizeof(T); + if (sizeof(T) % 4 == 0) return (size_t)(aVarCount * 4) / sizeof(T); + if (sizeof(T) % 2 == 0) return (size_t)(aVarCount * 2) / sizeof(T); + return (size_t) aVarCount / sizeof(T); + } + + static void Copy(T aFrom, T &aTo) { aTo = aFrom; } +}; + +template +struct SafeArrayTraits +{ + // Arbitrary pointer types are not supported +}; + +/* Although the generic SafeArrayTraits template would work for all integers, + * we specialize it for some of them in order to use the correct VT_ type */ + +template<> +struct SafeArrayTraits : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_I4; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(LONG aFrom, LONG &aTo) { aTo = aFrom; } +}; + +template<> +struct SafeArrayTraits : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_UI4; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(ULONG aFrom, ULONG &aTo) { aTo = aFrom; } +}; + +template<> +struct SafeArrayTraits : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_I8; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(LONG64 aFrom, LONG64 &aTo) { aTo = aFrom; } +}; + +template<> +struct SafeArrayTraits : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_UI8; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(ULONG64 aFrom, ULONG64 &aTo) { aTo = aFrom; } +}; + +template<> +struct SafeArrayTraits : public SafeArrayTraitsBase +{ +protected: + + static VARTYPE VarType() { return VT_BSTR; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(BSTR aFrom, BSTR &aTo) + { + aTo = aFrom ? ::SysAllocString((const OLECHAR *)aFrom) : NULL; + } +}; + +template<> +struct SafeArrayTraits : public SafeArrayTraitsBase +{ +protected: + + /* Use the 64-bit unsigned integer type for GUID */ + static VARTYPE VarType() { return VT_UI8; } + + /* GUID is 128 bit, so we need two VT_UI8 */ + static ULONG VarCount(size_t aSize) + { + AssertCompileSize(GUID, 16); + return (ULONG)(aSize * 2); + } + + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount / 2; } + + static void Copy(GUID aFrom, GUID &aTo) { aTo = aFrom; } +}; + +/** + * Helper for SafeArray::__asOutParam() that automatically updates m.raw after a + * non-NULL m.arr assignment. + */ +class OutSafeArrayDipper +{ + OutSafeArrayDipper(SAFEARRAY **aArr, void **aRaw) + : arr(aArr), raw(aRaw) { Assert(*aArr == NULL && *aRaw == NULL); } + + SAFEARRAY **arr; + void **raw; + + template friend class SafeArray; + +public: + + ~OutSafeArrayDipper() + { + if (*arr != NULL) + { + HRESULT rc = SafeArrayAccessData(*arr, raw); + AssertComRC(rc); + } + } + + operator SAFEARRAY **() { return arr; } +}; + +#endif /* !VBOX_WITH_XPCOM */ + +//////////////////////////////////////////////////////////////////////////////// + +/** + * The SafeArray class represents the safe array type used in COM to pass arrays + * to/from interface methods. + * + * This helper class hides all MSCOM/XPCOM specific implementation details and, + * together with ComSafeArrayIn, ComSafeArrayOut and ComSafeArrayRet macros, + * provides a platform-neutral way to handle safe arrays in the method + * implementation. + * + * When an instance of this class is destroyed, it automatically frees all + * resources occupied by individual elements of the array as well as by the + * array itself. However, when the value of an element is manually changed + * using #operator[] or by accessing array data through the #raw() pointer, it is + * the caller's responsibility to free resources occupied by the previous + * element's value. + * + * Also, objects of this class do not support copy and assignment operations and + * therefore cannot be returned from functions by value. In other words, this + * class is just a temporary storage for handling interface method calls and not + * intended to be used to store arrays as data members and such -- you should + * use normal list/vector classes for that. + * + * @note The current implementation supports only one-dimensional arrays. + * + * @note This class is not thread-safe. + */ +template > +class SafeArray : public Traits +{ +public: + + /** + * Creates a null array. + */ + SafeArray() { } + + /** + * Creates a new array of the given size. All elements of the newly created + * array initialized with null values. + * + * @param aSize Initial number of elements in the array. + * + * @note If this object remains null after construction it means that there + * was not enough memory for creating an array of the requested size. + * The constructor will also assert in this case. + */ + SafeArray(size_t aSize) { resize(aSize); } + + /** + * Weakly attaches this instance to the existing array passed in a method + * parameter declared using the ComSafeArrayIn macro. When using this call, + * always wrap the parameter name in the ComSafeArrayInArg macro call like + * this: + *
+     *  SafeArray safeArray(ComSafeArrayInArg(aArg));
+     * 
+ * + * Note that this constructor doesn't take the ownership of the array. In + * particular, it means that operations that operate on the ownership (e.g. + * #detachTo()) are forbidden and will assert. + * + * @param aArg Input method parameter to attach to. + */ + SafeArray(ComSafeArrayIn(T, aArg)) + { + if (aArg) + { +#ifdef VBOX_WITH_XPCOM + + m.size = aArgSize; + m.arr = aArg; + m.isWeak = true; + +#else /* !VBOX_WITH_XPCOM */ + + SAFEARRAY *arg = aArg; + + AssertReturnVoid(arg->cDims == 1); + + VARTYPE vt; + HRESULT rc = SafeArrayGetVartype(arg, &vt); + AssertComRCReturnVoid(rc); +# ifndef VBOX_WITH_TYPE_TRAITS + AssertMsgReturnVoid( + vt == VarType() + || vt == VarTypeUnsigned(), + ("Expected vartype %d or %d, got %d.\n", + VarType(), VarTypeUnsigned(), vt)); +# else /* !VBOX_WITH_TYPE_TRAITS */ + AssertMsgReturnVoid( + vt == VarType(), + ("Expected vartype %d, got %d.\n", + VarType(), vt)); +# endif + rc = SafeArrayAccessData(arg, (void HUGEP **)&m.raw); + AssertComRCReturnVoid(rc); + + m.arr = arg; + m.isWeak = true; + +#endif /* !VBOX_WITH_XPCOM */ + } + } + + /** + * Creates a deep copy of the given standard C++ container that stores + * T objects. + * + * @param aCntr Container object to copy. + * + * @tparam C Standard C++ container template class (normally deduced from + * @c aCntr). + */ + template class C, class A> + SafeArray(const C & aCntr) + { + resize(aCntr.size()); + AssertReturnVoid(!isNull()); + + size_t i = 0; + for (typename C::const_iterator it = aCntr.begin(); + it != aCntr.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + SafeArray::Copy(*it, m.arr[i]); +#else + Copy(*it, m.raw[i]); +#endif + } + + /** + * Creates a deep copy of the given standard C++ map that stores T objects + * as values. + * + * @param aMap Map object to copy. + * + * @tparam C Standard C++ map template class (normally deduced from + * @a aMap). + * @tparam L Standard C++ compare class (deduced from @a aMap). + * @tparam A Standard C++ allocator class (deduced from @a aMap). + * @tparam K Map key class (deduced from @a aMap). + */ + template + class C, class L, class A, class K> + SafeArray(const C & aMap) + { + typedef C Map; + + resize(aMap.size()); + AssertReturnVoid(!isNull()); + + size_t i = 0; + for (typename Map::const_iterator it = aMap.begin(); + it != aMap.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + Copy(it->second, m.arr[i]); +#else + Copy(it->second, m.raw[i]); +#endif + } + + /** + * Destroys this instance after calling #setNull() to release allocated + * resources. See #setNull() for more details. + */ + virtual ~SafeArray() { setNull(); } + + /** + * Returns @c true if this instance represents a null array. + */ + bool isNull() const { return m.arr == NULL; } + + /** + * Returns @c true if this instance does not represents a null array. + */ + bool isNotNull() const { return m.arr != NULL; } + + /** + * Resets this instance to null and, if this instance is not a weak one, + * releases any resources occupied by the array data. + * + * @note This method destroys (cleans up) all elements of the array using + * the corresponding cleanup routine for the element type before the + * array itself is destroyed. + */ + virtual void setNull() { m.uninit(); } + + /** + * Returns @c true if this instance is weak. A weak instance doesn't own the + * array data and therefore operations manipulating the ownership (e.g. + * #detachTo()) are forbidden and will assert. + */ + bool isWeak() const { return m.isWeak; } + + /** Number of elements in the array. */ + size_t size() const + { +#ifdef VBOX_WITH_XPCOM + if (m.arr) + return m.size; + return 0; +#else + if (m.arr) + return Size(m.arr->rgsabound[0].cElements); + return 0; +#endif + } + + /** + * Appends a copy of the given element at the end of the array. + * + * The array size is increased by one by this method and the additional + * space is allocated as needed. + * + * This method is handy in cases where you want to assign a copy of the + * existing value to the array element, for example: + * Bstr string; array.push_back(string);. If you create a string + * just to put it in the array, you may find #appendedRaw() more useful. + * + * @param aElement Element to append. + * + * @return @c true on success and @c false if there is not enough + * memory for resizing. + */ + bool push_back(const T &aElement) + { + if (!ensureCapacity(size() + 1)) + return false; + +#ifdef VBOX_WITH_XPCOM + SafeArray::Copy(aElement, m.arr[m.size]); + ++ m.size; +#else + Copy(aElement, m.raw[size() - 1]); +#endif + return true; + } + + /** + * Appends an empty element at the end of the array and returns a raw + * pointer to it suitable for assigning a raw value (w/o constructing a + * copy). + * + * The array size is increased by one by this method and the additional + * space is allocated as needed. + * + * Note that in case of raw assignment, value ownership (for types with + * dynamically allocated data and for interface pointers) is transferred to + * the safe array object. + * + * This method is handy for operations like + * Bstr("foo").detachTo(array.appendedRaw());. Don't use it as + * an l-value (array.appendedRaw() = SysAllocString(L"tralala");) + * since this doesn't check for a NULL condition; use #resize() instead. If + * you need to assign a copy of the existing value instead of transferring + * the ownership, look at #push_back(). + * + * @return Raw pointer to the added element or NULL if no memory. + */ + T *appendedRaw() + { + if (!ensureCapacity(size() + 1)) + return NULL; + +#ifdef VBOX_WITH_XPCOM + SafeArray::Init(m.arr[m.size]); + ++ m.size; + return &m.arr[m.size - 1]; +#else + /* nothing to do here, SafeArrayCreate() has performed element + * initialization */ + return &m.raw[size() - 1]; +#endif + } + + /** + * Resizes the array preserving its contents when possible. If the new size + * is larger than the old size, new elements are initialized with null + * values. If the new size is less than the old size, the contents of the + * array beyond the new size is lost. + * + * @param aNewSize New number of elements in the array. + * @return @c true on success and @c false if there is not enough + * memory for resizing. + */ + bool resize(size_t aNewSize) + { + if (!ensureCapacity(aNewSize)) + return false; + +#ifdef VBOX_WITH_XPCOM + + if (m.size < aNewSize) + { + /* initialize the new elements */ + for (size_t i = m.size; i < aNewSize; ++ i) + SafeArray::Init(m.arr[i]); + } + + /** @todo Fix this! */ + m.size = (PRUint32)aNewSize; +#else + /* nothing to do here, SafeArrayCreate() has performed element + * initialization */ +#endif + return true; + } + + /** + * Reinitializes this instance by preallocating space for the given number + * of elements. The previous array contents is lost. + * + * @param aNewSize New number of elements in the array. + * @return @c true on success and @c false if there is not enough + * memory for resizing. + */ + bool reset(size_t aNewSize) + { + m.uninit(); + return resize(aNewSize); + } + + /** + * Returns a pointer to the raw array data. Use this raw pointer with care + * as no type or bound checking is done for you in this case. + * + * @note This method returns @c NULL when this instance is null. + * @see #operator[] + */ + T *raw() + { +#ifdef VBOX_WITH_XPCOM + return m.arr; +#else + return m.raw; +#endif + } + + /** + * Const version of #raw(). + */ + const T *raw() const + { +#ifdef VBOX_WITH_XPCOM + return m.arr; +#else + return m.raw; +#endif + } + + /** + * Array access operator that returns an array element by reference. A bit + * safer than #raw(): asserts and returns a reference to a static zero + * element (const, i.e. writes will fail) if this instance is null or + * if the index is out of bounds. + * + * @note For weak instances, this call will succeed but the behavior of + * changing the contents of an element of the weak array instance is + * undefined and may lead to a program crash on some platforms. + */ + T &operator[] (size_t aIdx) + { + /** @todo r=klaus should do this as a AssertCompile, but cannot find a way which works. */ + Assert(sizeof(T) <= sizeof(Zeroes)); + AssertReturn(m.arr != NULL, *(T *)&Zeroes[0]); + AssertReturn(aIdx < size(), *(T *)&Zeroes[0]); +#ifdef VBOX_WITH_XPCOM + return m.arr[aIdx]; +#else + AssertReturn(m.raw != NULL, *(T *)&Zeroes[0]); + return m.raw[aIdx]; +#endif + } + + /** + * Const version of #operator[] that returns an array element by value. + */ + const T operator[] (size_t aIdx) const + { + AssertReturn(m.arr != NULL, *(const T *)&Zeroes[0]); + AssertReturn(aIdx < size(), *(const T *)&Zeroes[0]); +#ifdef VBOX_WITH_XPCOM + return m.arr[aIdx]; +#else + AssertReturn(m.raw != NULL, *(const T *)&Zeroes[0]); + return m.raw[aIdx]; +#endif + } + + /** + * Creates a copy of this array and stores it in a method parameter declared + * using the ComSafeArrayOut macro. When using this call, always wrap the + * parameter name in the ComSafeArrayOutArg macro call like this: + *
+     *  safeArray.cloneTo(ComSafeArrayOutArg(aArg));
+     * 
+ * + * @note It is assumed that the ownership of the returned copy is + * transferred to the caller of the method and he is responsible to free the + * array data when it is no longer needed. + * + * @param aArg Output method parameter to clone to. + */ + virtual const SafeArray &cloneTo(ComSafeArrayOut(T, aArg)) const + { + /// @todo Implement me! +#ifdef VBOX_WITH_XPCOM + NOREF(aArgSize); + NOREF(aArg); +#else + NOREF(aArg); +#endif + AssertFailedReturn(*this); + } + + HRESULT cloneTo(SafeArray& aOther) const + { + aOther.reset(size()); + return aOther.initFrom(*this); + } + + + /** + * Transfers the ownership of this array's data to the specified location + * declared using the ComSafeArrayOut macro and makes this array a null + * array. When using this call, always wrap the parameter name in the + * ComSafeArrayOutArg macro call like this: + *
+     *  safeArray.detachTo(ComSafeArrayOutArg(aArg));
+     * 
+ * + * Detaching the null array is also possible in which case the location will + * receive NULL. + * + * @note Since the ownership of the array data is transferred to the + * caller of the method, he is responsible to free the array data when it is + * no longer needed. + * + * @param aArg Location to detach to. + */ + virtual SafeArray &detachTo(ComSafeArrayOut(T, aArg)) + { + AssertReturn(!m.isWeak, *this); + +#ifdef VBOX_WITH_XPCOM + + AssertReturn(aArgSize != NULL, *this); + AssertReturn(aArg != NULL, *this); + + *aArgSize = m.size; + *aArg = m.arr; + + m.isWeak = false; + m.size = 0; + m.arr = NULL; + +#else /* !VBOX_WITH_XPCOM */ + + AssertReturn(aArg != NULL, *this); + *aArg = m.arr; + + if (m.raw) + { + HRESULT rc = SafeArrayUnaccessData(m.arr); + AssertComRCReturn(rc, *this); + m.raw = NULL; + } + + m.isWeak = false; + m.arr = NULL; + +#endif /* !VBOX_WITH_XPCOM */ + + return *this; + } + + /** + * Returns a copy of this SafeArray as RTCList. + */ + RTCList toList() + { + RTCList list(size()); + for (size_t i = 0; i < size(); ++i) +#ifdef VBOX_WITH_XPCOM + list.append(m.arr[i]); +#else + list.append(m.raw[i]); +#endif + return list; + } + + inline HRESULT initFrom(const com::SafeArray & aRef); + inline HRESULT initFrom(const T* aPtr, size_t aSize); + + // Public methods for internal purposes only. + +#ifdef VBOX_WITH_XPCOM + + /** Internal function. Never call it directly. */ + PRUint32 *__asOutParam_Size() { setNull(); return &m.size; } + + /** Internal function Never call it directly. */ + T **__asOutParam_Arr() { Assert(isNull()); return &m.arr; } + +#else /* !VBOX_WITH_XPCOM */ + + /** Internal function Never call it directly. */ + SAFEARRAY * __asInParam() { return m.arr; } + + /** Internal function Never call it directly. */ + OutSafeArrayDipper __asOutParam() + { setNull(); return OutSafeArrayDipper(&m.arr, (void **)&m.raw); } + +#endif /* !VBOX_WITH_XPCOM */ + + static const SafeArray Null; + +protected: + + DECLARE_CLS_COPY_CTOR_ASSIGN_NOOP(SafeArray); + + /** + * Ensures that the array is big enough to contain aNewSize elements. + * + * If the new size is greater than the current capacity, a new array is + * allocated and elements from the old array are copied over. The size of + * the array doesn't change, only the capacity increases (which is always + * greater than the size). Note that the additionally allocated elements are + * left uninitialized by this method. + * + * If the new size is less than the current size, the existing array is + * truncated to the specified size and the elements outside the new array + * boundary are freed. + * + * If the new size is the same as the current size, nothing happens. + * + * @param aNewSize New size of the array. + * + * @return @c true on success and @c false if not enough memory. + */ + bool ensureCapacity(size_t aNewSize) + { + AssertReturn(!m.isWeak, false); + +#ifdef VBOX_WITH_XPCOM + + /* Note: we distinguish between a null array and an empty (zero + * elements) array. Therefore we never use zero in malloc (even if + * aNewSize is zero) to make sure we get a non-null pointer. */ + + if (m.size == aNewSize && m.arr != NULL) + return true; + + /* Allocate in 16-byte pieces. */ + size_t newCapacity = RT_MAX((aNewSize + 15) / 16 * 16, 16); + + if (m.capacity != newCapacity) + { + T *newArr = (T *)nsMemory::Alloc(RT_MAX(newCapacity, 1) * sizeof(T)); + AssertReturn(newArr != NULL, false); + + if (m.arr != NULL) + { + if (m.size > aNewSize) + { + /* Truncation takes place, uninit exceeding elements and + * shrink the size. */ + for (size_t i = aNewSize; i < m.size; ++ i) + SafeArray::Uninit(m.arr[i]); + + /** @todo Fix this! */ + m.size = (PRUint32)aNewSize; + } + + /* Copy the old contents. */ + memcpy(newArr, m.arr, m.size * sizeof(T)); + nsMemory::Free((void *)m.arr); + } + + m.arr = newArr; + } + else + { + if (m.size > aNewSize) + { + /* Truncation takes place, uninit exceeding elements and + * shrink the size. */ + for (size_t i = aNewSize; i < m.size; ++ i) + SafeArray::Uninit(m.arr[i]); + + /** @todo Fix this! */ + m.size = (PRUint32)aNewSize; + } + } + + /** @todo Fix this! */ + m.capacity = (PRUint32)newCapacity; + +#else + + SAFEARRAYBOUND bound = { VarCount(aNewSize), 0 }; + HRESULT rc; + + if (m.arr == NULL) + { + m.arr = CreateSafeArray(VarType(), &bound); + AssertReturn(m.arr != NULL, false); + } + else + { + SafeArrayUnaccessData(m.arr); + + rc = SafeArrayRedim(m.arr, &bound); + AssertComRCReturn(rc == S_OK, false); + } + + rc = SafeArrayAccessData(m.arr, (void HUGEP **)&m.raw); + AssertComRCReturn(rc, false); + +#endif + return true; + } + + struct Data + { + Data() + : isWeak(false) +#ifdef VBOX_WITH_XPCOM + , capacity(0), size(0), arr(NULL) +#else + , arr(NULL), raw(NULL) +#endif + {} + + ~Data() { uninit(); } + + void uninit() + { +#ifdef VBOX_WITH_XPCOM + + if (arr) + { + if (!isWeak) + { + for (size_t i = 0; i < size; ++ i) + SafeArray::Uninit(arr[i]); + + nsMemory::Free((void *)arr); + } + else + isWeak = false; + + arr = NULL; + } + + size = capacity = 0; + +#else /* !VBOX_WITH_XPCOM */ + + if (arr) + { + if (raw) + { + SafeArrayUnaccessData(arr); + raw = NULL; + } + + if (!isWeak) + { + HRESULT rc = SafeArrayDestroy(arr); + AssertComRCReturnVoid(rc); + } + else + isWeak = false; + + arr = NULL; + } + +#endif /* !VBOX_WITH_XPCOM */ + } + + bool isWeak : 1; + +#ifdef VBOX_WITH_XPCOM + PRUint32 capacity; + PRUint32 size; + T *arr; +#else + SAFEARRAY *arr; + T *raw; +#endif + }; + + Data m; +}; + +/* Few fast specializations for primitive array types */ +template<> +inline HRESULT com::SafeArray::initFrom(const com::SafeArray & aRef) +{ + size_t sSize = aRef.size(); + if (resize(sSize)) + { + ::memcpy(raw(), aRef.raw(), sSize); + return S_OK; + } + return E_OUTOFMEMORY; +} +template<> +inline HRESULT com::SafeArray::initFrom(const BYTE *aPtr, size_t aSize) +{ + if (resize(aSize)) + { + ::memcpy(raw(), aPtr, aSize); + return S_OK; + } + return E_OUTOFMEMORY; +} + + +template<> +inline HRESULT com::SafeArray::initFrom(const com::SafeArray & aRef) +{ + size_t sSize = aRef.size(); + if (resize(sSize)) + { + ::memcpy(raw(), aRef.raw(), sSize * sizeof(SHORT)); + return S_OK; + } + return E_OUTOFMEMORY; +} +template<> +inline HRESULT com::SafeArray::initFrom(const SHORT *aPtr, size_t aSize) +{ + if (resize(aSize)) + { + ::memcpy(raw(), aPtr, aSize * sizeof(SHORT)); + return S_OK; + } + return E_OUTOFMEMORY; +} + +template<> +inline HRESULT com::SafeArray::initFrom(const com::SafeArray & aRef) +{ + size_t sSize = aRef.size(); + if (resize(sSize)) + { + ::memcpy(raw(), aRef.raw(), sSize * sizeof(USHORT)); + return S_OK; + } + return E_OUTOFMEMORY; +} +template<> +inline HRESULT com::SafeArray::initFrom(const USHORT *aPtr, size_t aSize) +{ + if (resize(aSize)) + { + ::memcpy(raw(), aPtr, aSize * sizeof(USHORT)); + return S_OK; + } + return E_OUTOFMEMORY; +} + +template<> +inline HRESULT com::SafeArray::initFrom(const com::SafeArray & aRef) +{ + size_t sSize = aRef.size(); + if (resize(sSize)) + { + ::memcpy(raw(), aRef.raw(), sSize * sizeof(LONG)); + return S_OK; + } + return E_OUTOFMEMORY; +} +template<> +inline HRESULT com::SafeArray::initFrom(const LONG *aPtr, size_t aSize) +{ + if (resize(aSize)) + { + ::memcpy(raw(), aPtr, aSize * sizeof(LONG)); + return S_OK; + } + return E_OUTOFMEMORY; +} + + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef VBOX_WITH_XPCOM + +/** + * Version of com::SafeArray for arrays of GUID. + * + * In MS COM, GUID arrays store GUIDs by value and therefore input arrays are + * represented using |GUID *| and out arrays -- using |GUID **|. In XPCOM, + * GUID arrays store pointers to nsID so that input arrays are |const nsID **| + * and out arrays are |nsID ***|. Due to this difference, it is impossible to + * work with arrays of GUID on both platforms by simply using com::SafeArray + * . This class is intended to provide some level of cross-platform + * behavior. + * + * The basic usage pattern is basically similar to com::SafeArray<> except that + * you use ComSafeGUIDArrayIn* and ComSafeGUIDArrayOut* macros instead of + * ComSafeArrayIn* and ComSafeArrayOut*. Another important nuance is that the + * raw() array type is different (nsID **, or GUID ** on XPCOM and GUID * on MS + * COM) so it is recommended to use operator[] instead which always returns a + * GUID by value. + * + * Note that due to const modifiers, you cannot use SafeGUIDArray for input GUID + * arrays. Please use SafeConstGUIDArray for this instead. + * + * Other than mentioned above, the functionality of this class is equivalent to + * com::SafeArray<>. See the description of that template and its methods for + * more information. + * + * Output GUID arrays are handled by a separate class, SafeGUIDArrayOut, since + * this class cannot handle them because of const modifiers. + */ +class SafeGUIDArray : public SafeArray +{ +public: + + typedef SafeArray Base; + + class nsIDRef + { + public: + + nsIDRef(nsID * &aVal) : mVal(aVal) { AssertCompile(sizeof(nsID) <= sizeof(Zeroes)); } + + operator const nsID &() const { return mVal ? *mVal : *(const nsID *)&Zeroes[0]; } + operator nsID() const { return mVal ? *mVal : *(nsID *)&Zeroes[0]; } + + const nsID *operator&() const { return mVal ? mVal : (const nsID *)&Zeroes[0]; } + + nsIDRef &operator= (const nsID &aThat) + { + if (mVal == NULL) + Copy(&aThat, mVal); + else + *mVal = aThat; + return *this; + } + + private: + + nsID * &mVal; + + friend class SafeGUIDArray; + }; + + /** See SafeArray<>::SafeArray(). */ + SafeGUIDArray() {} + + /** See SafeArray<>::SafeArray(size_t). */ + SafeGUIDArray(size_t aSize) : Base(aSize) {} + + /** + * Array access operator that returns an array element by reference. As a + * special case, the return value of this operator on XPCOM is an nsID (GUID) + * reference, instead of an nsID pointer (the actual SafeArray template + * argument), for compatibility with the MS COM version. + * + * The rest is equivalent to SafeArray<>::operator[]. + */ + nsIDRef operator[] (size_t aIdx) + { + Assert(m.arr != NULL); + Assert(aIdx < size()); + return nsIDRef(m.arr[aIdx]); + } + + /** + * Const version of #operator[] that returns an array element by value. + */ + const nsID &operator[] (size_t aIdx) const + { + Assert(m.arr != NULL); + Assert(aIdx < size()); + return m.arr[aIdx] ? *m.arr[aIdx] : *(const nsID *)&Zeroes[0]; + } +}; + +/** + * Version of com::SafeArray for const arrays of GUID. + * + * This class is used to work with input GUID array parameters in method + * implementations. See SafeGUIDArray for more details. + */ +class SafeConstGUIDArray : public SafeArray > +{ +public: + + typedef SafeArray > Base; + + /** See SafeArray<>::SafeArray(). */ + SafeConstGUIDArray() { AssertCompile(sizeof(nsID) <= sizeof(Zeroes)); } + + /* See SafeArray<>::SafeArray(ComSafeArrayIn(T, aArg)). */ + SafeConstGUIDArray(ComSafeGUIDArrayIn(aArg)) + : Base(ComSafeGUIDArrayInArg(aArg)) {} + + /** + * Array access operator that returns an array element by reference. As a + * special case, the return value of this operator on XPCOM is nsID (GUID) + * instead of nsID *, for compatibility with the MS COM version. + * + * The rest is equivalent to SafeArray<>::operator[]. + */ + const nsID &operator[] (size_t aIdx) const + { + AssertReturn(m.arr != NULL, *(const nsID *)&Zeroes[0]); + AssertReturn(aIdx < size(), *(const nsID *)&Zeroes[0]); + return *m.arr[aIdx]; + } + +private: + + /* These are disabled because of const. */ + bool reset(size_t aNewSize) { NOREF(aNewSize); return false; } +}; + +#else /* !VBOX_WITH_XPCOM */ + +typedef SafeArray SafeGUIDArray; +typedef SafeArray > SafeConstGUIDArray; + +#endif /* !VBOX_WITH_XPCOM */ + +//////////////////////////////////////////////////////////////////////////////// + +#ifdef VBOX_WITH_XPCOM + +template +struct SafeIfaceArrayTraits +{ +protected: + + static void Init(I * &aElem) { aElem = NULL; } + static void Uninit(I * &aElem) + { + if (aElem) + { + aElem->Release(); + aElem = NULL; + } + } + + static void Copy(I * aFrom, I * &aTo) + { + if (aFrom != NULL) + { + aTo = aFrom; + aTo->AddRef(); + } + else + aTo = NULL; + } + +public: + + /* Magic to workaround strict rules of par. 4.4.4 of the C++ standard. */ + static I **__asInParam_Arr(I **aArr) { return aArr; } + static I **__asInParam_Arr(const I **aArr) { return const_cast(aArr); } +}; + +#else /* !VBOX_WITH_XPCOM */ + +template +struct SafeIfaceArrayTraits +{ +protected: + + static VARTYPE VarType() { return VT_DISPATCH; } + static ULONG VarCount(size_t aSize) { return (ULONG)aSize; } + static size_t Size(ULONG aVarCount) { return (size_t)aVarCount; } + + static void Copy(I * aFrom, I * &aTo) + { + if (aFrom != NULL) + { + aTo = aFrom; + aTo->AddRef(); + } + else + aTo = NULL; + } + + static SAFEARRAY *CreateSafeArray(VARTYPE aVarType, SAFEARRAYBOUND *aBound) + { + NOREF(aVarType); + return SafeArrayCreateEx(VT_DISPATCH, 1, aBound, (PVOID)&COM_IIDOF(I)); + } +}; + +#endif /* !VBOX_WITH_XPCOM */ + +//////////////////////////////////////////////////////////////////////////////// + +/** + * Version of com::SafeArray for arrays of interface pointers. + * + * Except that it manages arrays of interface pointers, the usage of this class + * is identical to com::SafeArray. + * + * @param I Interface class (no asterisk). + */ +template +class SafeIfaceArray : public SafeArray > +{ +public: + + typedef SafeArray > Base; + + /** + * Creates a null array. + */ + SafeIfaceArray() {} + + /** + * Creates a new array of the given size. All elements of the newly created + * array initialized with null values. + * + * @param aSize Initial number of elements in the array. Must be greater + * than 0. + * + * @note If this object remains null after construction it means that there + * was not enough memory for creating an array of the requested size. + * The constructor will also assert in this case. + */ + SafeIfaceArray(size_t aSize) { Base::resize(aSize); } + + /** + * Weakly attaches this instance to the existing array passed in a method + * parameter declared using the ComSafeArrayIn macro. When using this call, + * always wrap the parameter name in the ComSafeArrayOutArg macro call like + * this: + *
+     *  SafeArray safeArray(ComSafeArrayInArg(aArg));
+     * 
+ * + * Note that this constructor doesn't take the ownership of the array. In + * particular, this means that operations that operate on the ownership + * (e.g. #detachTo()) are forbidden and will assert. + * + * @param aArg Input method parameter to attach to. + */ + SafeIfaceArray(ComSafeArrayIn(I *, aArg)) + { + if (aArg) + { +#ifdef VBOX_WITH_XPCOM + + Base::m.size = aArgSize; + Base::m.arr = aArg; + Base::m.isWeak = true; + +#else /* !VBOX_WITH_XPCOM */ + + SAFEARRAY *arg = aArg; + + AssertReturnVoid(arg->cDims == 1); + + VARTYPE vt; + HRESULT rc = SafeArrayGetVartype(arg, &vt); + AssertComRCReturnVoid(rc); + AssertMsgReturnVoid(vt == VT_UNKNOWN || vt == VT_DISPATCH, + ("Expected vartype VT_UNKNOWN or VT_DISPATCH, got %d.\n", + vt)); + GUID guid; + rc = SafeArrayGetIID(arg, &guid); + AssertComRCReturnVoid(rc); + AssertMsgReturnVoid(InlineIsEqualGUID(COM_IIDOF(I), guid) || arg->rgsabound[0].cElements == 0 /* IDispatch if empty */, + ("Expected IID {%RTuuid}, got {%RTuuid}.\n", &COM_IIDOF(I), &guid)); + + rc = SafeArrayAccessData(arg, (void HUGEP **)&m.raw); + AssertComRCReturnVoid(rc); + + m.arr = arg; + m.isWeak = true; + +#endif /* !VBOX_WITH_XPCOM */ + } + } + + /** + * Creates a deep copy of the given standard C++ container that stores + * interface pointers as objects of the ComPtr\ class. + * + * @param aCntr Container object to copy. + * + * @tparam C Standard C++ container template class (normally deduced from + * @c aCntr). + * @tparam A Standard C++ allocator class (deduced from @c aCntr). + * @tparam OI Argument to the ComPtr template (deduced from @c aCntr). + */ + template class C, class A, class OI> + SafeIfaceArray(const C, A> & aCntr) + { + typedef C, A> List; + + Base::resize(aCntr.size()); + AssertReturnVoid(!Base::isNull()); + + size_t i = 0; + for (typename List::const_iterator it = aCntr.begin(); + it != aCntr.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + this->Copy(*it, Base::m.arr[i]); +#else + Copy(*it, Base::m.raw[i]); +#endif + } + + /** + * Creates a deep copy of the given standard C++ container that stores + * interface pointers as objects of the ComObjPtr\ class. + * + * @param aCntr Container object to copy. + * + * @tparam C Standard C++ container template class (normally deduced from + * @c aCntr). + * @tparam A Standard C++ allocator class (deduced from @c aCntr). + * @tparam OI Argument to the ComObjPtr template (deduced from @c aCntr). + */ + template class C, class A, class OI> + SafeIfaceArray(const C, A> & aCntr) + { + typedef C, A> List; + + Base::resize(aCntr.size()); + AssertReturnVoid(!Base::isNull()); + + size_t i = 0; + for (typename List::const_iterator it = aCntr.begin(); + it != aCntr.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + SafeIfaceArray::Copy(*it, Base::m.arr[i]); +#else + Copy(*it, Base::m.raw[i]); +#endif + } + + /** + * Creates a deep copy of the given standard C++ map whose values are + * interface pointers stored as objects of the ComPtr\ class. + * + * @param aMap Map object to copy. + * + * @tparam C Standard C++ map template class (normally deduced from + * @c aCntr). + * @tparam L Standard C++ compare class (deduced from @c aCntr). + * @tparam A Standard C++ allocator class (deduced from @c aCntr). + * @tparam K Map key class (deduced from @c aCntr). + * @tparam OI Argument to the ComPtr template (deduced from @c aCntr). + */ + template + class C, class L, class A, class K, class OI> + SafeIfaceArray(const C, L, A> & aMap) + { + typedef C, L, A> Map; + + Base::resize(aMap.size()); + AssertReturnVoid(!Base::isNull()); + + size_t i = 0; + for (typename Map::const_iterator it = aMap.begin(); + it != aMap.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + SafeIfaceArray::Copy(it->second, Base::m.arr[i]); +#else + Copy(it->second, Base::m.raw[i]); +#endif + } + + /** + * Creates a deep copy of the given standard C++ map whose values are + * interface pointers stored as objects of the ComObjPtr\ class. + * + * @param aMap Map object to copy. + * + * @tparam C Standard C++ map template class (normally deduced from + * @c aCntr). + * @tparam L Standard C++ compare class (deduced from @c aCntr). + * @tparam A Standard C++ allocator class (deduced from @c aCntr). + * @tparam K Map key class (deduced from @c aCntr). + * @tparam OI Argument to the ComObjPtr template (deduced from @c aCntr). + */ + template + class C, class L, class A, class K, class OI> + SafeIfaceArray(const C, L, A> & aMap) + { + typedef C, L, A> Map; + + Base::resize(aMap.size()); + AssertReturnVoid(!Base::isNull()); + + size_t i = 0; + for (typename Map::const_iterator it = aMap.begin(); + it != aMap.end(); ++ it, ++ i) +#ifdef VBOX_WITH_XPCOM + SafeIfaceArray::Copy(it->second, Base::m.arr[i]); +#else + Copy(it->second, Base::m.raw[i]); +#endif + } + + void setElement(size_t iIdx, I* obj) + { +#ifdef VBOX_WITH_XPCOM + SafeIfaceArray::Copy(obj, Base::m.arr[iIdx]); +#else + Copy(obj, Base::m.raw[iIdx]); +#endif + } +}; + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_array_h */ + diff --git a/include/VBox/com/assert.h b/include/VBox/com/assert.h new file mode 100644 index 00000000..f70f474d --- /dev/null +++ b/include/VBox/com/assert.h @@ -0,0 +1,135 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Assertion macros for COM/XPCOM. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_assert_h +#define VBOX_INCLUDED_com_assert_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_com_assert Assertion Macros for COM/XPCOM + * @ingroup grp_com + * @{ + */ + + +/** + * Asserts that the COM result code is succeeded in strict builds. + * In non-strict builds the result code will be NOREF'ed to kill compiler warnings. + * + * @param hrc The COM result code + */ +#define AssertComRC(hrc) \ + do { AssertMsg(SUCCEEDED(hrc), ("COM RC = %Rhrc (0x%08X)\n", hrc, hrc)); NOREF(hrc); } while (0) + +/** + * Same as AssertComRC, except the caller already knows we failed. + * + * @param hrc The COM result code + */ +#define AssertComRCFailed(hrc) \ + do { AssertMsgFailed(("COM RC = %Rhrc (0x%08X)\n", hrc, hrc)); NOREF(hrc); } while (0) + +/** + * A special version of AssertComRC that returns the given expression + * if the result code is failed. + * + * @param hrc The COM result code + * @param RetExpr The expression to return + */ +#define AssertComRCReturn(hrc, RetExpr) \ + AssertMsgReturn(SUCCEEDED(hrc), ("COM RC = %Rhrc (0x%08X)\n", hrc, hrc), RetExpr) + +/** + * A special version of AssertComRC that returns the given result code + * if it is failed. + * + * @param hrc The COM result code + */ +#define AssertComRCReturnRC(hrc) \ + AssertMsgReturn(SUCCEEDED(hrc), ("COM RC = %Rhrc (0x%08X)\n", hrc, hrc), hrc) + +/** + * A special version of AssertComRC that returns if the result code is failed. + * + * @param hrc The COM result code + */ +#define AssertComRCReturnVoid(hrc) \ + AssertMsgReturnVoid(SUCCEEDED(hrc), ("COM RC = %Rhrc (0x%08X)\n", hrc, hrc)) + +/** + * A special version of AssertComRC that evaluates the given expression and + * breaks if the result code is failed. + * + * @param hrc The COM result code + * @param PreBreakExpr The expression to evaluate on failure. + */ +#define AssertComRCBreak(hrc, PreBreakExpr) \ + if (!SUCCEEDED(hrc)) { AssertComRCFailed(hrc); PreBreakExpr; break; } else do {} while (0) + +/** + * A special version of AssertComRC that evaluates the given expression and + * throws it if the result code is failed. + * + * @param hrc The COM result code + * @param ThrowMeExpr The expression which result to be thrown on failure. + */ +#define AssertComRCThrow(hrc, ThrowMeExpr) \ + do { if (SUCCEEDED(hrc)) { /*likely*/} else { AssertComRCFailed(hrc); throw (ThrowMeExpr); } } while (0) + +/** + * A special version of AssertComRC that just breaks if the result code is + * failed. + * + * @param hrc The COM result code + */ +#define AssertComRCBreakRC(hrc) \ + if (!SUCCEEDED(hrc)) { AssertComRCFailed(hrc); break; } else do {} while (0) + +/** + * A special version of AssertComRC that just throws @a hrc if the result code + * is failed. + * + * @param hrc The COM result code + */ +#define AssertComRCThrowRC(hrc) \ + do { if (SUCCEEDED(hrc)) { /*likely*/ } else { AssertComRCFailed(hrc); throw hrc; } } while (0) + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_assert_h */ + diff --git a/include/VBox/com/com.h b/include/VBox/com/com.h new file mode 100644 index 00000000..946122b1 --- /dev/null +++ b/include/VBox/com/com.h @@ -0,0 +1,102 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - COM initialization / shutdown. + */ + +/* + * Copyright (C) 2005-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_com_h +#define VBOX_INCLUDED_com_com_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "VBox/com/defs.h" +#include "VBox/com/utils.h" + +/** @defgroup grp_com MS COM / XPCOM Abstraction Layer + * @{ + */ + +namespace com +{ + +/** @name VBOX_COM_INIT_F_XXX - flags for com::Initialize(). + * @{ */ +/** Windows: Caller is the GUI and needs a STA rather than MTA apartment. */ +#define VBOX_COM_INIT_F_GUI RT_BIT_32(0) +/** Windows: Auto registration updating, if privileged enough. */ +#define VBOX_COM_INIT_F_AUTO_REG_UPDATE RT_BIT_32(1) +/** Windows: Opt-out of COM patching (client code should do this). */ +#define VBOX_COM_INIT_F_NO_COM_PATCHING RT_BIT_32(2) +/** The default flags. */ +#define VBOX_COM_INIT_F_DEFAULT (VBOX_COM_INIT_F_AUTO_REG_UPDATE) +/** @} */ + +/** + * Initializes the COM runtime. + * + * Must be called on the main thread, before any COM activity in any thread, and by any thread + * willing to perform COM operations. + * + * @return COM result code + */ +HRESULT Initialize(uint32_t fInitFlags = VBOX_COM_INIT_F_DEFAULT); + +/** + * Shuts down the COM runtime. + * + * Must be called on the main thread before termination. + * No COM calls may be made in any thread after this method returns. + */ +HRESULT Shutdown(); + +/** + * Resolves a given interface ID to a string containing the interface name. + * + * If, for some reason, the given IID cannot be resolved to a name, a NULL + * string is returned. A non-NULL string returned by this function must be + * freed using SysFreeString(). + * + * @param aIID ID of the interface to get a name for + * @param aName Resolved interface name or @c NULL on error + */ +void GetInterfaceNameByIID(const GUID &aIID, BSTR *aName); + +#ifdef RT_OS_WINDOWS +void PatchComBugs(void); +#endif + +} /* namespace com */ + +/** @} */ +#endif /* !VBOX_INCLUDED_com_com_h */ + diff --git a/include/VBox/com/defs.h b/include/VBox/com/defs.h new file mode 100644 index 00000000..86b7b101 --- /dev/null +++ b/include/VBox/com/defs.h @@ -0,0 +1,606 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Common Definitions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_defs_h +#define VBOX_INCLUDED_com_defs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Make sure all the stdint.h macros are included - must come first! */ +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#if defined (RT_OS_OS2) + +# if defined(RT_MAX) && RT_MAX != 22 +# undef RT_MAX +# define REDEFINE_RT_MAX +# endif +# undef RT_MAX + +/* Make sure OS/2 Toolkit headers are pulled in to have BOOL/ULONG/etc. typedefs + * already defined in order to be able to redefine them using #define. */ +# define INCL_BASE +# define INCL_PM +# include + +/* OS/2 Toolkit defines TRUE and FALSE */ +# undef FALSE +# undef TRUE + +/* */ +# undef RT_MAX +# ifdef REDEFINE_RT_MAX +# define RT_MAX(Value1, Value2) ( (Value1) >= (Value2) ? (Value1) : (Value2) ) +# endif + +#endif /* defined(RT_OS_OS2) */ + +/* Include iprt/types.h (which also includes iprt/types.h) now to make sure iprt + * gets to stdint.h first, otherwise a system/xpcom header might beat us and + * we'll be without the macros that are optional in C++. */ +#include + + + +/** @defgroup grp_com_defs Common Definitions + * @ingroup grp_com + * @{ + */ + +#if !defined(VBOX_WITH_XPCOM) + +#ifdef RT_OS_WINDOWS + +// Windows COM +///////////////////////////////////////////////////////////////////////////// + +# include +# ifndef VBOX_COM_NO_ATL + +/* Do not use actual ATL, just provide a superficial lookalike ourselves. */ +# include +# endif /* VBOX_COM_NO_ATL */ + +# define NS_DECL_ISUPPORTS +# define NS_IMPL_ISUPPORTS1_CI(a, b) + +/* these are XPCOM only, one for every interface implemented */ +# define NS_DECL_ISUPPORTS + +/** Returns @c true if @a rc represents a warning result code */ +# define SUCCEEDED_WARNING(rc) (SUCCEEDED(rc) && (rc) != S_OK) + +/** Tests is a COM result code indicates that the process implementing the + * interface is dead. + * + * COM status codes: + * 0x800706ba - RPC_S_SERVER_UNAVAILABLE. Killed before call was made. + * 0x800706be - RPC_S_CALL_FAILED. Killed after call was made. + * 0x800706bf - RPC_S_CALL_FAILED_DNE. Not observed, but should be + * matter of timing. + * 0x80010108 - RPC_E_DISCONNECTED. Observed deregistering + * python event listener. + * 0x800706b5 - RPC_S_UNKNOWN_IF. Observed deregistering python + * event listener + */ +#define FAILED_DEAD_INTERFACE(rc) \ + ( (rc) == HRESULT_FROM_WIN32(RPC_S_SERVER_UNAVAILABLE) \ + || (rc) == HRESULT_FROM_WIN32(RPC_S_CALL_FAILED) \ + || (rc) == HRESULT_FROM_WIN32(RPC_S_CALL_FAILED_DNE) \ + || (rc) == RPC_E_DISCONNECTED \ + ) + +/** Immutable BSTR string */ +typedef const OLECHAR *CBSTR; + +/** Input BSTR argument of interface method declaration. */ +#define IN_BSTR BSTR + +/** Input GUID argument of interface method declaration. */ +#define IN_GUID GUID +/** Output GUID argument of interface method declaration. */ +#define OUT_GUID GUID * + +/** Makes the name of the getter interface function (n must be capitalized). */ +#define COMGETTER(n) get_##n +/** Makes the name of the setter interface function (n must be capitalized). */ +#define COMSETTER(n) put_##n + +/** + * Declares an input safearray parameter in the COM method implementation. Also + * used to declare the COM attribute setter parameter. Corresponds to either of + * the following XIDL definitions: + *
+ *  
+ *  ...
+ *  
+ * 
+ * + * The method implementation should use the com::SafeArray helper class to work + * with parameters declared using this define. + * + * @param aType Array element type. + * @param aArg Parameter/attribute name. + */ +#define ComSafeArrayIn(aType, aArg) SAFEARRAY *aArg + +/** + * Expands to @c true if the given input safearray parameter is a "null pointer" + * which makes it impossible to use it for reading safearray data. + */ +#define ComSafeArrayInIsNull(aArg) ((aArg) == NULL) + +/** + * Wraps the given parameter name to generate an expression that is suitable for + * passing the parameter to functions that take input safearray parameters + * declared using the ComSafeArrayIn macro. + * + * @param aArg Parameter name to wrap. The given parameter must be declared + * within the calling function using the ComSafeArrayIn macro. + */ +#define ComSafeArrayInArg(aArg) aArg + +/** + * Declares an output safearray parameter in the COM method implementation. Also + * used to declare the COM attribute getter parameter. Corresponds to either of + * the following XIDL definitions: + *
+ *  
+ *  
+ *  ...
+ *  
+ * 
+ * + * The method implementation should use the com::SafeArray helper class to work + * with parameters declared using this define. + * + * @param aType Array element type. + * @param aArg Parameter/attribute name. + */ +#define ComSafeArrayOut(aType, aArg) SAFEARRAY **aArg + +/** + * Expands to @c true if the given output safearray parameter is a "null + * pointer" which makes it impossible to use it for returning a safearray. + */ +#define ComSafeArrayOutIsNull(aArg) ((aArg) == NULL) + +/** + * Wraps the given parameter name to generate an expression that is suitable for + * passing the parameter to functions that take output safearray parameters + * declared using the ComSafeArrayOut marco. + * + * @param aArg Parameter name to wrap. The given parameter must be declared + * within the calling function using the ComSafeArrayOut macro. + */ +#define ComSafeArrayOutArg(aArg) aArg + +/** + * Version of ComSafeArrayIn for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayIn(aArg) SAFEARRAY *aArg + +/** + * Version of ComSafeArrayInIsNull for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayInIsNull(aArg) ComSafeArrayInIsNull(aArg) + +/** + * Version of ComSafeArrayInArg for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayInArg(aArg) ComSafeArrayInArg(aArg) + +/** + * Version of ComSafeArrayOut for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayOut(aArg) SAFEARRAY **aArg + +/** + * Version of ComSafeArrayOutIsNull for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayOutIsNull(aArg) ComSafeArrayOutIsNull(aArg) + +/** + * Version of ComSafeArrayOutArg for GUID. + * @param aArg Parameter name to wrap. + */ +#define ComSafeGUIDArrayOutArg(aArg) ComSafeArrayOutArg(aArg) + +/** + * Gets size of safearray parameter. + * @param aArg Parameter name. + */ +#define ComSafeArraySize(aArg) ((aArg) == NULL ? 0 : (aArg)->rgsabound[0].cElements) + +/** + * Apply RT_NOREF_PV to a safearray parameter. + * @param aArg Parameter name. + */ +#define ComSafeArrayNoRef(aArg) RT_NOREF_PV(aArg) + +/** + * Returns the const reference to the IID (i.e., |const GUID &|) of the given + * interface. + * + * @param I interface class + */ +#define COM_IIDOF(I) __uuidof(I) + +/** + * For using interfaces before including the interface definitions. This will + * deal with XPCOM using 'class' and COM using 'struct' when defining + * interfaces. + * + * @param I interface name. + */ +#define COM_STRUCT_OR_CLASS(I) struct I + +#else /* defined(RT_OS_WINDOWS) */ + +#error "VBOX_WITH_XPCOM must be defined on a platform other than Windows!" + +#endif /* defined(RT_OS_WINDOWS) */ + +#else /* !defined(VBOX_WITH_XPCOM) */ + +// XPCOM +///////////////////////////////////////////////////////////////////////////// + +#if defined(RT_OS_DARWIN) || (defined(QT_VERSION) && (QT_VERSION >= 0x040000)) + /* CFBase.h defines these & + * qglobal.h from Qt4 defines these */ +# undef FALSE +# undef TRUE +#endif /* RT_OS_DARWIN || QT_VERSION */ + +#include + +#define HRESULT nsresult +#define SUCCEEDED NS_SUCCEEDED +#define FAILED NS_FAILED + +#define SUCCEEDED_WARNING(rc) (NS_SUCCEEDED(rc) && (rc) != NS_OK) + +#define FAILED_DEAD_INTERFACE(rc) ( (rc) == NS_ERROR_ABORT \ + || (rc) == NS_ERROR_CALL_FAILED \ + ) + +#define IUnknown nsISupports + +#define BOOL PRBool +#define BYTE PRUint8 +#define SHORT PRInt16 +#define USHORT PRUint16 +#define LONG PRInt32 +#define ULONG PRUint32 +#define LONG64 PRInt64 +#define ULONG64 PRUint64 +/* XPCOM has only 64bit floats */ +#define FLOAT PRFloat64 +#define DOUBLE PRFloat64 + +#define FALSE PR_FALSE +#define TRUE PR_TRUE + +#define OLECHAR wchar_t + +/* note: typedef to semantically match BSTR on Win32 */ +typedef PRUnichar *BSTR; +typedef const PRUnichar *CBSTR; +typedef BSTR *LPBSTR; + +/** Input BSTR argument the interface method declaration. */ +#define IN_BSTR CBSTR + +/** + * Type to define a raw GUID variable (for members use the com::Guid class + * instead). + */ +#define GUID nsID +/** Input GUID argument the interface method declaration. */ +#define IN_GUID const nsID & +/** Output GUID argument the interface method declaration. */ +#define OUT_GUID nsID ** + +/** Makes the name of the getter interface function (n must be capitalized). */ +#define COMGETTER(n) Get##n +/** Makes the name of the setter interface function (n must be capitalized). */ +#define COMSETTER(n) Set##n + +/* safearray input parameter macros */ +#define ComSafeArrayIn(aType, aArg) PRUint32 aArg##Size, aType *aArg +#define ComSafeArrayInIsNull(aArg) ((aArg) == NULL) +#define ComSafeArrayInArg(aArg) aArg##Size, aArg + +/* safearray output parameter macros */ +#define ComSafeArrayOut(aType, aArg) PRUint32 *aArg##Size, aType **aArg +#define ComSafeArrayOutIsNull(aArg) ((aArg) == NULL) +#define ComSafeArrayOutArg(aArg) aArg##Size, aArg + +/* safearray input parameter macros for GUID */ +#define ComSafeGUIDArrayIn(aArg) PRUint32 aArg##Size, const nsID **aArg +#define ComSafeGUIDArrayInIsNull(aArg) ComSafeArrayInIsNull(aArg) +#define ComSafeGUIDArrayInArg(aArg) ComSafeArrayInArg(aArg) + +/* safearray output parameter macros for GUID */ +#define ComSafeGUIDArrayOut(aArg) PRUint32 *aArg##Size, nsID ***aArg +#define ComSafeGUIDArrayOutIsNull(aArg) ComSafeArrayOutIsNull(aArg) +#define ComSafeGUIDArrayOutArg(aArg) ComSafeArrayOutArg(aArg) + +/** safearray size */ +#define ComSafeArraySize(aArg) ((aArg) == NULL ? 0 : (aArg##Size)) + +/** NOREF a COM safe array argument. */ +#define ComSafeArrayNoRef(aArg) RT_NOREF2(aArg, aArg##Size) + +/* CLSID and IID for compatibility with Win32 */ +typedef nsCID CLSID; +typedef nsIID IID; + +/* OLE error codes */ +#define S_OK ((nsresult)NS_OK) +#define S_FALSE ((nsresult)1) +#define E_UNEXPECTED NS_ERROR_UNEXPECTED +#define E_NOTIMPL NS_ERROR_NOT_IMPLEMENTED +#define E_OUTOFMEMORY NS_ERROR_OUT_OF_MEMORY +#define E_INVALIDARG NS_ERROR_INVALID_ARG +#define E_NOINTERFACE NS_ERROR_NO_INTERFACE +#define E_POINTER NS_ERROR_NULL_POINTER +#define E_ABORT NS_ERROR_ABORT +#define E_FAIL NS_ERROR_FAILURE +/* Note: a better analog for E_ACCESSDENIED would probably be + * NS_ERROR_NOT_AVAILABLE, but we want binary compatibility for now. */ +#define E_ACCESSDENIED ((nsresult)0x80070005L) + +#define STDMETHOD(a) NS_IMETHOD a +#define STDMETHODIMP NS_IMETHODIMP +#define STDMETHOD_(ret, meth) NS_IMETHOD_(ret) meth + +#define COM_IIDOF(I) NS_GET_IID(I) + +#define COM_STRUCT_OR_CLASS(I) class I + +/* helper functions */ +extern "C" +{ +BSTR SysAllocString(const OLECHAR *sz); +BSTR SysAllocStringByteLen(char const *psz, unsigned int len); +BSTR SysAllocStringLen(const OLECHAR *pch, unsigned int cch); +void SysFreeString(BSTR bstr); +int SysReAllocString(BSTR *pbstr, const OLECHAR *psz); +int SysReAllocStringLen(BSTR *pbstr, const OLECHAR *psz, unsigned int cch); +unsigned int SysStringByteLen(BSTR bstr); +unsigned int SysStringLen(BSTR bstr); +} + +#ifndef VBOX_COM_NO_ATL + +namespace ATL +{ + +#define ATL_NO_VTABLE +#define DECLARE_CLASSFACTORY(a) +#define DECLARE_CLASSFACTORY_SINGLETON(a) +#define DECLARE_REGISTRY_RESOURCEID(a) +#define DECLARE_NOT_AGGREGATABLE(a) +#define DECLARE_PROTECT_FINAL_CONSTRUCT() +#define BEGIN_COM_MAP(a) +#define COM_INTERFACE_ENTRY(a) +#define COM_INTERFACE_ENTRY2(a,b) +#define END_COM_MAP() NS_DECL_ISUPPORTS +#define COM_INTERFACE_ENTRY_AGGREGATE(a,b) + +/* A few very simple ATL emulator classes to provide + * FinalConstruct()/FinalRelease() functionality with XPCOM. */ + +class CComMultiThreadModel +{ +}; + +template class CComObjectRootEx +{ +public: + HRESULT FinalConstruct() + { + return S_OK; + } + void FinalRelease() + { + } +}; + +template class CComObject : public Base +{ +public: + virtual ~CComObject() { this->FinalRelease(); } +}; + +} /* namespace ATL */ + + +/** + * 'Constructor' for the component class. + * This constructor, as opposed to NS_GENERIC_FACTORY_CONSTRUCTOR, + * assumes that the component class is derived from the CComObjectRootEx<> + * template, so it calls FinalConstruct() right after object creation + * and ensures that FinalRelease() will be called right before destruction. + * The result from FinalConstruct() is returned to the caller. + */ +#define NS_GENERIC_FACTORY_CONSTRUCTOR_WITH_RC(_InstanceClass) \ +static NS_IMETHODIMP \ +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ + void **aResult) \ +{ \ + nsresult rv; \ + \ + *aResult = NULL; \ + if (NULL != aOuter) { \ + rv = NS_ERROR_NO_AGGREGATION; \ + return rv; \ + } \ + \ + ATL::CComObject<_InstanceClass> *inst = new ATL::CComObject<_InstanceClass>(); \ + if (NULL == inst) { \ + rv = NS_ERROR_OUT_OF_MEMORY; \ + return rv; \ + } \ + \ + NS_ADDREF(inst); /* protect FinalConstruct() */ \ + rv = inst->FinalConstruct(); \ + if (NS_SUCCEEDED(rv)) \ + rv = inst->QueryInterface(aIID, aResult); \ + NS_RELEASE(inst); \ + \ + return rv; \ +} + +/** + * 'Constructor' that uses an existing getter function that gets a singleton. + * The getter function must have the following prototype: + * nsresult _GetterProc(_InstanceClass **inst) + * This constructor, as opposed to NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR, + * lets the getter function return a result code that is passed back to the + * caller that tries to instantiate the object. + * NOTE: assumes that getter does an AddRef - so additional AddRef is not done. + */ +#define NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR_WITH_RC(_InstanceClass, _GetterProc) \ +static NS_IMETHODIMP \ +_InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID, \ + void **aResult) \ +{ \ + nsresult rv; \ + \ + _InstanceClass *inst = NULL; /* initialized to shut up gcc */ \ + \ + *aResult = NULL; \ + if (NULL != aOuter) { \ + rv = NS_ERROR_NO_AGGREGATION; \ + return rv; \ + } \ + \ + rv = _GetterProc(&inst); \ + if (NS_FAILED(rv)) \ + return rv; \ + \ + /* sanity check */ \ + if (NULL == inst) \ + return NS_ERROR_OUT_OF_MEMORY; \ + \ + /* NS_ADDREF(inst); */ \ + if (NS_SUCCEEDED(rv)) { \ + rv = inst->QueryInterface(aIID, aResult); \ + } \ + NS_RELEASE(inst); \ + \ + return rv; \ +} + +#endif /* !VBOX_COM_NO_ATL */ + +#endif /* !defined(VBOX_WITH_XPCOM) */ + +/** + * Declares a wchar_t string literal from the argument. + * Necessary to overcome MSC / GCC differences. + * @param s expression to stringify + */ +#if defined(_MSC_VER) +# define WSTR_LITERAL(s) L#s +#elif defined(__GNUC__) +# define WSTR_LITERAL(s) L""#s +#else +# error "Unsupported compiler!" +#endif + +namespace com +{ + +#ifndef VBOX_COM_NO_ATL + +// use this macro to implement scriptable interfaces +#ifdef RT_OS_WINDOWS +#define VBOX_SCRIPTABLE_IMPL(iface) \ + public ATL::IDispatchImpl + +#define VBOX_SCRIPTABLE_DISPATCH_IMPL(iface) \ + STDMETHOD(QueryInterface)(REFIID riid, void **ppObj) \ + { \ + if (riid == IID_##iface) \ + { \ + *ppObj = (iface *)this; \ + AddRef(); \ + return S_OK; \ + } \ + if (riid == IID_IUnknown) \ + { \ + *ppObj = (IUnknown *)this; \ + AddRef(); \ + return S_OK; \ + } \ + if (riid == IID_IDispatch) \ + { \ + *ppObj = (IDispatch *)this; \ + AddRef(); \ + return S_OK; \ + } \ + *ppObj = NULL; \ + return E_NOINTERFACE; \ + } +#else +#define VBOX_SCRIPTABLE_IMPL(iface) \ + public iface +#define VBOX_SCRIPTABLE_DISPATCH_IMPL(iface) +#endif + +#endif /* !VBOX_COM_NO_ATL */ + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_defs_h */ + diff --git a/include/VBox/com/errorprint.h b/include/VBox/com/errorprint.h new file mode 100644 index 00000000..037b1ff4 --- /dev/null +++ b/include/VBox/com/errorprint.h @@ -0,0 +1,401 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Error Reporting. + * + * Error printing macros using shared functions defined in shared glue code. + * Use these CHECK_* macros for efficient error checking around calling COM + * methods. + */ + +/* + * Copyright (C) 2009-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_errorprint_h +#define VBOX_INCLUDED_com_errorprint_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/** @defgroup grp_com_error_reporting Error Reporting + * @ingroup grp_com + * @{ + */ + +namespace com +{ + +// shared prototypes; these are defined in shared glue code and are +// compiled only once for all front-ends +void GluePrintErrorInfo(const com::ErrorInfo &info); +void GluePrintErrorContext(const char *pcszContext, const char *pcszSourceFile, uint32_t uLine, bool fWarning = false); +void GluePrintRCMessage(HRESULT rc); +void GlueHandleComError(ComPtr iface, const char *pcszContext, HRESULT rc, const char *pcszSourceFile, uint32_t uLine); +void GlueHandleComErrorNoCtx(ComPtr iface, HRESULT rc); +void GlueHandleComErrorProgress(ComPtr progress, const char *pcszContext, HRESULT rc, + const char *pcszSourceFile, uint32_t uLine); + +/** + * Extended macro that implements all the other CHECK_ERROR2XXX macros. + * + * Calls the method of the given interface and checks the return status code. + * If the status indicates failure, as much information as possible is reported + * about the error, including current source file and line. + * + * After reporting an error, the statement |stmtError| is executed. + * + * This macro family is intended for command line tools like VBoxManage, but + * could also be handy for debugging. + * + * @param type For defining @a hrc locally inside the the macro + * expansion, pass |HRESULT| otherwise |RT_NOTHING|. + * @param hrc Name of the HRESULT variable to assign the result of the + * method call to. + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @param stmtError Statement to be executed after reporting failures. This + * can be a |break| or |return| statement, if so desired. + * + * @remarks Unlike CHECK_ERROR, CHECK_ERROR_RET and family, this macro family + * does not presuppose a |rc| variable but instead either let the user + * specify the variable to use or employs a local variable |hrcCheck| + * within its own scope. + * + * @sa CHECK_ERROR2, CHECK_ERROR2I, CHECK_ERROR2_STMT, CHECK_ERROR2I_STMT, + * CHECK_ERROR2_BREAK, CHECK_ERROR2I_BREAK, CHECK_ERROR2_RET, + * CHECK_ERROR2I_RET + */ +#define CHECK_ERROR2_EX(type, hrc, iface, method, stmtError) \ + if (1) { \ + type hrc = iface->method; \ + if (SUCCEEDED(hrc) && !SUCCEEDED_WARNING(hrc)) \ + { /*likely*/ } \ + else \ + { \ + com::GlueHandleComError(iface, #method, (hrc), __FILE__, __LINE__); \ + if (!SUCCEEDED_WARNING(hrc)) \ + { \ + stmtError; \ + } \ + } \ + } else do { /* nothing */ } while (0) + + +/** + * Calls the given method of the given interface and then checks if the return + * value (COM result code) indicates a failure. If so, prints the failed + * function/line/file, the description of the result code and attempts to + * query the extended error information on the current thread (using + * com::ErrorInfo) if the interface reports that it supports error information. + * + * Used by command line tools or for debugging and assumes the |HRESULT rc| + * variable is accessible for assigning in the current scope. + * @sa CHECK_ERROR2, CHECK_ERROR2I + */ +#define CHECK_ERROR(iface, method) \ + do { \ + hrc = iface->method; \ + if (FAILED(hrc) || SUCCEEDED_WARNING(hrc)) \ + com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \ + } while (0) +/** + * Simplified version of CHECK_ERROR2_EX, no error statement or type necessary. + * + * @param hrc Name of the HRESULT variable to assign the result of the + * method call to. + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @sa CHECK_ERROR2I, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2(hrc, iface, method) CHECK_ERROR2_EX(RT_NOTHING, hrc, iface, method, (void)1) +/** + * Simplified version of CHECK_ERROR2_EX that uses an internal variable + * |hrcCheck| for holding the result and have no error statement. + * + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @sa CHECK_ERROR2, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2I(iface, method) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, (void)1) + + +/** + * Same as CHECK_ERROR except that it also executes the statement |stmt| on + * failure. + * @sa CHECK_ERROR2_STMT, CHECK_ERROR2I_STMT + */ +#define CHECK_ERROR_STMT(iface, method, stmt) \ + do { \ + hrc = iface->method; \ + if (FAILED(hrc) || SUCCEEDED_WARNING(hrc)) \ + { \ + com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \ + if (!SUCCEEDED_WARNING(hrc) \ + { \ + stmt; \ + } \ + } \ + } while (0) +/** + * Simplified version of CHECK_ERROR2_EX (no @a hrc type). + * + * @param hrc Name of the HRESULT variable to assign the result of the + * method call to. + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @param stmt Statement to be executed after reporting failures. + * @sa CHECK_ERROR2I_STMT, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2_STMT(hrc, iface, method, stmt) CHECK_ERROR2_EX(RT_NOTHING, hrc, iface, method, stmt) +/** + * Simplified version of CHECK_ERROR2_EX that uses an internal variable + * |hrcCheck| for holding the result. + * + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @param stmt Statement to be executed after reporting failures. + * @sa CHECK_ERROR2_STMT, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2I_STMT(iface, method, stmt) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, stmt) + + +/** + * Does the same as CHECK_ERROR(), but executes the |break| statement on + * failure. + * @sa CHECK_ERROR2_BREAK, CHECK_ERROR2I_BREAK + */ +#ifdef __GNUC__ +# define CHECK_ERROR_BREAK(iface, method) \ + __extension__ \ + ({ \ + hrc = iface->method; \ + if (FAILED(hrc) || SUCCEEDED_WARNING(hrc)) \ + { \ + com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \ + if (!SUCCEEDED_WARNING(hrc)) \ + break; \ + } \ + }) +#else +# define CHECK_ERROR_BREAK(iface, method) \ + if (1) \ + { \ + hrc = iface->method; \ + if (FAILED(hrc)) \ + { \ + com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \ + if (!SUCCEEDED_WARNING(hrc)) \ + break; \ + } \ + } \ + else do {} while (0) +#endif +/** + * Simplified version of CHECK_ERROR2_EX that executes the |break| statement + * after error reporting (no @a hrc type). + * + * @param hrc The result variable (type HRESULT). + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @sa CHECK_ERROR2I_BREAK, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2_BREAK(hrc, iface, method) CHECK_ERROR2_EX(RT_NOTHING, hrc, iface, method, break) +/** + * Simplified version of CHECK_ERROR2_EX that executes the |break| statement + * after error reporting and that uses an internal variable |hrcCheck| for + * holding the result. + * + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @sa CHECK_ERROR2_BREAK, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2I_BREAK(iface, method) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, break) +/** + * Simplified version of CHECK_ERROR2_EX that executes the |stmt;break| + * statements after error reporting and that uses an internal variable + * |hrcCheck| for holding the result. + * + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @param stmt Statement to be executed after reporting failures. + * @sa CHECK_ERROR2_BREAK, CHECK_ERROR2_EX + */ +#define CHECK_ERROR2I_BREAK_STMT(iface, method, stmt) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, stmt; break) + + +/** + * Does the same as CHECK_ERROR(), but executes the |return ret| statement on + * failure. + * @sa CHECK_ERROR2_RET, CHECK_ERROR2I_RET + */ +#define CHECK_ERROR_RET(iface, method, ret) \ + do { \ + hrc = iface->method; \ + if (FAILED(hrc) || SUCCEEDED_WARNING(hrc)) \ + { \ + com::GlueHandleComError(iface, #method, hrc, __FILE__, __LINE__); \ + if (!SUCCEEDED_WARNING(hrc)) \ + return (ret); \ + } \ + } while (0) +/** + * Simplified version of CHECK_ERROR2_EX that executes the |return (rcRet)| + * statement after error reporting. + * + * @param hrc The result variable (type HRESULT). + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @param rcRet What to return on failure. + */ +#define CHECK_ERROR2_RET(hrc, iface, method, rcRet) CHECK_ERROR2_EX(RT_NOTHING, hrc, iface, method, return (rcRet)) +/** + * Simplified version of CHECK_ERROR2_EX that executes the |return (rcRet)| + * statement after error reporting and that uses an internal variable |hrcCheck| + * for holding the result. + * + * @param iface The interface pointer (can be a smart pointer object). + * @param method The method to invoke together with the parameters. + * @param rcRet What to return on failure. Use |hrcCheck| to return + * the status code of the method call. + */ +#define CHECK_ERROR2I_RET(iface, method, rcRet) CHECK_ERROR2_EX(HRESULT, hrcCheck, iface, method, return (rcRet)) + + +/** + * Check the progress object for an error and if there is one print out the + * extended error information. + * @remarks Requires HRESULT variable named @a rc. + */ +#define CHECK_PROGRESS_ERROR(progress, msg) \ + do { \ + LONG iRc; \ + hrc = progress->COMGETTER(ResultCode)(&iRc); \ + if (FAILED(hrc) || FAILED(iRc)) \ + { \ + if (SUCCEEDED(hrc)) hrc = iRc; else iRc = hrc; \ + RTMsgError msg; \ + com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, iRc, __FILE__, __LINE__); \ + } \ + } while (0) + +/** + * Does the same as CHECK_PROGRESS_ERROR(), but executes the |break| statement + * on failure. + * @remarks Requires HRESULT variable named @a rc. + */ +#ifdef __GNUC__ +# define CHECK_PROGRESS_ERROR_BREAK(progress, msg) \ + __extension__ \ + ({ \ + LONG iRc; \ + hrc = progress->COMGETTER(ResultCode)(&iRc); \ + if (FAILED(hrc) || FAILED(iRc)) \ + { \ + if (SUCCEEDED(hrc)) hrc = iRc; else iRc = hrc; \ + RTMsgError msg; \ + com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, iRc, __FILE__, __LINE__); \ + break; \ + } \ + }) +#else +# define CHECK_PROGRESS_ERROR_BREAK(progress, msg) \ + if (1) \ + { \ + LONG iRc; \ + hrc = progress->COMGETTER(ResultCode)(&iRc); \ + if (FAILED(hrc) || FAILED(iRc)) \ + { \ + if (SUCCEEDED(hrc)) hrc = iRc; else iRc = hrc; \ + RTMsgError msg; \ + com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, iRc, __FILE__, __LINE__); \ + break; \ + } \ + } \ + else do {} while (0) +#endif + +/** + * Does the same as CHECK_PROGRESS_ERROR(), but executes the |return ret| + * statement on failure. + */ +#define CHECK_PROGRESS_ERROR_RET(progress, msg, ret) \ + do { \ + LONG iRc; \ + HRESULT hrcCheck = progress->COMGETTER(ResultCode)(&iRc); \ + if (SUCCEEDED(hrcCheck) && SUCCEEDED(iRc)) \ + { /* likely */ } \ + else \ + { \ + RTMsgError msg; \ + com::GlueHandleComErrorProgress(progress, __PRETTY_FUNCTION__, \ + SUCCEEDED(hrcCheck) ? iRc : hrcCheck, __FILE__, __LINE__); \ + return (ret); \ + } \ + } while (0) + +/** + * Asserts the given expression is true. When the expression is false, prints + * a line containing the failed function/line/file; otherwise does nothing. + */ +#define ASSERT(expr) \ + do { \ + if (!(expr)) \ + { \ + RTPrintf ("[!] ASSERTION FAILED at line %d: %s\n", __LINE__, #expr); \ + Log (("[!] ASSERTION FAILED at line %d: %s\n", __LINE__, #expr)); \ + } \ + } while (0) + + +/** + * Does the same as ASSERT(), but executes the |return ret| statement if the + * expression to assert is false; + * @remarks WARNING! @a expr is evalutated TWICE! + */ +#define ASSERT_RET(expr, ret) \ + do { ASSERT(expr); if (!(expr)) return (ret); } while (0) + +/** + * Does the same as ASSERT(), but executes the |break| statement if the + * expression to assert is false; + * @remarks WARNING! @a expr is evalutated TWICE! + */ +#define ASSERT_BREAK(expr, ret) \ + if (1) { ASSERT(expr); if (!(expr)) break; } else do {} while (0) + +} /* namespace com */ + + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_errorprint_h */ + diff --git a/include/VBox/com/list.h b/include/VBox/com/list.h new file mode 100644 index 00000000..e898e15b --- /dev/null +++ b/include/VBox/com/list.h @@ -0,0 +1,223 @@ +/* $Id: list.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - List classes declaration. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_list_h +#define VBOX_INCLUDED_com_list_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +/** @defgroup grp_com_list List Classes + * @ingroup grp_com + * @{ + */ + +/** + * Specialized list class for using with com::ComPtr + * + * @note This is necessary cause ComPtr has a size of 8. + */ +template +class RTCList< ComPtr >: public RTCListBase< ComPtr, ComPtr*, false> +{ + /* Traits */ + typedef ComPtr T; + typedef T *ITYPE; + static const bool MT = false; + typedef RTCListBase BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized list class for using with com::ComObjPtr + * + * @note: This is necessary cause ComObjPtr has a size of 8. + */ +template +class RTCList< ComObjPtr >: public RTCListBase< ComObjPtr, ComObjPtr*, false> +{ + /* Traits */ + typedef ComObjPtr T; + typedef T *ITYPE; + static const bool MT = false; + typedef RTCListBase BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized list class for using with com::Utf8Str. + * + * The class offers methods for importing com::SafeArray's of com::Bstr's. + */ +template <> +class RTCList: public RTCListBase +{ + /* Traits */ + typedef com::Utf8Str T; + typedef T *ITYPE; + static const bool MT = false; + typedef RTCListBase BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. The com::Bstr's are silently converted to + * com::Utf8Str's. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCList(ComSafeArrayIn(IN_BSTR, other)) + { + com::SafeArray sfaOther(ComSafeArrayInArg(other)); + size_t const cElementsOther = sfaOther.size(); + resizeArray(cElementsOther); + m_cElements = cElementsOther; + for (size_t i = 0; i < cElementsOther; ++i) + RTCListHelper::set(m_pArray, i, T(sfaOther[i])); + } + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. The com::Bstr's are silently converted to + * com::Utf8Str's. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCList(const com::SafeArray &other) + : BASE(other.size()) + { + for (size_t i = 0; i < m_cElements; ++i) + RTCListHelper::set(m_pArray, i, T(other[i])); + } + + /** + * Copy the items of the other list into this list. All previous items of + * this list are deleted. + * + * @param other The list to copy. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase &operator=(const com::SafeArray &other) + { + m_guard.enterWrite(); + + /* Values cleanup */ + RTCListHelper::eraseRange(m_pArray, 0, m_cElements); + + /* Copy */ + size_t cElementsOther = other.size(); + if (cElementsOther != m_cCapacity) + resizeArrayNoErase(cElementsOther); + m_cElements = cElementsOther; + for (size_t i = 0; i < cElementsOther; ++i) + RTCListHelper::set(m_pArray, i, T(other[i])); + + m_guard.leaveWrite(); + return *this; + } + + /** + * Implicit conversion to a RTCString list. + * + * This allows the usage of the RTCString::join method with this list type. + * + * @return a converted const reference to this list. + */ + operator const RTCList&() + { + return *reinterpret_cast *>(this); + } + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_list_h */ + diff --git a/include/VBox/com/listeners.h b/include/VBox/com/listeners.h new file mode 100644 index 00000000..06f35ebf --- /dev/null +++ b/include/VBox/com/listeners.h @@ -0,0 +1,194 @@ +/* $Id: listeners.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - Listener helpers. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_listeners_h +#define VBOX_INCLUDED_com_listeners_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_com_listeners Listener Helpers + * @ingroup grp_com + * @{ + */ + + +#ifdef VBOX_WITH_XPCOM +# define NS_IMPL_QUERY_HEAD_INLINE() \ +NS_IMETHODIMP QueryInterface(REFNSIID aIID, void **aInstancePtr) \ +{ \ + NS_ASSERTION(aInstancePtr, "QueryInterface requires a non-NULL destination!"); \ + nsISupports *foundInterface; + +# define NS_INTERFACE_MAP_BEGIN_INLINE() NS_IMPL_QUERY_HEAD_INLINE() + +# define NS_IMPL_QUERY_INTERFACE1_INLINE(a_i1) \ + NS_INTERFACE_MAP_BEGIN_INLINE() \ + NS_INTERFACE_MAP_ENTRY(a_i1) \ + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, a_i1) \ + NS_INTERFACE_MAP_END +#endif + +template +class ListenerImpl : + public ATL::CComObjectRootEx, + VBOX_SCRIPTABLE_IMPL(IEventListener) +{ + T* mListener; + +#ifdef RT_OS_WINDOWS + /* FTM stuff */ + ComPtr m_pUnkMarshaler; +#else + nsAutoRefCnt mRefCnt; + NS_DECL_OWNINGTHREAD +#endif + +public: + ListenerImpl() + { + } + + virtual ~ListenerImpl() + { + } + + HRESULT init(T* aListener, TParam param) + { + mListener = aListener; + return mListener->init(param); + } + + HRESULT init(T* aListener) + { + mListener = aListener; + return mListener->init(); + } + + void uninit() + { + if (mListener) + { + mListener->uninit(); + delete mListener; + mListener = 0; + } + } + + HRESULT FinalConstruct() + { +#ifdef RT_OS_WINDOWS + return CoCreateFreeThreadedMarshaler(this, &m_pUnkMarshaler.m_p); +#else + return S_OK; +#endif + } + + void FinalRelease() + { + uninit(); +#ifdef RT_OS_WINDOWS + m_pUnkMarshaler.setNull(); +#endif + } + + T* getWrapped() + { + return mListener; + } + + DECLARE_NOT_AGGREGATABLE(ListenerImpl) + + DECLARE_PROTECT_FINAL_CONSTRUCT() + +#ifdef RT_OS_WINDOWS + BEGIN_COM_MAP(ListenerImpl) + COM_INTERFACE_ENTRY(IEventListener) + COM_INTERFACE_ENTRY2(IDispatch, IEventListener) + COM_INTERFACE_ENTRY_AGGREGATE(IID_IMarshal, m_pUnkMarshaler.m_p) + END_COM_MAP() +#else + NS_IMETHOD_(nsrefcnt) AddRef(void) + { + NS_PRECONDITION(PRInt32(mRefCnt) >= 0, "illegal refcnt"); + nsrefcnt count; + count = PR_AtomicIncrement((PRInt32*)&mRefCnt); + NS_LOG_ADDREF(this, count, "ListenerImpl", sizeof(*this)); + return count; + } + + NS_IMETHOD_(nsrefcnt) Release(void) + { + nsrefcnt count; + NS_PRECONDITION(0 != mRefCnt, "dup release"); + count = PR_AtomicDecrement((PRInt32 *)&mRefCnt); + NS_LOG_RELEASE(this, count, "ListenerImpl"); + if (0 == count) { + mRefCnt = 1; /* stabilize */ + /* enable this to find non-threadsafe destructors: */ + /* NS_ASSERT_OWNINGTHREAD(_class); */ + NS_DELETEXPCOM(this); + return 0; + } + return count; + } + + NS_IMPL_QUERY_INTERFACE1_INLINE(IEventListener) +#endif + + + STDMETHOD(HandleEvent)(IEvent * aEvent) + { + VBoxEventType_T aType = VBoxEventType_Invalid; + HRESULT hrc = aEvent->COMGETTER(Type)(&aType); + AssertMsg(SUCCEEDED(hrc), ("hrc=%Rhrc\n", hrc)); RT_NOREF(hrc); + return mListener->HandleEvent(aType, aEvent); + } +}; + +#ifdef VBOX_WITH_XPCOM +# define VBOX_LISTENER_DECLARE(klazz) NS_DECL_CLASSINFO(klazz) +#else +# define VBOX_LISTENER_DECLARE(klazz) +#endif + +/** @} */ +#endif /* !VBOX_INCLUDED_com_listeners_h */ + diff --git a/include/VBox/com/microatl.h b/include/VBox/com/microatl.h new file mode 100644 index 00000000..7066ed02 --- /dev/null +++ b/include/VBox/com/microatl.h @@ -0,0 +1,1408 @@ +/** @file + * ATL lookalike, just the tiny subset we actually need. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_microatl_h +#define VBOX_INCLUDED_com_microatl_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include /* VBOX_STRICT */ +#include +#include +#include /* RT_FAILURE() */ + +#include + +#include + + +namespace ATL +{ + +#define ATL_NO_VTABLE __declspec(novtable) + +class CAtlModule; +__declspec(selectany) CAtlModule *_pAtlModule = NULL; + +class CComModule; +__declspec(selectany) CComModule *_pModule = NULL; + +typedef HRESULT (WINAPI FNCREATEINSTANCE)(void *pv, REFIID riid, void **ppv); +typedef FNCREATEINSTANCE *PFNCREATEINSTANCE; +typedef HRESULT (WINAPI FNINTERFACEMAPHELPER)(void *pv, REFIID riid, void **ppv, DWORD_PTR dw); +typedef FNINTERFACEMAPHELPER *PFNINTERFACEMAPHELPER; +typedef void (__stdcall FNATLTERMFUNC)(void *pv); +typedef FNATLTERMFUNC *PFNATLTERMFUNC; + +struct _ATL_TERMFUNC_ELEM +{ + PFNATLTERMFUNC pfn; + void *pv; + _ATL_TERMFUNC_ELEM *pNext; +}; + +struct _ATL_INTMAP_ENTRY +{ + const IID *piid; // interface ID + DWORD_PTR dw; + PFNINTERFACEMAPHELPER pFunc; // NULL: end of array, 1: offset based map entry, other: function pointer +}; + +#define COM_SIMPLEMAPENTRY ((ATL::PFNINTERFACEMAPHELPER)1) + +#define DECLARE_CLASSFACTORY_EX(c) typedef ATL::CComCreator > _ClassFactoryCreatorClass; +#define DECLARE_CLASSFACTORY() DECLARE_CLASSFACTORY_EX(ATL::CComClassFactory) +#define DECLARE_CLASSFACTORY_SINGLETON(o) DECLARE_CLASSFACTORY_EX(ATL::CComClassFactorySingleton) +#define DECLARE_AGGREGATABLE(c) \ +public: \ + typedef ATL::CComCreator2 >, ATL::CComCreator > > _CreatorClass; +#define DECLARE_NOT_AGGREGATABLE(c) \ +public: \ + typedef ATL::CComCreator2 >, ATL::CComFailCreator > _CreatorClass; + +#define DECLARE_PROTECT_FINAL_CONSTRUCT() \ + void InternalFinalConstructAddRef() \ + { \ + InternalAddRef(); \ + } \ + void InternalFinalConstructRelease() \ + { \ + InternalRelease(); \ + } + +#define BEGIN_COM_MAP(c) \ +public: \ + typedef c _ComClass; \ + HRESULT _InternalQueryInterface(REFIID iid, void **ppvObj) throw() \ + { \ + return InternalQueryInterface(this, _GetEntries(), iid, ppvObj); \ + } \ + const static ATL::_ATL_INTMAP_ENTRY *WINAPI _GetEntries() throw() \ + { \ + static const ATL::_ATL_INTMAP_ENTRY _aInterfaces[] = \ + { + +#define COM_INTERFACE_ENTRY(c) \ + { &__uuidof(c), (DWORD_PTR)(static_cast((_ComClass *)8))-8, COM_SIMPLEMAPENTRY }, + +#define COM_INTERFACE_ENTRY2(c, c2) \ + { &__uuidof(c), (DWORD_PTR)(static_cast(static_cast((_ComClass *)8)))-8, COM_SIMPLEMAPENTRY }, + +#define COM_INTERFACE_ENTRY_AGGREGATE(iid, pUnk) \ + { &iid, (DWORD_PTR)RT_UOFFSETOF(_ComClass, pUnk), _Delegate}, + +#define END_COM_MAP() \ + { NULL, 0, NULL} \ + }; \ + return _aInterfaces; \ + } \ + virtual ULONG STDMETHODCALLTYPE AddRef(void) throw() = 0; \ + virtual ULONG STDMETHODCALLTYPE Release(void) throw() = 0; \ + STDMETHOD(QueryInterface)(REFIID, void **) throw() = 0; + +struct _ATL_OBJMAP_ENTRY +{ + const CLSID *pclsid; + PFNCREATEINSTANCE pfnGetClassObject; + PFNCREATEINSTANCE pfnCreateInstance; + IUnknown *pCF; + DWORD dwRegister; +}; + +#define BEGIN_OBJECT_MAP(o) static ATL::_ATL_OBJMAP_ENTRY o[] = { +#define END_OBJECT_MAP() {NULL, NULL, NULL, NULL, 0}}; +#define OBJECT_ENTRY(clsid, c) {&clsid, c::_ClassFactoryCreatorClass::CreateInstance, c::_CreatorClass::CreateInstance, NULL, 0 }, + + +class CComCriticalSection +{ +public: + CComCriticalSection() throw() + { + memset(&m_CritSect, 0, sizeof(m_CritSect)); + } + ~CComCriticalSection() + { + } + HRESULT Lock() throw() + { + RTCritSectEnter(&m_CritSect); + return S_OK; + } + HRESULT Unlock() throw() + { + RTCritSectLeave(&m_CritSect); + return S_OK; + } + HRESULT Init() throw() + { + HRESULT hrc = S_OK; + if (RT_FAILURE(RTCritSectInit(&m_CritSect))) + hrc = E_FAIL; + return hrc; + } + + HRESULT Term() throw() + { + RTCritSectDelete(&m_CritSect); + return S_OK; + } + + RTCRITSECT m_CritSect; +}; + +template +class CComCritSectLockManual +{ +public: + CComCritSectLockManual(CComCriticalSection &cs) + : m_cs(cs) + , m_fLocked(false) + { + } + + ~CComCritSectLockManual() throw() + { + if (m_fLocked) + Unlock(); + } + + HRESULT Lock() + { + Assert(!m_fLocked); + HRESULT hrc = m_cs.Lock(); + if (FAILED(hrc)) + return hrc; + m_fLocked = true; + return S_OK; + } + + void Unlock() throw() + { + Assert(m_fLocked); + m_cs.Unlock(); + m_fLocked = false; + } + + +private: + TLock &m_cs; + bool m_fLocked; + + CComCritSectLockManual(const CComCritSectLockManual&) throw(); // Do not call. + CComCritSectLockManual &operator=(const CComCritSectLockManual &) throw(); // Do not call. +}; + + +#ifdef RT_EXCEPTIONS_ENABLED +/** This is called CComCritSecLock in real ATL... */ +template +class CComCritSectLock : public CComCritSectLockManual +{ +public: + CComCritSectLock(CComCriticalSection &cs, bool fInitialLock = true) + : CComCritSectLockManual(cs) + { + if (fInitialLock) + { + HRESULT hrc = Lock(); + if (FAILED(hrc)) + throw hrc; + } + } + +private: + CComCritSectLock(const CComCritSectLock&) throw(); // Do not call. + CComCritSectLock &operator=(const CComCritSectLock &) throw(); // Do not call. +}; +#endif + +class CComFakeCriticalSection +{ +public: + HRESULT Lock() throw() + { + return S_OK; + } + HRESULT Unlock() throw() + { + return S_OK; + } + HRESULT Init() throw() + { + return S_OK; + } + HRESULT Term() throw() + { + return S_OK; + } +}; + +class CComAutoCriticalSection : public CComCriticalSection +{ +public: + CComAutoCriticalSection() + { + HRESULT hrc = CComCriticalSection::Init(); + if (FAILED(hrc)) + throw hrc; + } + ~CComAutoCriticalSection() throw() + { + CComCriticalSection::Term(); + } +private : + HRESULT Init() throw(); // Do not call. + HRESULT Term() throw(); // Do not call. +}; + +class CComAutoDeleteCriticalSection : public CComCriticalSection +{ +public: + CComAutoDeleteCriticalSection(): m_fInit(false) + { + } + + ~CComAutoDeleteCriticalSection() throw() + { + if (!m_fInit) + return; + m_fInit = false; + CComCriticalSection::Term(); + } + + HRESULT Init() throw() + { + Assert(!m_fInit); + HRESULT hrc = CComCriticalSection::Init(); + if (SUCCEEDED(hrc)) + m_fInit = true; + return hrc; + } + + HRESULT Lock() + { + Assert(m_fInit); + return CComCriticalSection::Lock(); + } + + HRESULT Unlock() + { + Assert(m_fInit); + return CComCriticalSection::Unlock(); + } + +private: + HRESULT Term() throw(); + bool m_fInit; +}; + + +class CComMultiThreadModelNoCS +{ +public: + static ULONG WINAPI Increment(LONG *pL) throw() + { + return InterlockedIncrement(pL); + } + static ULONG WINAPI Decrement(LONG *pL) throw() + { + return InterlockedDecrement(pL); + } + typedef CComFakeCriticalSection AutoCriticalSection; + typedef CComFakeCriticalSection AutoDeleteCriticalSection; + typedef CComMultiThreadModelNoCS ThreadModelNoCS; +}; + +class CComMultiThreadModel +{ +public: + static ULONG WINAPI Increment(LONG *pL) throw() + { + return InterlockedIncrement(pL); + } + static ULONG WINAPI Decrement(LONG *pL) throw() + { + return InterlockedDecrement(pL); + } + typedef CComAutoCriticalSection AutoCriticalSection; + typedef CComAutoDeleteCriticalSection AutoDeleteCriticalSection; + typedef CComMultiThreadModelNoCS ThreadModelNoCS; +}; + +class ATL_NO_VTABLE CAtlModule +{ +public: + static GUID m_LibID; + CComCriticalSection m_csStaticDataInitAndTypeInfo; + + CAtlModule() throw() + { + // One instance only per linking namespace! + AssertMsg(!_pAtlModule, ("CAtlModule: trying to create more than one instance per linking namespace\n")); + + fInit = false; + + m_cLock = 0; + m_pTermFuncs = NULL; + _pAtlModule = this; + + if (FAILED(m_csStaticDataInitAndTypeInfo.Init())) + { + AssertMsgFailed(("CAtlModule: failed to init critsect\n")); + return; + } + fInit = true; + } + + void Term() throw() + { + if (!fInit) + return; + + // Call all term functions. + if (m_pTermFuncs) + { + _ATL_TERMFUNC_ELEM *p = m_pTermFuncs; + _ATL_TERMFUNC_ELEM *pNext; + while (p) + { + p->pfn(p->pv); + pNext = p->pNext; + delete p; + p = pNext; + } + m_pTermFuncs = NULL; + } + m_csStaticDataInitAndTypeInfo.Term(); + fInit = false; + } + + virtual ~CAtlModule() throw() + { + Term(); + } + + virtual LONG Lock() throw() + { + return CComMultiThreadModel::Increment(&m_cLock); + } + + virtual LONG Unlock() throw() + { + return CComMultiThreadModel::Decrement(&m_cLock); + } + + virtual LONG GetLockCount() throw() + { + return m_cLock; + } + + HRESULT AddTermFunc(PFNATLTERMFUNC pfn, void *pv) + { + _ATL_TERMFUNC_ELEM *pNew = new(std::nothrow) _ATL_TERMFUNC_ELEM; + if (!pNew) + return E_OUTOFMEMORY; + pNew->pfn = pfn; + pNew->pv = pv; + CComCritSectLockManual lock(m_csStaticDataInitAndTypeInfo); + HRESULT hrc = lock.Lock(); + if (SUCCEEDED(hrc)) + { + pNew->pNext = m_pTermFuncs; + m_pTermFuncs = pNew; + } + else + { + delete pNew; + AssertMsgFailed(("CComModule::AddTermFunc: failed to lock critsect\n")); + } + return hrc; + } + +protected: + bool fInit; + LONG m_cLock; + _ATL_TERMFUNC_ELEM *m_pTermFuncs; +}; + +__declspec(selectany) GUID CAtlModule::m_LibID = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0} }; + +struct _ATL_COM_MODULE +{ + HINSTANCE m_hInstTypeLib; + CComCriticalSection m_csObjMap; +}; + +#ifndef _delayimp_h +extern "C" IMAGE_DOS_HEADER __ImageBase; +#endif + +class CAtlComModule : public _ATL_COM_MODULE +{ +public: + static bool m_fInitFailed; + CAtlComModule() throw() + { + m_hInstTypeLib = reinterpret_cast(&__ImageBase); + + if (FAILED(m_csObjMap.Init())) + { + AssertMsgFailed(("CAtlComModule: critsect init failed\n")); + m_fInitFailed = true; + return; + } + } + + ~CAtlComModule() + { + Term(); + } + + void Term() + { + m_csObjMap.Term(); + } +}; + +__declspec(selectany) bool CAtlComModule::m_fInitFailed = false; +__declspec(selectany) CAtlComModule _AtlComModule; + +template class ATL_NO_VTABLE CAtlModuleT : public CAtlModule +{ +public: + CAtlModuleT() throw() + { + T::InitLibId(); + } + + static void InitLibId() throw() + { + } +}; + +/** + * + * This class not _not_ be statically instantiated as a global variable! It may + * use VBoxRT before it's initialized otherwise, messing up logging and whatnot. + * + * When possible create the instance inside the TrustedMain() or main() as a + * stack variable. In DLLs use 'new' to instantiate it in the DllMain function. + */ +class CComModule : public CAtlModuleT +{ +public: + CComModule() + { + // One instance only per linking namespace! + AssertMsg(!_pModule, ("CComModule: trying to create more than one instance per linking namespace\n")); + _pModule = this; + m_pObjMap = NULL; + } + + ~CComModule() + { + } + + _ATL_OBJMAP_ENTRY *m_pObjMap; + HRESULT Init(_ATL_OBJMAP_ENTRY *p, HINSTANCE h, const GUID *pLibID = NULL) throw() + { + RT_NOREF1(h); + + if (pLibID) + m_LibID = *pLibID; + + // Go over the object map to do some sanity checking, making things + // crash early if something is seriously busted. + _ATL_OBJMAP_ENTRY *pEntry; + if (p != (_ATL_OBJMAP_ENTRY *)-1) + { + m_pObjMap = p; + if (m_pObjMap) + { + pEntry = m_pObjMap; + while (pEntry->pclsid) + pEntry++; + } + } + return S_OK; + } + + void Term() throw() + { + _ATL_OBJMAP_ENTRY *pEntry; + if (m_pObjMap) + { + pEntry = m_pObjMap; + while (pEntry->pclsid) + { + if (pEntry->pCF) + pEntry->pCF->Release(); + pEntry->pCF = NULL; + pEntry++; + } + } + + CAtlModuleT::Term(); + } + + HRESULT GetClassObject(REFCLSID rclsid, REFIID riid, void **ppv) throw() + { + *ppv = NULL; + HRESULT hrc = S_OK; + + if (m_pObjMap) + { + const _ATL_OBJMAP_ENTRY *pEntry = m_pObjMap; + + while (pEntry->pclsid) + { + if (pEntry->pfnGetClassObject && rclsid == *pEntry->pclsid) + { + if (!pEntry->pCF) + { + CComCritSectLockManual lock(_AtlComModule.m_csObjMap); + hrc = lock.Lock(); + if (FAILED(hrc)) + { + AssertMsgFailed(("CComModule::GetClassObject: failed to lock critsect\n")); + break; + } + + if (!pEntry->pCF) + { + hrc = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (void **)&pEntry->pCF); + } + } + + if (pEntry->pCF) + { + hrc = pEntry->pCF->QueryInterface(riid, ppv); + } + break; + } + pEntry++; + } + } + + return hrc; + } + + // For EXE only: register all class factories with COM. + HRESULT RegisterClassObjects(DWORD dwClsContext, DWORD dwFlags) throw() + { + HRESULT hrc = S_OK; + _ATL_OBJMAP_ENTRY *pEntry; + if (m_pObjMap) + { + pEntry = m_pObjMap; + while (pEntry->pclsid && SUCCEEDED(hrc)) + { + if (pEntry->pfnGetClassObject) + { + IUnknown *p; + hrc = pEntry->pfnGetClassObject(pEntry->pfnCreateInstance, __uuidof(IUnknown), (void **)&p); + if (SUCCEEDED(hrc)) + hrc = CoRegisterClassObject(*(pEntry->pclsid), p, dwClsContext, dwFlags, &pEntry->dwRegister); + if (p) + p->Release(); + } + pEntry++; + } + } + return hrc; + } + // For EXE only: revoke all class factories with COM. + HRESULT RevokeClassObjects() throw() + { + HRESULT hrc = S_OK; + _ATL_OBJMAP_ENTRY *pEntry; + if (m_pObjMap != NULL) + { + pEntry = m_pObjMap; + while (pEntry->pclsid && SUCCEEDED(hrc)) + { + if (pEntry->dwRegister) + hrc = CoRevokeClassObject(pEntry->dwRegister); + pEntry++; + } + } + return hrc; + } +}; + + +template class CComCreator +{ +public: + static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, void **ppv) + { + AssertReturn(ppv, E_POINTER); + *ppv = NULL; + HRESULT hrc = E_OUTOFMEMORY; + T *p = new(std::nothrow) T(pv); + if (p) + { + p->SetVoid(pv); + p->InternalFinalConstructAddRef(); + hrc = p->_AtlInitialConstruct(); + if (SUCCEEDED(hrc)) + hrc = p->FinalConstruct(); + p->InternalFinalConstructRelease(); + if (SUCCEEDED(hrc)) + hrc = p->QueryInterface(riid, ppv); + if (FAILED(hrc)) + delete p; + } + return hrc; + } +}; + +template class CComFailCreator +{ +public: + static HRESULT WINAPI CreateInstance(void *, REFIID, void **ppv) + { + AssertReturn(ppv, E_POINTER); + *ppv = NULL; + + return hrc; + } +}; + +template class CComCreator2 +{ +public: + static HRESULT WINAPI CreateInstance(void *pv, REFIID riid, void **ppv) + { + AssertReturn(ppv, E_POINTER); + + return !pv ? T1::CreateInstance(NULL, riid, ppv) : T2::CreateInstance(pv, riid, ppv); + } +}; + +template class CComObjectCached : public Base +{ +public: + CComObjectCached(void * = NULL) + { + } + virtual ~CComObjectCached() + { + // Catch refcount screwups by setting refcount to -(LONG_MAX/2). + m_iRef = -(LONG_MAX/2); + FinalRelease(); + } + STDMETHOD_(ULONG, AddRef)() throw() + { + // If you get errors about undefined InternalAddRef then Base does not + // derive from CComObjectRootEx. + ULONG l = InternalAddRef(); + if (l == 2) + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + _pAtlModule->Lock(); + } + return l; + } + STDMETHOD_(ULONG, Release)() throw() + { + // If you get errors about undefined InternalRelease then Base does not + // derive from CComObjectRootEx. + ULONG l = InternalRelease(); + if (l == 0) + delete this; + else if (l == 1) + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + _pAtlModule->Unlock(); + } + return l; + } + STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw() + { + // If you get errors about undefined _InternalQueryInterface then + // double check BEGIN_COM_MAP in the class definition. + return _InternalQueryInterface(iid, ppvObj); + } + static HRESULT WINAPI CreateInstance(CComObjectCached **pp) throw() + { + AssertReturn(pp, E_POINTER); + *pp = NULL; + + HRESULT hrc = E_OUTOFMEMORY; + CComObjectCached *p = new(std::nothrow) CComObjectCached(); + if (p) + { + p->SetVoid(NULL); + p->InternalFinalConstructAddRef(); + hrc = p->_AtlInitialConstruct(); + if (SUCCEEDED(hrc)) + hrc = p->FinalConstruct(); + p->InternalFinalConstructRelease(); + if (FAILED(hrc)) + delete p; + else + *pp = p; + } + return hrc; + } +}; + +template class CComObjectNoLock : public Base +{ +public: + CComObjectNoLock(void * = NULL) + { + } + virtual ~CComObjectNoLock() + { + // Catch refcount screwups by setting refcount to -(LONG_MAX/2). + m_iRef = -(LONG_MAX/2); + FinalRelease(); + } + STDMETHOD_(ULONG, AddRef)() throw() + { + // If you get errors about undefined InternalAddRef then Base does not + // derive from CComObjectRootEx. + return InternalAddRef(); + } + STDMETHOD_(ULONG, Release)() throw() + { + // If you get errors about undefined InternalRelease then Base does not + // derive from CComObjectRootEx. + ULONG l = InternalRelease(); + if (l == 0) + delete this; + return l; + } + STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw() + { + // If you get errors about undefined _InternalQueryInterface then + // double check BEGIN_COM_MAP in the class definition. + return _InternalQueryInterface(iid, ppvObj); + } +}; + +class CComTypeInfoHolder +{ + /** @todo implement type info caching, making stuff more efficient - would we benefit? */ +public: + const GUID *m_pGUID; + const GUID *m_pLibID; + WORD m_iMajor; + WORD m_iMinor; + ITypeInfo *m_pTInfo; + + HRESULT GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) + { + if (iTInfo != 0) + return DISP_E_BADINDEX; + return GetTI(lcid, ppTInfo); + } + HRESULT GetIDsOfNames(REFIID riid, LPOLESTR *pwszNames, UINT cNames, LCID lcid, DISPID *pDispID) + { + RT_NOREF1(riid); /* should be IID_NULL */ + HRESULT hrc = FetchTI(lcid); + if (m_pTInfo) + hrc = m_pTInfo->GetIDsOfNames(pwszNames, cNames, pDispID); + return hrc; + } + HRESULT Invoke(IDispatch *p, DISPID DispID, REFIID riid, LCID lcid, WORD iFlags, DISPPARAMS *pDispParams, + VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) + { + RT_NOREF1(riid); /* should be IID_NULL */ + HRESULT hrc = FetchTI(lcid); + if (m_pTInfo) + hrc = m_pTInfo->Invoke(p, DispID, iFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + return hrc; + } +private: + static void __stdcall Cleanup(void *pv) + { + AssertReturnVoid(pv); + CComTypeInfoHolder *p = (CComTypeInfoHolder *)pv; + if (p->m_pTInfo != NULL) + p->m_pTInfo->Release(); + p->m_pTInfo = NULL; + } + + HRESULT GetTI(LCID lcid) + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + Assert(m_pLibID && m_pGUID); + if (m_pTInfo) + return S_OK; + + CComCritSectLockManual lock(_pAtlModule->m_csStaticDataInitAndTypeInfo); + HRESULT hrc = lock.Lock(); + if (SUCCEEDED(hrc)) + { + ITypeLib *pTypeLib = NULL; + Assert(*m_pLibID != GUID_NULL); + hrc = LoadRegTypeLib(*m_pLibID, m_iMajor, m_iMinor, lcid, &pTypeLib); + if (SUCCEEDED(hrc)) + { + ITypeInfo *pTypeInfo; + hrc = pTypeLib->GetTypeInfoOfGuid(*m_pGUID, &pTypeInfo); + if (SUCCEEDED(hrc)) + { + ITypeInfo2 *pTypeInfo2; + if (SUCCEEDED(pTypeInfo->QueryInterface(__uuidof(ITypeInfo2), (void **)&pTypeInfo2))) + { + pTypeInfo->Release(); + pTypeInfo = pTypeInfo2; + } + m_pTInfo = pTypeInfo; + _pAtlModule->AddTermFunc(Cleanup, (void *)this); + } + pTypeLib->Release(); + } + } + return hrc; + } + HRESULT GetTI(LCID lcid, ITypeInfo **ppTInfo) + { + AssertReturn(ppTInfo, E_POINTER); + HRESULT hrc = S_OK; + if (!m_pTInfo) + hrc = GetTI(lcid); + if (m_pTInfo) + { + m_pTInfo->AddRef(); + hrc = S_OK; + } + *ppTInfo = m_pTInfo; + return hrc; + } + HRESULT FetchTI(LCID lcid) + { + if (!m_pTInfo) + return GetTI(lcid); + return S_OK; + } +}; + +template class CComObjectRootEx +{ +public: + typedef ThreadModel _ThreadModel; + CComObjectRootEx() + { + m_iRef = 0L; + } + ~CComObjectRootEx() + { + } + ULONG InternalAddRef() + { + Assert(m_iRef != -1L); + return ThreadModel::Increment(&m_iRef); + } + ULONG InternalRelease() + { +#ifdef VBOX_STRICT + LONG c = ThreadModel::Decrement(&m_iRef); + AssertMsg(c >= -(LONG_MAX / 2), /* See ~CComObjectNoLock, ~CComObject & ~CComAggObject. */ + ("Release called on object which has been already destroyed!\n")); + return c; +#else + return ThreadModel::Decrement(&m_iRef); +#endif + } + ULONG OuterAddRef() + { + return m_pOuterUnknown->AddRef(); + } + ULONG OuterRelease() + { + return m_pOuterUnknown->Release(); + } + HRESULT OuterQueryInterface(REFIID iid, void **ppvObject) + { + return m_pOuterUnknown->QueryInterface(iid, ppvObject); + } + HRESULT _AtlInitialConstruct() + { + return m_CritSect.Init(); + } + void Lock() + { + m_CritSect.Lock(); + } + void Unlock() + { + m_CritSect.Unlock(); + } + void SetVoid(void *) + { + } + void InternalFinalConstructAddRef() + { + } + void InternalFinalConstructRelease() + { + Assert(m_iRef == 0); + } + HRESULT FinalConstruct() + { + return S_OK; + } + void FinalRelease() + { + } + static HRESULT WINAPI InternalQueryInterface(void *pThis, const _ATL_INTMAP_ENTRY *pEntries, REFIID iid, void **ppvObj) + { + AssertReturn(pThis, E_INVALIDARG); + AssertReturn(pEntries, E_INVALIDARG); + AssertReturn(ppvObj, E_POINTER); + *ppvObj = NULL; + if (iid == IID_IUnknown) + { + // For IUnknown use first interface, must be simple map entry. + Assert(pEntries->pFunc == COM_SIMPLEMAPENTRY); + IUnknown *pObj = (IUnknown *)((INT_PTR)pThis + pEntries->dw); + pObj->AddRef(); + *ppvObj = pObj; + return S_OK; + } + while (pEntries->pFunc) + { + if (iid == *pEntries->piid) + { + if (pEntries->pFunc == COM_SIMPLEMAPENTRY) + { + IUnknown *pObj = (IUnknown *)((INT_PTR)pThis + pEntries->dw); + pObj->AddRef(); + *ppvObj = pObj; + return S_OK; + } + else + return pEntries->pFunc(pThis, iid, ppvObj, pEntries->dw); + } + pEntries++; + } + return E_NOINTERFACE; + } + static HRESULT WINAPI _Delegate(void *pThis, REFIID iid, void **ppvObj, DWORD_PTR dw) + { + AssertPtrReturn(pThis, E_NOINTERFACE); + IUnknown *pObj = *(IUnknown **)((DWORD_PTR)pThis + dw); + // If this assertion fails then the object has a delegation with a NULL + // object pointer, which is highly unusual often means that the pointer + // was not set up correctly. Check the COM interface map of the class + // for bugs with initializing. + AssertPtrReturn(pObj, E_NOINTERFACE); + return pObj->QueryInterface(iid, ppvObj); + } + + union + { + LONG m_iRef; + IUnknown *m_pOuterUnknown; + }; +private: + typename ThreadModel::AutoDeleteCriticalSection m_CritSect; +}; + +template class CComObject : public Base +{ +public: + CComObject(void * = NULL) throw() + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + _pAtlModule->Lock(); + } + virtual ~CComObject() throw() + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + // Catch refcount screwups by setting refcount to -(LONG_MAX/2). + m_iRef = -(LONG_MAX/2); + FinalRelease(); + _pAtlModule->Unlock(); + } + STDMETHOD_(ULONG, AddRef)() + { + // If you get errors about undefined InternalAddRef then Base does not + // derive from CComObjectRootEx. + return InternalAddRef(); + } + STDMETHOD_(ULONG, Release)() + { + // If you get errors about undefined InternalRelease then Base does not + // derive from CComObjectRootEx. + ULONG l = InternalRelease(); + if (l == 0) + delete this; + return l; + } + STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw() + { + // If you get errors about undefined _InternalQueryInterface then + // double check BEGIN_COM_MAP in the class definition. + return _InternalQueryInterface(iid, ppvObj); + } + + static HRESULT WINAPI CreateInstance(CComObject **pp) throw() + { + AssertReturn(pp, E_POINTER); + *pp = NULL; + + HRESULT hrc = E_OUTOFMEMORY; + CComObject *p = NULL; + try + { + p = new CComObject(); + } + catch (std::bad_alloc &) + { + p = NULL; + } + if (p) + { + p->InternalFinalConstructAddRef(); + try + { + hrc = p->_AtlInitialConstruct(); + if (SUCCEEDED(hrc)) + hrc = p->FinalConstruct(); + } + catch (std::bad_alloc &) + { + hrc = E_OUTOFMEMORY; + } + p->InternalFinalConstructRelease(); + if (FAILED(hrc)) + { + delete p; + p = NULL; + } + } + *pp = p; + return hrc; + } +}; + +template class ATL_NO_VTABLE IDispatchImpl : public T +{ +public: + // IDispatch + STDMETHOD(GetTypeInfoCount)(UINT *pcTInfo) + { + if (!pcTInfo) + return E_POINTER; + *pcTInfo = 1; + return S_OK; + } + STDMETHOD(GetTypeInfo)(UINT cTInfo, LCID lcid, ITypeInfo **ppTInfo) + { + return tih.GetTypeInfo(cTInfo, lcid, ppTInfo); + } + STDMETHOD(GetIDsOfNames)(REFIID riid, LPOLESTR *pwszNames, UINT cNames, LCID lcid, DISPID *pDispID) + { + return tih.GetIDsOfNames(riid, pwszNames, cNames, lcid, pDispID); + } + STDMETHOD(Invoke)(DISPID DispID, REFIID riid, LCID lcid, WORD iFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr) + { + return tih.Invoke((IDispatch *)this, DispID, riid, lcid, iFlags, pDispParams, pVarResult, pExcepInfo, puArgErr); + } +protected: + static CComTypeInfoHolder tih; + static HRESULT GetTI(LCID lcid, ITypeInfo **ppTInfo) + { + return tih.GetTI(lcid, ppTInfo); + } +}; + +template CComTypeInfoHolder IDispatchImpl::tih = { piid, pLibID, iMajor, iMinor, NULL }; + + +template class CComContainedObject : public Base +{ +public: + CComContainedObject(void *pv) + { + m_pOuterUnknown = (IUnknown *)pv; + } + + STDMETHOD_(ULONG, AddRef)() throw() + { + return OuterAddRef(); + } + STDMETHOD_(ULONG, Release)() throw() + { + return OuterRelease(); + } + STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) throw() + { + return OuterQueryInterface(iid, ppvObj); + } +}; + +template class CComAggObject : + public IUnknown, + public CComObjectRootEx +{ +public: + CComAggObject(void *pv) : + m_Aggregated(pv) + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + _pAtlModule->Lock(); + } + virtual ~CComAggObject() + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + // Catch refcount screwups by setting refcount to -(LONG_MAX/2). + m_iRef = -(LONG_MAX/2); + FinalRelease(); + _pAtlModule->Unlock(); + } + HRESULT _AtlInitialConstruct() + { + HRESULT hrc = m_Aggregated._AtlInitialConstruct(); + if (SUCCEEDED(hrc)) + { + hrc = CComObjectRootEx::_AtlInitialConstruct(); + } + return hrc; + } + HRESULT FinalConstruct() + { + CComObjectRootEx::FinalConstruct(); + return m_Aggregated.FinalConstruct(); + } + void FinalRelease() + { + CComObjectRootEx::FinalRelease(); + m_Aggregated.FinalRelease(); + } + + STDMETHOD_(ULONG, AddRef)() + { + return InternalAddRef(); + } + STDMETHOD_(ULONG, Release)() + { + ULONG l = InternalRelease(); + if (l == 0) + delete this; + return l; + } + STDMETHOD(QueryInterface)(REFIID iid, void **ppvObj) + { + AssertReturn(ppvObj, E_POINTER); + *ppvObj = NULL; + + HRESULT hrc = S_OK; + if (iid == __uuidof(IUnknown)) + { + *ppvObj = (void *)(IUnknown *)this; + AddRef(); + } + else + hrc = m_Aggregated._InternalQueryInterface(iid, ppvObj); + return hrc; + } + static HRESULT WINAPI CreateInstance(LPUNKNOWN pUnkOuter, CComAggObject **pp) + { + AssertReturn(pp, E_POINTER); + *pp = NULL; + + HRESULT hrc = E_OUTOFMEMORY; + CComAggObject *p = new(std::nothrow) CComAggObject(pUnkOuter); + if (p) + { + p->SetVoid(NULL); + p->InternalFinalConstructAddRef(); + hrc = p->_AtlInitialConstruct(); + if (SUCCEEDED(hrc)) + hrc = p->FinalConstruct(); + p->InternalFinalConstructRelease(); + if (FAILED(hrc)) + delete p; + else + *pp = p; + } + return hrc; + } + + CComContainedObject m_Aggregated; +}; + +class CComClassFactory: + public IClassFactory, + public CComObjectRootEx +{ +public: + BEGIN_COM_MAP(CComClassFactory) + COM_INTERFACE_ENTRY(IClassFactory) + END_COM_MAP() + + virtual ~CComClassFactory() + { + } + + // IClassFactory + STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **ppvObj) + { + Assert(m_pfnCreateInstance); + HRESULT hrc = E_POINTER; + if (ppvObj) + { + *ppvObj = NULL; + if (pUnkOuter && riid != __uuidof(IUnknown)) + { + AssertMsgFailed(("CComClassFactory: cannot create an aggregated object other than IUnknown\n")); + hrc = CLASS_E_NOAGGREGATION; + } + else + hrc = m_pfnCreateInstance(pUnkOuter, riid, ppvObj); + } + return hrc; + } + + STDMETHOD(LockServer)(BOOL fLock) + { + AssertMsg(_pAtlModule, ("ATL: referring to ATL module without having one declared in this linking namespace\n")); + if (fLock) + _pAtlModule->Lock(); + else + _pAtlModule->Unlock(); + return S_OK; + } + + // Set creator for use by the factory. + void SetVoid(void *pv) + { + m_pfnCreateInstance = (PFNCREATEINSTANCE)pv; + } + + PFNCREATEINSTANCE m_pfnCreateInstance; +}; + +template class CComClassFactorySingleton : public CComClassFactory +{ +public: + CComClassFactorySingleton() : + m_hrc(S_OK), + m_pObj(NULL) + { + } + virtual ~CComClassFactorySingleton() + { + if (m_pObj) + m_pObj->Release(); + } + // IClassFactory + STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void **pvObj) + { + HRESULT hrc = E_POINTER; + if (ppvObj) + { + *ppvObj = NULL; + // Singleton factories do not support aggregation. + AssertReturn(!pUnkOuter, CLASS_E_NOAGGREGATION); + + // Test if singleton is already created. Do it outside the lock, + // relying on atomic checks. Remember the inherent race! + if (SUCCEEDED(m_hrc) && !m_pObj) + { + Lock(); + // Make sure that the module is in use, otherwise the + // module can terminate while we're creating a new + // instance, which leads to strange errors. + LockServer(true); + __try + { + // Repeat above test to avoid races when multiple threads + // want to create a singleton simultaneously. + if (SUCCEEDED(m_hrc) && !m_pObj) + { + CComObjectCached *p; + m_hrc = CComObjectCached::CreateInstance(&p); + if (SUCCEEDED(m_hrc)) + { + m_hrc = p->QueryInterface(IID_IUnknown, (void **)&m_pObj); + if (FAILED(m_hrc)) + { + delete p; + } + } + } + } + __finally + { + Unlock(); + LockServer(false); + } + } + if (SUCCEEDED(m_hrc)) + { + hrc = m_pObj->QueryInterface(riid, ppvObj); + } + else + { + hrc = m_hrc; + } + } + return hrc; + } + HRESULT m_hrc; + IUnknown *m_pObj; +}; + + +template class CComCoClass +{ +public: + DECLARE_CLASSFACTORY() + DECLARE_AGGREGATABLE(T) + static const CLSID& WINAPI GetObjectCLSID() + { + return *pClsID; + } + template + static HRESULT CreateInstance(Q **pp) + { + return T::_CreatorClass::CreateInstance(NULL, __uuidof(Q), (void **)pp); + } +}; + +} /* namespace ATL */ + +#endif /* !VBOX_INCLUDED_com_microatl_h */ + diff --git a/include/VBox/com/mtlist.h b/include/VBox/com/mtlist.h new file mode 100644 index 00000000..0ff79bb1 --- /dev/null +++ b/include/VBox/com/mtlist.h @@ -0,0 +1,220 @@ +/* $Id: mtlist.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - Thread-safe list classes declaration. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_mtlist_h +#define VBOX_INCLUDED_com_mtlist_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +/** @defgroup grp_com_mtlist Thread-safe List Classes + * @ingroup grp_com + * @{ + */ + +/** + * Specialized thread-safe list class for using with com::ComPtr + * + * @note: This is necessary cause ComPtr has a size of 8. + */ +template +class RTCMTList< ComPtr >: public RTCListBase< ComPtr, ComPtr*, true> +{ + /* Traits */ + typedef ComPtr T; + typedef T *ITYPE; + static const bool MT = true; + typedef RTCListBase BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCMTList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized thread-safe list class for using with com::ComObjPtr + * + * @note: This is necessary cause ComObjPtr has a size of 8. + */ +template +class RTCMTList< ComObjPtr >: public RTCListBase< ComObjPtr, ComObjPtr*, true> +{ + /* Traits */ + typedef ComObjPtr T; + typedef T *ITYPE; + static const bool MT = true; + typedef RTCListBase BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCMTList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** + * Specialized thread-safe list class for using with com::Utf8Str. + * + * The class offers methods for importing com::SafeArray's of com::Bstr's. + */ +template <> +class RTCMTList: public RTCListBase +{ + /* Traits */ + typedef com::Utf8Str T; + typedef T *ITYPE; + static const bool MT = true; + typedef RTCListBase BASE; + +public: + /** + * Creates a new list. + * + * This preallocates @a cCapacity elements within the list. + * + * @param cCapacity The initial capacity the list has. + * @throws std::bad_alloc + */ + RTCMTList(size_t cCapacity = BASE::kDefaultCapacity) + : BASE(cCapacity) {} + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. The com::Bstr's are silently converted to + * com::Utf8Str's. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCMTList(ComSafeArrayIn(IN_BSTR, other)) + { + com::SafeArray sfaOther(ComSafeArrayInArg(other)); + size_t const cElementsOther = sfaOther.size(); + resizeArray(cElementsOther); + m_cElements = cElementsOther; + for (size_t i = 0; i < cElementsOther; ++i) + RTCListHelper::set(m_pArray, i, T(sfaOther[i])); + } + + /** + * Creates a copy of another list. + * + * The other list will be fully copied and the capacity will be the same as + * the size of the other list. The com::Bstr's are silently converted to + * com::Utf8Str's. + * + * @param other The list to copy. + * @throws std::bad_alloc + */ + RTCMTList(const com::SafeArray &other) + : BASE(other.size()) + { + for (size_t i = 0; i < m_cElements; ++i) + RTCListHelper::set(m_pArray, i, T(other[i])); + } + + /** + * Copy the items of the other list into this list. All previous items of + * this list are deleted. + * + * @param other The list to copy. + * @return a reference to this list. + * @throws std::bad_alloc + */ + RTCListBase &operator=(const com::SafeArray &other) + { + m_guard.enterWrite(); + /* Values cleanup */ + RTCListHelper::eraseRange(m_pArray, 0, m_cElements); + /* Copy */ + if (other.size() != m_cCapacity) + resizeArrayNoErase(other.size()); + m_cElements = other.size(); + for (size_t i = 0; i < other.size(); ++i) + RTCListHelper::set(m_pArray, i, T(other[i])); + m_guard.leaveWrite(); + + return *this; + } + + /** + * Implicit conversion to a RTCString list. + * + * This allows the usage of the RTCString::join method with this list type. + * + * @return a converted const reference to this list. + */ + operator const RTCMTList&() + { + return *reinterpret_cast *>(this); + } + + /* Define our own new and delete. */ + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +}; + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_mtlist_h */ + diff --git a/include/VBox/com/ptr.h b/include/VBox/com/ptr.h new file mode 100644 index 00000000..613d2d08 --- /dev/null +++ b/include/VBox/com/ptr.h @@ -0,0 +1,569 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - Smart COM pointer classes declaration. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_ptr_h +#define VBOX_INCLUDED_com_ptr_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Make sure all the stdint.h macros are included - must come first! */ +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#ifdef VBOX_WITH_XPCOM +# include +#endif /* VBOX_WITH_XPCOM */ + +#include +#include /* For bad_alloc. */ + + +/** @defgroup grp_com_ptr Smart COM Pointer Classes + * @ingroup grp_com + * @{ + */ + +#ifdef VBOX_WITH_XPCOM + +namespace com +{ +// declare a couple of XPCOM helper methods (defined in glue/com.cpp) +// so we don't have to include a ton of XPCOM implementation headers here +HRESULT GlueCreateObjectOnServer(const CLSID &clsid, + const char *serverName, + const nsIID &id, + void **ppobj); +HRESULT GlueCreateInstance(const CLSID &clsid, + const nsIID &id, + void **ppobj); +} + +#endif // VBOX_WITH_XPCOM + +/** + * COM autopointer class which takes care of all required reference counting. + * + * This automatically calls the required basic COM methods on COM pointers + * given to it: + * + * -- AddRef() gets called automatically whenever a new COM pointer is assigned + * to the ComPtr instance (either in the copy constructor or by assignment); + * + * -- Release() gets called automatically by the destructor and when an existing + * object gets released in assignment; + * + * -- QueryInterface() gets called automatically when COM pointers get converted + * from one interface to another. + * + * Example usage: + * + * @code + * + * { + * ComPtr pMachine = findMachine("blah"); // calls AddRef() + * ComPtr pUnknown = pMachine; // calls QueryInterface() + * } # ComPtr destructor of both instances calls Release() + * + * @endcode + */ +template +class ComPtr +{ +public: + + /** + * Default constructor, sets up a NULL pointer. + */ + ComPtr() + : m_p(NULL) + { } + + /** + * Destructor. Calls Release() on the contained COM object. + */ + ~ComPtr() + { + cleanup(); + } + + /** + * Copy constructor from another ComPtr of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already. + */ + template + ComPtr(const ComPtr &that) + { + m_p = NULL; + if (!that.isNull()) + that->QueryInterface(COM_IIDOF(T), (void **)&m_p); + } + + /** + * Specialization: copy constructor from another ComPtr. Calls AddRef(). + */ + ComPtr(const ComPtr &that) + { + copyFrom(that.m_p); + } + + /** + * Copy constructor from another interface pointer of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already. + */ + template + ComPtr(T2 *p) + { + m_p = NULL; + if (p) + p->QueryInterface(COM_IIDOF(T), (void **)&m_p); + } + + /** + * Specialization: copy constructor from a plain T * pointer. Calls AddRef(). + */ + ComPtr(T *that_p) + { + copyFrom(that_p); + } + + /** + * Assignment from another ComPtr of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already. + */ + template + ComPtr& operator=(const ComPtr &that) + { + return operator=((T2 *)that); + } + + /** + * Specialization of the previous: assignment from another ComPtr. + * Calls Release() on the previous member pointer, if any, and AddRef() on the new one. + */ + ComPtr& operator=(const ComPtr &that) + { + return operator=((T *)that); + } + + /** + * Assignment from another interface pointer of any interface. + * + * This calls QueryInterface(T) and can result in a NULL pointer if the input + * pointer p does not support the ComPtr interface T. + * + * Does not call AddRef explicitly because if QueryInterface succeeded, then + * the refcount will have been increased by one already. + */ + template + ComPtr& operator=(T2 *p) + { + cleanup(); + if (p) + p->QueryInterface(COM_IIDOF(T), (void **)&m_p); + return *this; + } + + /** + * Specialization of the previous: assignment from a plain T * pointer. + * Calls Release() on the previous member pointer, if any, and AddRef() on the new one. + */ + ComPtr& operator=(T *p) + { + cleanup(); + copyFrom(p); + return *this; + } + + /** + * Resets the ComPtr to NULL. Works like a NULL assignment except it avoids the templates. + */ + void setNull() + { + cleanup(); + } + + /** + * Returns true if the pointer is NULL. + */ + bool isNull() const + { + return (m_p == NULL); + } + + /** + * Returns true if the pointer is not NULL. + */ + bool isNotNull() const + { + return (m_p != NULL); + } + + bool operator<(T *p) const + { + return m_p < p; + } + + /** + * Conversion operator, most often used to pass ComPtr instances as + * parameters to COM method calls. + */ + operator T *() const + { + return m_p; + } + + /** + * Dereferences the instance (redirects the -> operator to the managed + * pointer). + */ + T *operator->() const + { + return m_p; + } + + /** + * Special method which allows using a ComPtr as an output argument of a COM method. + * The ComPtr will then accept the method's interface pointer without calling AddRef() + * itself, since by COM convention this must has been done by the method which created + * the object that is being accepted. + * + * The ComPtr destructor will then still invoke Release() so that the returned object + * can get cleaned up properly. + */ + T **asOutParam() + { + cleanup(); + return &m_p; + } + + /** + * Converts the contained pointer to a different interface + * by calling QueryInterface() on it. + * @param pp + * @return + */ + template + HRESULT queryInterfaceTo(T2 **pp) const + { + if (pp) + { + if (m_p) + return m_p->QueryInterface(COM_IIDOF(T2), (void **)pp); + *pp = NULL; + return S_OK; + } + return E_INVALIDARG; + } + + /** + * Equality test operator. By COM definition, two COM objects are considered + * equal if their IUnknown interface pointers are equal. + */ + template + bool operator==(T2 *p) + { + IUnknown *p1 = NULL; + bool fNeedsRelease1 = false; + if (m_p) + fNeedsRelease1 = (SUCCEEDED(m_p->QueryInterface(COM_IIDOF(IUnknown), (void **)&p1))); + + IUnknown *p2 = NULL; + bool fNeedsRelease2 = false; + if (p) + fNeedsRelease2 = (SUCCEEDED(p->QueryInterface(COM_IIDOF(IUnknown), (void **)&p2))); + + bool f = p1 == p2; + if (fNeedsRelease1) + p1->Release(); + if (fNeedsRelease2) + p2->Release(); + return f; + } + + /** + * Creates an in-process object of the given class ID and starts to + * manage a reference to the created object in case of success. + */ + HRESULT createInprocObject(const CLSID &clsid) + { + HRESULT rc; + T *obj = NULL; +#ifndef VBOX_WITH_XPCOM + rc = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, COM_IIDOF(T), + (void **)&obj); +#else /* VBOX_WITH_XPCOM */ + using namespace com; + rc = GlueCreateInstance(clsid, NS_GET_IID(T), (void **)&obj); +#endif /* VBOX_WITH_XPCOM */ + *this = obj; + if (SUCCEEDED(rc)) + obj->Release(); + return rc; + } + + /** + * Creates a local (out-of-process) object of the given class ID and starts + * to manage a reference to the created object in case of success. + * + * Note: In XPCOM, the out-of-process functionality is currently emulated + * through in-process wrapper objects (that start a dedicated process and + * redirect all object requests to that process). For this reason, this + * method is fully equivalent to #createInprocObject() for now. + */ + HRESULT createLocalObject(const CLSID &clsid) + { +#ifndef VBOX_WITH_XPCOM + HRESULT rc; + T *obj = NULL; + rc = CoCreateInstance(clsid, NULL, CLSCTX_LOCAL_SERVER, COM_IIDOF(T), + (void **)&obj); + *this = obj; + if (SUCCEEDED(rc)) + obj->Release(); + return rc; +#else /* VBOX_WITH_XPCOM */ + return createInprocObject(clsid); +#endif /* VBOX_WITH_XPCOM */ + } + +#ifdef VBOX_WITH_XPCOM + /** + * Creates an object of the given class ID on the specified server and + * starts to manage a reference to the created object in case of success. + * + * @param serverName Name of the server to create an object within. + */ + HRESULT createObjectOnServer(const CLSID &clsid, const char *serverName) + { + T *obj = NULL; + HRESULT rc = GlueCreateObjectOnServer(clsid, serverName, NS_GET_IID(T), (void **)&obj); + *this = obj; + if (SUCCEEDED(rc)) + obj->Release(); + return rc; + } +#endif + +protected: + void copyFrom(T *p) + { + m_p = p; + if (m_p) + m_p->AddRef(); + } + + void cleanup() + { + if (m_p) + { + m_p->Release(); + m_p = NULL; + } + } + +public: + // Do NOT access this member unless you really know what you're doing! + T *m_p; +}; + +/** + * ComObjPtr is a more specialized variant of ComPtr designed to be used for implementation + * objects. For example, use ComPtr for a client pointer that calls the interface + * but ComObjPtr for a pointer to an implementation object. + * + * The methods behave the same except that ComObjPtr has the additional createObject() + * method which allows for instantiating a new implementation object. + * + * Note: To convert a ComObjPtr to a ComObj you have + * to query the interface. See the following example code for the IProgress + * interface: + * + * @code + * + * { + * ComObjPtr pProgress; // create the server side object + * pProgress.createObject(); // ... + * pProgress->init(...); // ... + * ComPtr pProgress2; // create an interface pointer + * pProgress.queryInterfaceTo(pProgress2.asOutParam()); // transfer the interface + * } + * + * @endcode + */ +template +class ComObjPtr : public ComPtr +{ +public: + + ComObjPtr() + : ComPtr() + {} + + ComObjPtr(const ComObjPtr &that) + : ComPtr(that) + {} + + ComObjPtr(T *that_p) + : ComPtr(that_p) + {} + + ComObjPtr& operator=(const ComObjPtr &that) + { + ComPtr::operator=(that); + return *this; + } + + ComObjPtr& operator=(T *that_p) + { + ComPtr::operator=(that_p); + return *this; + } + + /** + * Creates a new server-side object of the given component class and + * immediately starts to manage a pointer to the created object (the + * previous pointer, if any, is of course released when appropriate). + * + * @note Win32: when VBOX_COM_OUTOFPROC_MODULE is defined, the created + * object doesn't increase the lock count of the server module, as it + * does otherwise. + * + * @note In order to make it easier to use, this method does _not_ throw + * bad_alloc, but instead returns E_OUTOFMEMORY. + */ + HRESULT createObject() + { + HRESULT hrc; +#ifndef VBOX_WITH_XPCOM +# ifdef VBOX_COM_OUTOFPROC_MODULE + ATL::CComObjectNoLock *obj = NULL; + try + { + obj = new ATL::CComObjectNoLock(); + } + catch (std::bad_alloc &) + { + obj = NULL; + } + if (obj) + { + obj->InternalFinalConstructAddRef(); + try + { + hrc = obj->FinalConstruct(); + } + catch (std::bad_alloc &) + { + hrc = E_OUTOFMEMORY; + } + obj->InternalFinalConstructRelease(); + if (FAILED(hrc)) + { + delete obj; + obj = NULL; + } + } + else + hrc = E_OUTOFMEMORY; +# else + ATL::CComObject *obj = NULL; + hrc = ATL::CComObject::CreateInstance(&obj); +# endif +#else /* VBOX_WITH_XPCOM */ + ATL::CComObject *obj; +# ifndef RT_EXCEPTIONS_ENABLED + obj = new ATL::CComObject(); +# else + try + { + obj = new ATL::CComObject(); + } + catch (std::bad_alloc &) + { + obj = NULL; + } +# endif + if (obj) + { +# ifndef RT_EXCEPTIONS_ENABLED + hrc = obj->FinalConstruct(); +# else + try + { + hrc = obj->FinalConstruct(); + } + catch (std::bad_alloc &) + { + hrc = E_OUTOFMEMORY; + } +# endif + if (FAILED(hrc)) + { + delete obj; + obj = NULL; + } + } + else + hrc = E_OUTOFMEMORY; +#endif /* VBOX_WITH_XPCOM */ + *this = obj; + return hrc; + } +}; + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_ptr_h */ + diff --git a/include/VBox/com/string.h b/include/VBox/com/string.h new file mode 100644 index 00000000..62d5abc1 --- /dev/null +++ b/include/VBox/com/string.h @@ -0,0 +1,1494 @@ +/* $Id: string.h $ */ +/** @file + * MS COM / XPCOM Abstraction Layer - Smart string classes declaration. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_string_h +#define VBOX_INCLUDED_com_string_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Make sure all the stdint.h macros are included - must come first! */ +#ifndef __STDC_LIMIT_MACROS +# define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +# define __STDC_CONSTANT_MACROS +#endif + +#if defined(VBOX_WITH_XPCOM) +# include +#endif + +#include "VBox/com/defs.h" +#include "VBox/com/assert.h" + +#include +#include +#include + + +/** @defgroup grp_com_str Smart String Classes + * @ingroup grp_com + * @{ + */ + +namespace com +{ + +class Utf8Str; + +// global constant in glue/string.cpp that represents an empty BSTR +extern const BSTR g_bstrEmpty; + +/** + * String class used universally in Main for COM-style Utf-16 strings. + * + * Unfortunately COM on Windows uses UTF-16 everywhere, requiring conversions + * back and forth since most of VirtualBox and our libraries use UTF-8. + * + * To make things more obscure, on Windows, a COM-style BSTR is not just a + * pointer to a null-terminated wide character array, but the four bytes (32 + * bits) BEFORE the memory that the pointer points to are a length DWORD. One + * must therefore avoid pointer arithmetic and always use SysAllocString and + * the like to deal with BSTR pointers, which manage that DWORD correctly. + * + * For platforms other than Windows, we provide our own versions of the Sys* + * functions in Main/xpcom/helpers.cpp which do NOT use length prefixes though + * to be compatible with how XPCOM allocates string parameters to public + * functions. + * + * The Bstr class hides all this handling behind a std::string-like interface + * and also provides automatic conversions to RTCString and Utf8Str instances. + * + * The one advantage of using the SysString* routines is that this makes it + * possible to use it as a type of member variables of COM/XPCOM components and + * pass their values to callers through component methods' output parameters + * using the #cloneTo() operation. Also, the class can adopt (take ownership + * of) string buffers returned in output parameters of COM methods using the + * #asOutParam() operation and correctly free them afterwards. + * + * Starting with VirtualBox 3.2, like Utf8Str, Bstr no longer differentiates + * between NULL strings and empty strings. In other words, Bstr("") and + * Bstr(NULL) behave the same. In both cases, Bstr allocates no memory, + * reports a zero length and zero allocated bytes for both, and returns an + * empty C wide string from raw(). + * + * @note All Bstr methods ASSUMES valid UTF-16 or UTF-8 input strings. + * The VirtualBox policy in this regard is to validate strings coming + * from external sources before passing them to Bstr or Utf8Str. + */ +class Bstr +{ +public: + + Bstr() + : m_bstr(NULL) + { } + + Bstr(const Bstr &that) + { + copyFrom((const OLECHAR *)that.m_bstr); + } + + Bstr(CBSTR that) + { + copyFrom((const OLECHAR *)that); + } + +#if defined(VBOX_WITH_XPCOM) + Bstr(const wchar_t *that) + { + AssertCompile(sizeof(wchar_t) == sizeof(OLECHAR)); + copyFrom((const OLECHAR *)that); + } +#endif + + Bstr(const RTCString &that) + { + copyFrom(that.c_str()); + } + + Bstr(const char *that) + { + copyFrom(that); + } + + Bstr(const char *a_pThat, size_t a_cchMax) + { + copyFromN(a_pThat, a_cchMax); + } + + ~Bstr() + { + setNull(); + } + + Bstr &operator=(const Bstr &that) + { + cleanupAndCopyFrom((const OLECHAR *)that.m_bstr); + return *this; + } + + Bstr &operator=(CBSTR that) + { + cleanupAndCopyFrom((const OLECHAR *)that); + return *this; + } + +#if defined(VBOX_WITH_XPCOM) + Bstr &operator=(const wchar_t *that) + { + cleanupAndCopyFrom((const OLECHAR *)that); + return *this; + } +#endif + + Bstr &setNull() + { + cleanup(); + return *this; + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_rSrcStr The source string + */ + HRESULT assignEx(const Bstr &a_rSrcStr) RT_NOEXCEPT + { + return cleanupAndCopyFromEx((const OLECHAR *)a_rSrcStr.m_bstr); + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_pSrcStr The source string + */ + HRESULT assignEx(CBSTR a_pSrcStr) RT_NOEXCEPT + { + return cleanupAndCopyFromEx((const OLECHAR *)a_pSrcStr); + } + + /** + * Assign the value of a RTCString/Utf8Str string, no exceptions. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_rSrcStr The source string + */ + HRESULT assignEx(RTCString const &a_rSrcStr) RT_NOEXCEPT + { + return cleanupAndCopyFromNoThrow(a_rSrcStr.c_str(), a_rSrcStr.length()); + } + + /** + * Assign the value of a RTCString/Utf8Str substring, no exceptions. + * + * @returns S_OK, E_OUTOFMEMORY or E_INVALIDARG. + * @param a_rSrcStr The source string + * @param a_offSrc The character (byte) offset of the substring. + * @param a_cchSrc The number of characters (bytes) to copy from the source + * string. + */ + HRESULT assignEx(RTCString const &a_rSrcStr, size_t a_offSrc, size_t a_cchSrc) RT_NOEXCEPT + { + size_t const cchTmp = a_rSrcStr.length(); + if ( a_offSrc + a_cchSrc < cchTmp + && a_offSrc < cchTmp) + return cleanupAndCopyFromNoThrow(a_rSrcStr.c_str() + a_offSrc, a_cchSrc); + return E_INVALIDARG; + } + + /** + * Assign the value of a zero terminated UTF-8 string, no exceptions. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_pszSrcStr The source string. + */ + HRESULT assignEx(const char *a_pszSrcStr) RT_NOEXCEPT + { + return cleanupAndCopyFromNoThrow(a_pszSrcStr, RTSTR_MAX); + } + + /** + * Assign the value of a UTF-8 substring, no exceptions. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_pszSrcStr The source string. + * @param a_cchSrc The number of characters (bytes) to copy from the source + * string. + */ + HRESULT assignEx(const char *a_pszSrcStr, size_t a_cchSrc) RT_NOEXCEPT + { + return cleanupAndCopyFromNoThrow(a_pszSrcStr, a_cchSrc); + } + +#ifdef _MSC_VER +# if _MSC_VER >= 1400 + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +# endif +#else + RTMEMEF_NEW_AND_DELETE_OPERATORS(); +#endif + + /** Case sensitivity selector. */ + enum CaseSensitivity + { + CaseSensitive, + CaseInsensitive + }; + + /** + * Compares the member string to str. + * @param str + * @param cs Whether comparison should be case-sensitive. + * @return + */ + int compare(CBSTR str, CaseSensitivity cs = CaseSensitive) const + { + if (cs == CaseSensitive) + return ::RTUtf16Cmp((PRTUTF16)m_bstr, (PRTUTF16)str); + return ::RTUtf16LocaleICmp((PRTUTF16)m_bstr, (PRTUTF16)str); + } + + int compare(BSTR str, CaseSensitivity cs = CaseSensitive) const + { + return compare((CBSTR)str, cs); + } + + int compare(const Bstr &that, CaseSensitivity cs = CaseSensitive) const + { + return compare(that.m_bstr, cs); + } + + bool operator==(const Bstr &that) const { return !compare(that.m_bstr); } + bool operator==(CBSTR that) const { return !compare(that); } + bool operator==(BSTR that) const { return !compare(that); } + bool operator!=(const Bstr &that) const { return !!compare(that.m_bstr); } + bool operator!=(CBSTR that) const { return !!compare(that); } + bool operator!=(BSTR that) const { return !!compare(that); } + bool operator<(const Bstr &that) const { return compare(that.m_bstr) < 0; } + bool operator<(CBSTR that) const { return compare(that) < 0; } + bool operator<(BSTR that) const { return compare(that) < 0; } + bool operator<=(const Bstr &that) const { return compare(that.m_bstr) <= 0; } + bool operator<=(CBSTR that) const { return compare(that) <= 0; } + bool operator<=(BSTR that) const { return compare(that) <= 0; } + bool operator>(const Bstr &that) const { return compare(that.m_bstr) > 0; } + bool operator>(CBSTR that) const { return compare(that) > 0; } + bool operator>(BSTR that) const { return compare(that) > 0; } + bool operator>=(const Bstr &that) const { return compare(that.m_bstr) >= 0; } + bool operator>=(CBSTR that) const { return compare(that) >= 0; } + bool operator>=(BSTR that) const { return compare(that) >= 0; } + + /** + * Compares this string to an UTF-8 C style string. + * + * @retval 0 if equal + * @retval -1 if this string is smaller than the UTF-8 one. + * @retval 1 if the UTF-8 string is smaller than this. + * + * @param a_pszRight The string to compare with. + * @param a_enmCase Whether comparison should be case-sensitive. + */ + int compareUtf8(const char *a_pszRight, CaseSensitivity a_enmCase = CaseSensitive) const; + + /** Java style compare method. + * @returns true if @a a_pszRight equals this string. + * @param a_pszRight The (UTF-8) string to compare with. */ + bool equals(const char *a_pszRight) const { return compareUtf8(a_pszRight, CaseSensitive) == 0; } + + /** Java style case-insensitive compare method. + * @returns true if @a a_pszRight equals this string. + * @param a_pszRight The (UTF-8) string to compare with. */ + bool equalsIgnoreCase(const char *a_pszRight) const { return compareUtf8(a_pszRight, CaseInsensitive) == 0; } + + /** Java style compare method. + * @returns true if @a a_rThat equals this string. + * @param a_rThat The other Bstr instance to compare with. */ + bool equals(const Bstr &a_rThat) const { return compare(a_rThat.m_bstr, CaseSensitive) == 0; } + /** Java style case-insensitive compare method. + * @returns true if @a a_rThat equals this string. + * @param a_rThat The other Bstr instance to compare with. */ + bool equalsIgnoreCase(const Bstr &a_rThat) const { return compare(a_rThat.m_bstr, CaseInsensitive) == 0; } + + /** Java style compare method. + * @returns true if @a a_pThat equals this string. + * @param a_pThat The native const BSTR to compare with. */ + bool equals(CBSTR a_pThat) const { return compare(a_pThat, CaseSensitive) == 0; } + /** Java style case-insensitive compare method. + * @returns true if @a a_pThat equals this string. + * @param a_pThat The native const BSTR to compare with. */ + bool equalsIgnoreCase(CBSTR a_pThat) const { return compare(a_pThat, CaseInsensitive) == 0; } + + /** Java style compare method. + * @returns true if @a a_pThat equals this string. + * @param a_pThat The native BSTR to compare with. */ + bool equals(BSTR a_pThat) const { return compare(a_pThat, CaseSensitive) == 0; } + /** Java style case-insensitive compare method. + * @returns true if @a a_pThat equals this string. + * @param a_pThat The native BSTR to compare with. */ + bool equalsIgnoreCase(BSTR a_pThat) const { return compare(a_pThat, CaseInsensitive) == 0; } + + /** + * Checks if the string starts with @a a_rStart. + */ + bool startsWith(Bstr const &a_rStart) const; + /** + * Checks if the string starts with @a a_rStart. + */ + bool startsWith(RTCString const &a_rStart) const; + /** + * Checks if the string starts with @a a_pszStart. + */ + bool startsWith(const char *a_pszStart) const; + + /** + * Returns true if the member string has no length. + * This is true for instances created from both NULL and "" input strings. + * + * @note Always use this method to check if an instance is empty. Do not + * use length() because that may need to run through the entire string + * (Bstr does not cache string lengths). + */ + bool isEmpty() const { return m_bstr == NULL || *m_bstr == 0; } + + /** + * Returns true if the member string has a length of one or more. + * + * @returns true if not empty, false if empty (NULL or ""). + */ + bool isNotEmpty() const { return m_bstr != NULL && *m_bstr != 0; } + + size_t length() const { return isEmpty() ? 0 : ::RTUtf16Len((PRTUTF16)m_bstr); } + + /** + * Assigns the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + Bstr &printf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Assigns the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT printfNoThrow(const char *pszFormat, ...) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Assigns the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + Bstr &printfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Assigns the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT printfVNoThrow(const char *pszFormat, va_list va) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 0); + + /** @name Append methods and operators + * @{ */ + + /** + * Appends the string @a that to @a rThat. + * + * @param rThat The string to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(const Bstr &rThat); + + /** + * Appends the string @a that to @a rThat. + * + * @param rThat The string to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(const Bstr &rThat) RT_NOEXCEPT; + + /** + * Appends the UTF-8 string @a that to @a rThat. + * + * @param rThat The string to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(const RTCString &rThat); + + /** + * Appends the UTF-8 string @a that to @a rThat. + * + * @param rThat The string to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(const RTCString &rThat) RT_NOEXCEPT; + + /** + * Appends the UTF-16 string @a pszSrc to @a this. + * + * @param pwszSrc The C-style UTF-16 string to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(CBSTR pwszSrc); + + /** + * Appends the UTF-16 string @a pszSrc to @a this. + * + * @param pwszSrc The C-style UTF-16 string to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(CBSTR pwszSrc) RT_NOEXCEPT; + + /** + * Appends the UTF-8 string @a pszSrc to @a this. + * + * @param pszSrc The C-style string to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(const char *pszSrc); + + /** + * Appends the UTF-8 string @a pszSrc to @a this. + * + * @param pszSrc The C-style string to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(const char *pszSrc) RT_NOEXCEPT; + + /** + * Appends the a substring from @a rThat to @a this. + * + * @param rThat The string to append a substring from. + * @param offStart The start of the substring to append (UTF-16 + * offset, not codepoint). + * @param cwcMax The maximum number of UTF-16 units to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(const Bstr &rThat, size_t offStart, size_t cwcMax = RTSTR_MAX); + + /** + * Appends the a substring from @a rThat to @a this. + * + * @param rThat The string to append a substring from. + * @param offStart The start of the substring to append (UTF-16 + * offset, not codepoint). + * @param cwcMax The maximum number of UTF-16 units to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(const Bstr &rThat, size_t offStart, size_t cwcMax = RTSTR_MAX) RT_NOEXCEPT; + + /** + * Appends the a substring from UTF-8 @a rThat to @a this. + * + * @param rThat The string to append a substring from. + * @param offStart The start of the substring to append (byte offset, + * not codepoint). + * @param cchMax The maximum number of bytes to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(const RTCString &rThat, size_t offStart, size_t cchMax = RTSTR_MAX); + + /** + * Appends the a substring from UTF-8 @a rThat to @a this. + * + * @param rThat The string to append a substring from. + * @param offStart The start of the substring to append (byte offset, + * not codepoint). + * @param cchMax The maximum number of bytes to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(const RTCString &rThat, size_t offStart, size_t cchMax = RTSTR_MAX) RT_NOEXCEPT; + + /** + * Appends the first @a cchMax chars from UTF-16 string @a pszThat to @a this. + * + * @param pwszThat The C-style UTF-16 string to append. + * @param cchMax The maximum number of bytes to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(CBSTR pwszThat, size_t cchMax); + + /** + * Appends the first @a cchMax chars from UTF-16 string @a pszThat to @a this. + * + * @param pwszThat The C-style UTF-16 string to append. + * @param cchMax The maximum number of bytes to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(CBSTR pwszThat, size_t cchMax) RT_NOEXCEPT; + + /** + * Appends the first @a cchMax chars from string @a pszThat to @a this. + * + * @param pszThat The C-style string to append. + * @param cchMax The maximum number of bytes to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(const char *pszThat, size_t cchMax); + + /** + * Appends the first @a cchMax chars from string @a pszThat to @a this. + * + * @param pszThat The C-style string to append. + * @param cchMax The maximum number of bytes to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(const char *pszThat, size_t cchMax) RT_NOEXCEPT; + + /** + * Appends the given character to @a this. + * + * @param ch The character to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &append(char ch); + + /** + * Appends the given character to @a this. + * + * @param ch The character to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendNoThrow(char ch) RT_NOEXCEPT; + + /** + * Appends the given unicode code point to @a this. + * + * @param uc The unicode code point to append. + * @throws std::bad_alloc On allocation error. The object is left unchanged. + * @returns Reference to the object. + */ + Bstr &appendCodePoint(RTUNICP uc); + + /** + * Appends the given unicode code point to @a this. + * + * @param uc The unicode code point to append. + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendCodePointNoThrow(RTUNICP uc) RT_NOEXCEPT; + + /** + * Appends the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + Bstr &appendPrintf(const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Appends the output of the string format operation (RTStrPrintf). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + * + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendPrintfNoThrow(const char *pszFormat, ...) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 2); + + /** + * Appends the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @throws std::bad_alloc On allocation error. Object state is undefined. + * + * @returns Reference to the object. + */ + Bstr &appendPrintfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Appends the output of the string format operation (RTStrPrintfV). + * + * @param pszFormat Pointer to the format string, + * @see pg_rt_str_format. + * @param va Argument vector containing the arguments + * specified by the format string. + * + * @returns S_OK, E_OUTOFMEMORY or E_INVAL (bad encoding). + */ + HRESULT appendPrintfVNoThrow(const char *pszFormat, va_list va) RT_NOEXCEPT RT_IPRT_FORMAT_ATTR(1, 0); + + /** + * Shortcut to append(), Bstr variant. + * + * @param rThat The string to append. + * @returns Reference to the object. + */ + Bstr &operator+=(const Bstr &rThat) + { + return append(rThat); + } + + /** + * Shortcut to append(), RTCString variant. + * + * @param rThat The string to append. + * @returns Reference to the object. + */ + Bstr &operator+=(const RTCString &rThat) + { + return append(rThat); + } + + /** + * Shortcut to append(), CBSTR variant. + * + * @param pwszThat The C-style string to append. + * @returns Reference to the object. + */ + Bstr &operator+=(CBSTR pwszThat) + { + return append(pwszThat); + } + + /** + * Shortcut to append(), const char * variant. + * + * @param pszThat The C-style string to append. + * @returns Reference to the object. + */ + Bstr &operator+=(const char *pszThat) + { + return append(pszThat); + } + + /** + * Shortcut to append(), char variant. + * + * @param ch The character to append. + * + * @returns Reference to the object. + */ + Bstr &operator+=(char ch) + { + return append(ch); + } + + /** @} */ + + /** + * Erases a sequence from the string. + * + * @returns Reference to the object. + * @param offStart Where in @a this string to start erasing (UTF-16 + * units, not codepoints). + * @param cwcLength How much following @a offStart to erase (UTF-16 + * units, not codepoints). + */ + Bstr &erase(size_t offStart = 0, size_t cwcLength = RTSTR_MAX) RT_NOEXCEPT; + + + /** @name BASE64 related methods + * @{ */ + /** + * Encodes the given data as BASE64. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param pvData Pointer to the data to encode. + * @param cbData Number of bytes to encode. + * @param fLineBreaks Whether to add line breaks (true) or just encode it + * as a continuous string. + * @sa RTBase64EncodeUtf16 + */ + HRESULT base64Encode(const void *pvData, size_t cbData, bool fLineBreaks = false); + + /** + * Decodes the string as BASE64. + * + * @returns IPRT status code, see RTBase64DecodeUtf16Ex. + * @param pvData Where to return the decoded bytes. + * @param cbData Size of the @a pvData return buffer. + * @param pcbActual Where to return number of bytes actually decoded. + * This is optional and if not specified, the request + * will fail unless @a cbData matches the data size + * exactly. + * @param ppwszEnd Where to return pointer to the first non-base64 + * character following the encoded data. This is + * optional and if NULL, the request will fail if there + * are anything trailing the encoded bytes in the + * string. + * @sa base64DecodedSize, RTBase64DecodeUtf16 + */ + int base64Decode(void *pvData, size_t cbData, size_t *pcbActual = NULL, PRTUTF16 *ppwszEnd = NULL); + + /** + * Determins the size of the BASE64 encoded data in the string. + * + * @returns The length in bytes. -1 if the encoding is bad. + * + * @param ppwszEnd If not NULL, this will point to the first char + * following the Base64 encoded text block. If + * NULL the entire string is assumed to be Base64. + * @sa base64Decode, RTBase64DecodedUtf16Size + */ + ssize_t base64DecodedSize(PRTUTF16 *ppwszEnd = NULL); + /** @} */ + +#if defined(VBOX_WITH_XPCOM) + /** + * Returns a pointer to the raw member UTF-16 string. If the member string is empty, + * returns a pointer to a global variable containing an empty BSTR with a proper zero + * length prefix so that Windows is happy. + */ + CBSTR raw() const + { + if (m_bstr) + return m_bstr; + + return g_bstrEmpty; + } +#else + /** + * Windows-only hack, as the automatically generated headers use BSTR. + * So if we don't want to cast like crazy we have to be more loose than + * on XPCOM. + * + * Returns a pointer to the raw member UTF-16 string. If the member string is empty, + * returns a pointer to a global variable containing an empty BSTR with a proper zero + * length prefix so that Windows is happy. + */ + BSTR raw() const + { + if (m_bstr) + return m_bstr; + + return g_bstrEmpty; + } +#endif + + /** + * Returns a non-const raw pointer that allows modifying the string directly. + * + * @note As opposed to raw(), this DOES return NULL if the member string is + * empty because we cannot return a mutable pointer to the global variable + * with the empty string. + * + * @note If modifying the string size (only shrinking it is allows), #jolt() or + * #joltNoThrow() must be called! + * + * @note Do not modify memory beyond the #length() of the string! + * + * @sa joltNoThrow(), mutalbleRaw(), reserve(), reserveNoThrow() + */ + BSTR mutableRaw() { return m_bstr; } + + /** + * Correct the embedded length after using mutableRaw(). + * + * This is needed on COM (Windows) to update the embedded string length. It is + * a stub on hosts using XPCOM. + * + * @param cwcNew The new string length, if handy, otherwise a negative + * number. + * @sa joltNoThrow(), mutalbleRaw(), reserve(), reserveNoThrow() + */ +#ifndef VBOX_WITH_XPCOM + void jolt(ssize_t cwcNew = -1); +#else + void jolt(ssize_t cwcNew = -1) + { + Assert(cwcNew < 0 || (cwcNew == 0 && !m_bstr) || m_bstr[cwcNew] == '\0'); RT_NOREF(cwcNew); + } +#endif + + /** + * Correct the embedded length after using mutableRaw(). + * + * This is needed on COM (Windows) to update the embedded string length. It is + * a stub on hosts using XPCOM. + * + * @returns S_OK on success, E_OUTOFMEMORY if shrinking the string failed. + * @param cwcNew The new string length, if handy, otherwise a negative + * number. + * @sa jolt(), mutalbleRaw(), reserve(), reserveNoThrow() + */ +#ifndef VBOX_WITH_XPCOM + HRESULT joltNoThrow(ssize_t cwcNew = -1) RT_NOEXCEPT; +#else + HRESULT joltNoThrow(ssize_t cwcNew = -1) RT_NOEXCEPT + { + Assert(cwcNew < 0 || (cwcNew == 0 && !m_bstr) || m_bstr[cwcNew] == '\0'); RT_NOREF(cwcNew); + return S_OK; + } +#endif + + /** + * Make sure at that least @a cwc of buffer space is reserved. + * + * Requests that the contained memory buffer have at least cb bytes allocated. + * This may expand or shrink the string's storage, but will never truncate the + * contained string. In other words, cb will be ignored if it's smaller than + * length() + 1. + * + * @param cwcMin The new minimum string length that the can be stored. This + * does not include the terminator. + * @param fForce Force this size. + * + * @throws std::bad_alloc On allocation error. The object is left unchanged. + */ + void reserve(size_t cwcMin, bool fForce = false); + + /** + * A C like version of the #reserve() method, i.e. return code instead of throw. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param cwcMin The new minimum string length that the can be stored. This + * does not include the terminator. + * @param fForce Force this size. + */ + HRESULT reserveNoThrow(size_t cwcMin, bool fForce = false) RT_NOEXCEPT; + + /** + * Intended to assign copies of instances to |BSTR| out parameters from + * within the interface method. Transfers the ownership of the duplicated + * string to the caller. + * + * If the member string is empty, this allocates an empty BSTR in *pstr + * (i.e. makes it point to a new buffer with a null byte). + * + * @deprecated Use cloneToEx instead to avoid throwing exceptions. + */ + void cloneTo(BSTR *pstr) const + { + if (pstr) + { + *pstr = ::SysAllocString((const OLECHAR *)raw()); // raw() returns a pointer to "" if empty +#ifdef RT_EXCEPTIONS_ENABLED + if (!*pstr) + throw std::bad_alloc(); +#endif + } + } + + /** + * A version of cloneTo that does not throw any out of memory exceptions, but + * returns E_OUTOFMEMORY intead. + * @returns S_OK or E_OUTOFMEMORY. + */ + HRESULT cloneToEx(BSTR *pstr) const + { + if (!pstr) + return S_OK; + *pstr = ::SysAllocString((const OLECHAR *)raw()); // raw() returns a pointer to "" if empty + return pstr ? S_OK : E_OUTOFMEMORY; + } + + /** + * Intended to assign instances to |BSTR| out parameters from within the + * interface method. Transfers the ownership of the original string to the + * caller and resets the instance to null. + * + * As opposed to cloneTo(), this method doesn't create a copy of the + * string. + * + * If the member string is empty, this allocates an empty BSTR in *pstr + * (i.e. makes it point to a new buffer with a null byte). + * + * @param pbstrDst The BSTR variable to detach the string to. + * + * @throws std::bad_alloc if we failed to allocate a new empty string. + */ + void detachTo(BSTR *pbstrDst) + { + if (m_bstr) + { + *pbstrDst = m_bstr; + m_bstr = NULL; + } + else + { + // allocate null BSTR + *pbstrDst = ::SysAllocString((const OLECHAR *)g_bstrEmpty); +#ifdef RT_EXCEPTIONS_ENABLED + if (!*pbstrDst) + throw std::bad_alloc(); +#endif + } + } + + /** + * A version of detachTo that does not throw exceptions on out-of-memory + * conditions, but instead returns E_OUTOFMEMORY. + * + * @param pbstrDst The BSTR variable to detach the string to. + * @returns S_OK or E_OUTOFMEMORY. + */ + HRESULT detachToEx(BSTR *pbstrDst) + { + if (m_bstr) + { + *pbstrDst = m_bstr; + m_bstr = NULL; + } + else + { + // allocate null BSTR + *pbstrDst = ::SysAllocString((const OLECHAR *)g_bstrEmpty); + if (!*pbstrDst) + return E_OUTOFMEMORY; + } + return S_OK; + } + + /** + * Intended to pass instances as |BSTR| out parameters to methods. + * Takes the ownership of the returned data. + */ + BSTR *asOutParam() + { + cleanup(); + return &m_bstr; + } + + /** + * Static immutable empty-string object. May be used for comparison purposes. + */ + static const Bstr Empty; + +protected: + + void cleanup(); + + /** + * Protected internal helper to copy a string. This ignores the previous object + * state, so either call this from a constructor or call cleanup() first. + * + * This variant copies from a zero-terminated UTF-16 string (which need not + * be a BSTR, i.e. need not have a length prefix). + * + * If the source is empty, this sets the member string to NULL. + * + * @param a_bstrSrc The source string. The caller guarantees + * that this is valid UTF-16. + * + * @throws std::bad_alloc - the object is representing an empty string. + */ + void copyFrom(const OLECHAR *a_bstrSrc); + + /** cleanup() + copyFrom() - for assignment operators. */ + void cleanupAndCopyFrom(const OLECHAR *a_bstrSrc); + + /** + * Protected internal helper to copy a string, implying cleanup(). + * + * This variant copies from a zero-terminated UTF-16 string (which need not be a + * BSTR, i.e. need not have a length prefix). + * + * If the source is empty, this sets the member string to NULL. + * + * @param a_bstrSrc The source string. The caller guarantees + * that this is valid UTF-16. + * @returns S_OK or E_OUTOFMEMORY + */ + HRESULT cleanupAndCopyFromEx(const OLECHAR *a_bstrSrc) RT_NOEXCEPT; + + /** + * Protected internal helper to copy a string. This ignores the previous object + * state, so either call this from a constructor or call cleanup() first. + * + * This variant copies and converts from a zero-terminated UTF-8 string. + * + * If the source is empty, this sets the member string to NULL. + * + * @param a_pszSrc The source string. The caller guarantees + * that this is valid UTF-8. + * + * @throws std::bad_alloc - the object is representing an empty string. + */ + void copyFrom(const char *a_pszSrc) + { + copyFromN(a_pszSrc, RTSTR_MAX); + } + + /** + * Variant of copyFrom for sub-string constructors. + * + * @param a_pszSrc The source string. The caller guarantees + * that this is valid UTF-8. + * @param a_cchSrc The maximum number of chars (not codepoints) to + * copy. If you pass RTSTR_MAX it'll be exactly + * like copyFrom(). + * + * @throws std::bad_alloc - the object is representing an empty string. + */ + void copyFromN(const char *a_pszSrc, size_t a_cchSrc); + + /** cleanup() + non-throwing copyFromN(). */ + HRESULT cleanupAndCopyFromNoThrow(const char *a_pszSrc, size_t a_cchMax) RT_NOEXCEPT; + + Bstr &appendWorkerUtf16(PCRTUTF16 pwszSrc, size_t cwcSrc); + Bstr &appendWorkerUtf8(const char *pszSrc, size_t cchSrc); + HRESULT appendWorkerUtf16NoThrow(PCRTUTF16 pwszSrc, size_t cwcSrc) RT_NOEXCEPT; + HRESULT appendWorkerUtf8NoThrow(const char *pszSrc, size_t cchSrc) RT_NOEXCEPT; + + static DECLCALLBACK(size_t) printfOutputCallbackNoThrow(void *pvArg, const char *pachChars, size_t cbChars) RT_NOEXCEPT; + + BSTR m_bstr; + + friend class Utf8Str; /* to access our raw_copy() */ +}; + +/* symmetric compare operators */ +inline bool operator==(CBSTR l, const Bstr &r) { return r.operator==(l); } +inline bool operator!=(CBSTR l, const Bstr &r) { return r.operator!=(l); } +inline bool operator==(BSTR l, const Bstr &r) { return r.operator==(l); } +inline bool operator!=(BSTR l, const Bstr &r) { return r.operator!=(l); } + + + + +/** + * String class used universally in Main for UTF-8 strings. + * + * This is based on RTCString, to which some functionality has been + * moved. Here we keep things that are specific to Main, such as conversions + * with UTF-16 strings (Bstr). + * + * Like RTCString, Utf8Str does not differentiate between NULL strings + * and empty strings. In other words, Utf8Str("") and Utf8Str(NULL) behave the + * same. In both cases, RTCString allocates no memory, reports + * a zero length and zero allocated bytes for both, and returns an empty + * C string from c_str(). + * + * @note All Utf8Str methods ASSUMES valid UTF-8 or UTF-16 input strings. + * The VirtualBox policy in this regard is to validate strings coming + * from external sources before passing them to Utf8Str or Bstr. + */ +class Utf8Str : public RTCString +{ +public: + + Utf8Str() {} + + Utf8Str(const RTCString &that) + : RTCString(that) + {} + + Utf8Str(const char *that) + : RTCString(that) + {} + + Utf8Str(const Bstr &that) + { + copyFrom(that.raw()); + } + + Utf8Str(CBSTR that, size_t a_cwcSize = RTSTR_MAX) + { + copyFrom(that, a_cwcSize); + } + + Utf8Str(const char *a_pszSrc, size_t a_cchSrc) + : RTCString(a_pszSrc, a_cchSrc) + { + } + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param a_pszFormat Pointer to the format string (UTF-8), + * @see pg_rt_str_format. + * @param a_va Argument vector containing the arguments + * specified by the format string. + * @sa RTCString::printfV + */ + Utf8Str(const char *a_pszFormat, va_list a_va) RT_IPRT_FORMAT_ATTR(1, 0) + : RTCString(a_pszFormat, a_va) + { + } + + Utf8Str& operator=(const RTCString &that) + { + RTCString::operator=(that); + return *this; + } + + Utf8Str& operator=(const char *that) + { + RTCString::operator=(that); + return *this; + } + + Utf8Str& operator=(const Bstr &that) + { + cleanup(); + copyFrom(that.raw()); + return *this; + } + + Utf8Str& operator=(CBSTR that) + { + cleanup(); + copyFrom(that); + return *this; + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_rSrcStr The source string + */ + HRESULT assignEx(Utf8Str const &a_rSrcStr) + { + return copyFromExNComRC(a_rSrcStr.m_psz, 0, a_rSrcStr.m_cch); + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK, E_OUTOFMEMORY or E_INVALIDARG. + * @param a_rSrcStr The source string + * @param a_offSrc The character (byte) offset of the substring. + * @param a_cchSrc The number of characters (bytes) to copy from the source + * string. + */ + HRESULT assignEx(Utf8Str const &a_rSrcStr, size_t a_offSrc, size_t a_cchSrc) + { + if ( a_offSrc + a_cchSrc > a_rSrcStr.m_cch + || a_offSrc > a_rSrcStr.m_cch) + return E_INVALIDARG; + return copyFromExNComRC(a_rSrcStr.m_psz, a_offSrc, a_cchSrc); + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_pcszSrc The source string + */ + HRESULT assignEx(const char *a_pcszSrc) + { + return copyFromExNComRC(a_pcszSrc, 0, a_pcszSrc ? strlen(a_pcszSrc) : 0); + } + + /** + * Extended assignment method that returns a COM status code instead of an + * exception on failure. + * + * @returns S_OK or E_OUTOFMEMORY. + * @param a_pcszSrc The source string + * @param a_cchSrc The number of characters (bytes) to copy from the source + * string. + */ + HRESULT assignEx(const char *a_pcszSrc, size_t a_cchSrc) + { + return copyFromExNComRC(a_pcszSrc, 0, a_cchSrc); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +#if defined(VBOX_WITH_XPCOM) + /** + * Intended to assign instances to |char *| out parameters from within the + * interface method. Transfers the ownership of the duplicated string to the + * caller. + * + * This allocates a single 0 byte in the target if the member string is empty. + * + * This uses XPCOM memory allocation and thus only works on XPCOM. MSCOM doesn't + * like char* strings anyway. + */ + void cloneTo(char **pstr) const; + + /** + * A version of cloneTo that does not throw allocation errors but returns + * E_OUTOFMEMORY instead. + * @returns S_OK or E_OUTOFMEMORY (COM status codes). + */ + HRESULT cloneToEx(char **pstr) const; +#endif + + /** + * Intended to assign instances to |BSTR| out parameters from within the + * interface method. Transfers the ownership of the duplicated string to the + * caller. + */ + void cloneTo(BSTR *pstr) const + { + if (pstr) + { + Bstr bstr(*this); + bstr.cloneTo(pstr); + } + } + + /** + * A version of cloneTo that does not throw allocation errors but returns + * E_OUTOFMEMORY instead. + * + * @param pbstr Where to store a clone of the string. + * @returns S_OK or E_OUTOFMEMORY (COM status codes). + */ + HRESULT cloneToEx(BSTR *pbstr) const RT_NOEXCEPT; + + /** + * Safe assignment from BSTR. + * + * @param pbstrSrc The source string. + * @returns S_OK or E_OUTOFMEMORY (COM status codes). + */ + HRESULT cloneEx(CBSTR pbstrSrc) + { + cleanup(); + return copyFromEx(pbstrSrc); + } + + /** + * Removes a trailing slash from the member string, if present. + * Calls RTPathStripTrailingSlash() without having to mess with mutableRaw(). + */ + Utf8Str& stripTrailingSlash(); + + /** + * Removes a trailing filename from the member string, if present. + * Calls RTPathStripFilename() without having to mess with mutableRaw(). + */ + Utf8Str& stripFilename(); + + /** + * Removes the path component from the member string, if present. + * Calls RTPathFilename() without having to mess with mutableRaw(). + */ + Utf8Str& stripPath(); + + /** + * Removes a trailing file name suffix from the member string, if present. + * Calls RTPathStripSuffix() without having to mess with mutableRaw(). + */ + Utf8Str& stripSuffix(); + + /** + * Parses key=value pairs. + * + * @returns offset of the @a a_rPairSeparator following the returned value. + * @retval npos is returned if there are no more key/value pairs. + * + * @param a_rKey Reference to variable that should receive + * the key substring. This is set to null if + * no key/value found. (It's also possible the + * key is an empty string, so be careful.) + * @param a_rValue Reference to variable that should receive + * the value substring. This is set to null if + * no key/value found. (It's also possible the + * value is an empty string, so be careful.) + * @param a_offStart The offset to start searching from. This is + * typically 0 for the first call, and the + * return value of the previous call for the + * subsequent ones. + * @param a_rPairSeparator The pair separator string. If this is an + * empty string, the whole string will be + * considered as a single key/value pair. + * @param a_rKeyValueSeparator The key/value separator string. + */ + size_t parseKeyValue(Utf8Str &a_rKey, Utf8Str &a_rValue, size_t a_offStart = 0, + const Utf8Str &a_rPairSeparator = ",", const Utf8Str &a_rKeyValueSeparator = "=") const; + + /** + * Static immutable empty-string object. May be used for comparison purposes. + */ + static const Utf8Str Empty; +protected: + + void copyFrom(CBSTR a_pbstr, size_t a_cwcMax = RTSTR_MAX); + HRESULT copyFromEx(CBSTR a_pbstr); + HRESULT copyFromExNComRC(const char *a_pcszSrc, size_t a_offSrc, size_t a_cchSrc); + + friend class Bstr; /* to access our raw_copy() */ +}; + +/** + * Class with RTCString::printf as constructor for your convenience. + * + * Constructing a Utf8Str string object from a format string and a variable + * number of arguments can easily be confused with the other Utf8Str + * constructures, thus this child class. + * + * The usage of this class is like the following: + * @code + Utf8StrFmt strName("program name = %s", argv[0]); + @endcode + * + * @note Do not use in assignments to Utf8Str variables. Instead use + * RTCString::printf directly on the variable! This avoid an extra + * temporary Utf8Str instance and assignment operation. + */ +class Utf8StrFmt : public Utf8Str +{ +public: + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param a_pszFormat Pointer to the format string (UTF-8), + * @see pg_rt_str_format. + * @param ... Ellipsis containing the arguments specified by + * the format string. + */ + explicit Utf8StrFmt(const char *a_pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2) + { + va_list va; + va_start(va, a_pszFormat); + printfV(a_pszFormat, va); + va_end(va); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +protected: + Utf8StrFmt() + { } + +private: +}; + +/** + * Class with Bstr::printf as constructor for your convenience. + */ +class BstrFmt : public Bstr +{ +public: + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param a_pszFormat printf-like format string (in UTF-8 encoding), see + * iprt/string.h for details. + * @param ... List of the arguments for the format string. + */ + explicit BstrFmt(const char *a_pszFormat, ...) RT_IPRT_FORMAT_ATTR(1, 2) + { + va_list va; + va_start(va, a_pszFormat); + printfV(a_pszFormat, va); + va_end(va); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +protected: + BstrFmt() + { } +}; + +/** + * Class with Bstr::printfV as constructor for your convenience. + */ +class BstrFmtVA : public Bstr +{ +public: + + /** + * Constructs a new string given the format string and the list of the + * arguments for the format string. + * + * @param a_pszFormat printf-like format string (in UTF-8 encoding), see + * iprt/string.h for details. + * @param a_va List of arguments for the format string + */ + BstrFmtVA(const char *a_pszFormat, va_list a_va) RT_IPRT_FORMAT_ATTR(1, 0) + { + printfV(a_pszFormat, a_va); + } + + RTMEMEF_NEW_AND_DELETE_OPERATORS(); + +protected: + BstrFmtVA() + { } +}; + +} /* namespace com */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_com_string_h */ + diff --git a/include/VBox/com/utils.h b/include/VBox/com/utils.h new file mode 100644 index 00000000..e47b4129 --- /dev/null +++ b/include/VBox/com/utils.h @@ -0,0 +1,132 @@ +/** @file + * MS COM / XPCOM Abstraction Layer - COM initialization / shutdown. + */ + +/* + * Copyright (C) 2005-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_com_utils_h +#define VBOX_INCLUDED_com_utils_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include "iprt/types.h" + +/** @addtogroup grp_com + * @{ + */ + +namespace com +{ + +/** + * Returns the VirtualBox user home directory. + * + * On failure, this function will return a path that caused a failure (or + * NULL if the failure is not path-related). + * + * On success, this function will try to create the returned directory if it + * doesn't exist yet. This may also fail with the corresponding status code. + * + * If @a aDirLen is smaller than RTPATH_MAX then there is a great chance that + * this method will return VERR_BUFFER_OVERFLOW. + * + * @param aDir Buffer to store the directory string in UTF-8 encoding. + * @param aDirLen Length of the supplied buffer including space for the + * terminating null character, in bytes. + * @param fCreateDir Flag whether to create the returned directory on success + * if it doesn't exist. + * @returns VBox status code. + */ +int GetVBoxUserHomeDirectory(char *aDir, size_t aDirLen, bool fCreateDir = true); + +/** + * Creates a release log file, used both in VBoxSVC and in API clients. + * + * @param pszEntity Human readable name of the program. + * @param pszLogFile Name of the release log file. + * @param fFlags Logger instance flags. + * @param pszGroupSettings Group logging settings. + * @param pszEnvVarBase Base environment variable name for the logger. + * @param fDestFlags Logger destination flags. + * @param cMaxEntriesPerGroup Limit for log entries per group. UINT32_MAX for no limit. + * @param cHistory Number of old log files to keep. + * @param uHistoryFileTime Maximum amount of time to put in a log file. + * @param uHistoryFileSize Maximum size of a log file before rotating. + * @param pErrInfo Where to return extended error information. + * Optional. + * + * @returns VBox status code. + */ +int VBoxLogRelCreate(const char *pszEntity, const char *pszLogFile, + uint32_t fFlags, const char *pszGroupSettings, + const char *pszEnvVarBase, uint32_t fDestFlags, + uint32_t cMaxEntriesPerGroup, uint32_t cHistory, + uint32_t uHistoryFileTime, uint64_t uHistoryFileSize, + PRTERRINFO pErrInfo); + +/** + * Creates a release log file, used both in VBoxSVC and in API clients. + * + * @param pszEntity Human readable name of the program. + * @param pszLogFile Name of the release log file. + * @param fFlags Logger instance flags. + * @param pszGroupSettings Group logging settings. + * @param pszEnvVarBase Base environment variable name for the logger. + * @param fDestFlags Logger destination flags. + * @param cMaxEntriesPerGroup Limit for log entries per group. UINT32_MAX for no limit. + * @param cHistory Number of old log files to keep. + * @param uHistoryFileTime Maximum amount of time to put in a log file. + * @param uHistoryFileSize Maximum size of a log file before rotating. + * @param pOutputIf The optional file output interface, can be NULL which will + * make use of the default one. + * @param pvOutputIfUser The opaque user data to pass to the callbacks in the output interface. + * @param pErrInfo Where to return extended error information. + * Optional. + * + * @returns VBox status code. + * + * @note Can't include log.h here because of precompiled header fun, hence pOutputIf is void *... + */ +int VBoxLogRelCreateEx(const char *pszEntity, const char *pszLogFile, + uint32_t fFlags, const char *pszGroupSettings, + const char *pszEnvVarBase, uint32_t fDestFlags, + uint32_t cMaxEntriesPerGroup, uint32_t cHistory, + uint32_t uHistoryFileTime, uint64_t uHistoryFileSize, + const void *pOutputIf, void *pvOutputIfUser, + PRTERRINFO pErrInfo); + +} /* namespace com */ + +/** @} */ +#endif /* !VBOX_INCLUDED_com_utils_h */ + diff --git a/include/VBox/dbg.h b/include/VBox/dbg.h new file mode 100644 index 00000000..901b72da --- /dev/null +++ b/include/VBox/dbg.h @@ -0,0 +1,1222 @@ +/** @file + * Debugger Interfaces. (VBoxDbg) + * + * This header covers all external interfaces of the Debugger module. + * However, it does not cover the DBGF interface since that part of the + * VMM. Use dbgf.h for that. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_dbg_h +#define VBOX_INCLUDED_dbg_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +#include +#ifdef IN_RING3 +# include +#endif + +RT_C_DECLS_BEGIN + + + +/** @defgroup grp_dbg The VirtualBox Debugger + * @{ + */ + +#ifdef IN_RING3 /* The debugger stuff is ring-3 only. */ + +/** @defgroup grp_dbgc The Debugger Console API + * @{ + */ + +/** @def VBOX_WITH_DEBUGGER + * The build is with debugger module. Test if this is defined before registering + * external debugger commands. This is normally defined in Config.kmk. + */ +#ifdef DOXYGEN_RUNNING +# define VBOX_WITH_DEBUGGER +#endif + + +/** + * DBGC variable category. + * + * Used to describe an argument to a command or function and a functions + * return value. + */ +typedef enum DBGCVARCAT +{ + /** Any type is fine. */ + DBGCVAR_CAT_ANY = 0, + /** Any kind of pointer or number. */ + DBGCVAR_CAT_POINTER_NUMBER, + /** Any kind of pointer or number, no range. */ + DBGCVAR_CAT_POINTER_NUMBER_NO_RANGE, + /** Any kind of pointer. */ + DBGCVAR_CAT_POINTER, + /** Any kind of pointer with no range option. */ + DBGCVAR_CAT_POINTER_NO_RANGE, + /** GC pointer. */ + DBGCVAR_CAT_GC_POINTER, + /** GC pointer with no range option. */ + DBGCVAR_CAT_GC_POINTER_NO_RANGE, + /** Numeric argument. */ + DBGCVAR_CAT_NUMBER, + /** Numeric argument with no range option. */ + DBGCVAR_CAT_NUMBER_NO_RANGE, + /** String. */ + DBGCVAR_CAT_STRING, + /** Symbol. */ + DBGCVAR_CAT_SYMBOL, + /** Option. */ + DBGCVAR_CAT_OPTION, + /** Option + string. */ + DBGCVAR_CAT_OPTION_STRING, + /** Option + number. */ + DBGCVAR_CAT_OPTION_NUMBER +} DBGCVARCAT; + + +/** + * DBGC variable type. + */ +typedef enum DBGCVARTYPE +{ + /** unknown... */ + DBGCVAR_TYPE_UNKNOWN = 0, + /** Flat GC pointer. */ + DBGCVAR_TYPE_GC_FLAT, + /** Segmented GC pointer. */ + DBGCVAR_TYPE_GC_FAR, + /** Physical GC pointer. */ + DBGCVAR_TYPE_GC_PHYS, + /** Flat HC pointer. */ + DBGCVAR_TYPE_HC_FLAT, + /** Physical HC pointer. */ + DBGCVAR_TYPE_HC_PHYS, + /** Number. */ + DBGCVAR_TYPE_NUMBER, + /** String. */ + DBGCVAR_TYPE_STRING, + /** Symbol. */ + DBGCVAR_TYPE_SYMBOL, + /** Special type used when querying symbols. */ + DBGCVAR_TYPE_ANY +} DBGCVARTYPE; + +/** @todo Rename to DBGCVAR_IS_xyz. */ + +/** Checks if the specified variable type is of a pointer persuasion. */ +#define DBGCVAR_ISPOINTER(enmType) ((enmType) >= DBGCVAR_TYPE_GC_FLAT && enmType <= DBGCVAR_TYPE_HC_PHYS) +/** Checks if the specified variable type is of a pointer persuasion. */ +#define DBGCVAR_IS_FAR_PTR(enmType) ((enmType) == DBGCVAR_TYPE_GC_FAR) +/** Checks if the specified variable type is of a pointer persuasion and of the guest context sort. */ +#define DBGCVAR_ISGCPOINTER(enmType) ((enmType) >= DBGCVAR_TYPE_GC_FLAT && (enmType) <= DBGCVAR_TYPE_GC_PHYS) +/** Checks if the specified variable type is of a pointer persuasion and of the host context sort. */ +#define DBGCVAR_ISHCPOINTER(enmType) ((enmType) >= DBGCVAR_TYPE_HC_FLAT && (enmType) <= DBGCVAR_TYPE_HC_PHYS) + + +/** + * DBGC variable range type. + */ +typedef enum DBGCVARRANGETYPE +{ + /** No range appliable or no range specified. */ + DBGCVAR_RANGE_NONE = 0, + /** Number of elements. */ + DBGCVAR_RANGE_ELEMENTS, + /** Number of bytes. */ + DBGCVAR_RANGE_BYTES +} DBGCVARRANGETYPE; + + +/** + * Variable descriptor. + */ +typedef struct DBGCVARDESC +{ + /** The minimal number of times this argument may occur. + * Use 0 here to inidicate that the argument is optional. */ + unsigned cTimesMin; + /** Maximum number of occurrences. + * Use ~0 here to indicate infinite. */ + unsigned cTimesMax; + /** Argument category. */ + DBGCVARCAT enmCategory; + /** Flags, DBGCVD_FLAGS_* */ + unsigned fFlags; + /** Argument name. */ + const char *pszName; + /** Argument name. */ + const char *pszDescription; +} DBGCVARDESC; +/** Pointer to an argument descriptor. */ +typedef DBGCVARDESC *PDBGCVARDESC; +/** Pointer to a const argument descriptor. */ +typedef const DBGCVARDESC *PCDBGCVARDESC; + +/** Variable descriptor flags. + * @{ */ +/** Indicates that the variable depends on the previous being present. */ +#define DBGCVD_FLAGS_DEP_PREV RT_BIT(1) +/** @} */ + + +/** + * DBGC variable. + */ +typedef struct DBGCVAR +{ + /** Pointer to the argument descriptor. */ + PCDBGCVARDESC pDesc; + /** Pointer to the next argument. */ + struct DBGCVAR *pNext; + + /** Argument type. */ + DBGCVARTYPE enmType; + /** Type specific. */ + union + { + /** Flat GC Address. (DBGCVAR_TYPE_GC_FLAT) */ + RTGCPTR GCFlat; + /** Far (16:32) GC Address. (DBGCVAR_TYPE_GC_FAR) */ + RTFAR32 GCFar; + /** Physical GC Address. (DBGCVAR_TYPE_GC_PHYS) */ + RTGCPHYS GCPhys; + /** Flat HC Address. (DBGCVAR_TYPE_HC_FLAT) */ + void *pvHCFlat; + /** Physical GC Address. (DBGCVAR_TYPE_HC_PHYS) */ + RTHCPHYS HCPhys; + /** String. (DBGCVAR_TYPE_STRING) + * The basic idea is the the this is a pointer to the expression we're + * parsing, so no messing with freeing. */ + const char *pszString; + /** Number. (DBGCVAR_TYPE_NUMBER) */ + uint64_t u64Number; + } u; + + /** Range type. */ + DBGCVARRANGETYPE enmRangeType; + /** Range. The use of the content depends on the enmRangeType. */ + uint64_t u64Range; +} DBGCVAR; +/** Pointer to a command argument. */ +typedef DBGCVAR *PDBGCVAR; +/** Pointer to a const command argument. */ +typedef const DBGCVAR *PCDBGCVAR; + + +/** + * Macro for initializing a DBGC variable with defaults. + * The result is an unknown variable type without any range. + */ +#define DBGCVAR_INIT(pVar) \ + do { \ + (pVar)->pDesc = NULL;\ + (pVar)->pNext = NULL; \ + (pVar)->enmType = DBGCVAR_TYPE_UNKNOWN; \ + (pVar)->u.u64Number = 0; \ + (pVar)->enmRangeType = DBGCVAR_RANGE_NONE; \ + (pVar)->u64Range = 0; \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a HC physical address. + */ +#define DBGCVAR_INIT_HC_PHYS(pVar, Phys) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_HC_PHYS; \ + (pVar)->u.HCPhys = (Phys); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a HC flat address. + */ +#define DBGCVAR_INIT_HC_FLAT(pVar, Flat) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_HC_FLAT; \ + (pVar)->u.pvHCFlat = (Flat); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a GC physical address. + */ +#define DBGCVAR_INIT_GC_PHYS(pVar, Phys) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_GC_PHYS; \ + (pVar)->u.GCPhys = (Phys); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a GC flat address. + */ +#define DBGCVAR_INIT_GC_FLAT(pVar, Flat) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_GC_FLAT; \ + (pVar)->u.GCFlat = (Flat); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a GC flat address. + */ +#define DBGCVAR_INIT_GC_FLAT_BYTE_RANGE(pVar, Flat, cbRange) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_GC_FLAT; \ + (pVar)->u.GCFlat = (Flat); \ + DBGCVAR_SET_RANGE(pVar, DBGCVAR_RANGE_BYTES, cbRange); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a GC far address. + */ +#define DBGCVAR_INIT_GC_FAR(pVar, _sel, _off) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_GC_FAR; \ + (pVar)->u.GCFar.sel = (_sel); \ + (pVar)->u.GCFar.off = (_off); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a number. + */ +#define DBGCVAR_INIT_NUMBER(pVar, Value) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_NUMBER; \ + (pVar)->u.u64Number = (Value); \ + } while (0) + +/** + * Macro for initializing a DBGC variable with a string. + */ +#define DBGCVAR_INIT_STRING(pVar, a_pszString) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_STRING; \ + (pVar)->enmRangeType = DBGCVAR_RANGE_BYTES; \ + (pVar)->u.pszString = (a_pszString); \ + (pVar)->u64Range = strlen(a_pszString); \ + } while (0) + + +/** + * Macro for initializing a DBGC variable with a symbol. + */ +#define DBGCVAR_INIT_SYMBOL(pVar, a_pszSymbol) \ + do { \ + DBGCVAR_INIT(pVar); \ + (pVar)->enmType = DBGCVAR_TYPE_SYMBOL; \ + (pVar)->enmRangeType = DBGCVAR_RANGE_BYTES; \ + (pVar)->u.pszString = (a_pszSymbol); \ + (pVar)->u64Range = strlen(a_pszSymbol); \ + } while (0) + + +/** + * Macro for setting the range of a DBGC variable. + * @param pVar The variable. + * @param _enmRangeType The range type. + * @param Value The range length value. + */ +#define DBGCVAR_SET_RANGE(pVar, _enmRangeType, Value) \ + do { \ + (pVar)->enmRangeType = (_enmRangeType); \ + (pVar)->u64Range = (Value); \ + } while (0) + + +/** + * Macro for setting the range of a DBGC variable. + * @param a_pVar The variable. + * @param a_cbRange The range, in bytes. + */ +#define DBGCVAR_SET_BYTE_RANGE(a_pVar, a_cbRange) \ + DBGCVAR_SET_RANGE(a_pVar, DBGCVAR_RANGE_BYTES, a_cbRange) + + +/** + * Macro for resetting the range a DBGC variable. + * @param a_pVar The variable. + */ +#define DBGCVAR_ZAP_RANGE(a_pVar) \ + do { \ + (a_pVar)->enmRangeType = DBGCVAR_RANGE_NONE; \ + (a_pVar)->u64Range = 0; \ + } while (0) + + +/** + * Macro for assigning one DBGC variable to another. + * @param a_pResult The result (target) variable. + * @param a_pVar The source variable. + */ +#define DBGCVAR_ASSIGN(a_pResult, a_pVar) \ + do { \ + *(a_pResult) = *(a_pVar); \ + } while (0) + + +/** Pointer to a command descriptor. */ +typedef struct DBGCCMD *PDBGCCMD; +/** Pointer to a const command descriptor. */ +typedef const struct DBGCCMD *PCDBGCCMD; + +/** Pointer to a function descriptor. */ +typedef struct DBGCFUNC *PDBGCFUNC; +/** Pointer to a const function descriptor. */ +typedef const struct DBGCFUNC *PCDBGCFUNC; + +/** Pointer to helper functions for commands. */ +typedef struct DBGCCMDHLP *PDBGCCMDHLP; + + +/** + * Helper functions for commands. + */ +typedef struct DBGCCMDHLP +{ + /** Magic value (DBGCCMDHLP_MAGIC). */ + uint32_t u32Magic; + + /** + * Command helper for writing formatted text to the debug console. + * + * @returns VBox status. + * @param pCmdHlp Pointer to the command callback structure. + * @param pcbWritten Where to store the number of bytes written. + * This is optional. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param ... Arguments specified in the format string. + */ + DECLCALLBACKMEMBER(int, pfnPrintf,(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, + const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(3, 4); + + /** + * Command helper for writing formatted text to the debug console. + * + * @returns VBox status. + * @param pCmdHlp Pointer to the command callback structure. + * @param pcbWritten Where to store the number of bytes written. + * This is optional. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param args Arguments specified in the format string. + */ + DECLCALLBACKMEMBER(int, pfnPrintfV,(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, + const char *pszFormat, va_list args)) RT_IPRT_FORMAT_ATTR(3, 0); + + /** + * Command helper for formatting a string with debugger format specifiers. + * + * @returns The number of bytes written. + * @param pCmdHlp Pointer to the command callback structure. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param ... Arguments specified in the format string. + */ + DECLCALLBACKMEMBER(size_t, pfnStrPrintf,(PDBGCCMDHLP pCmdHlp, char *pszBuf, size_t cbBuf, + const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(4, 5); + + /** + * Command helper for formatting a string with debugger format specifiers. + * + * @returns The number of bytes written. + * @param pCmdHlp Pointer to the command callback structure. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param va Arguments specified in the format string. + */ + DECLCALLBACKMEMBER(size_t, pfnStrPrintfV,(PDBGCCMDHLP pCmdHlp, char *pszBuf, size_t cbBuf, + const char *pszFormat, va_list va)) RT_IPRT_FORMAT_ATTR(4, 0); + + /** + * Command helper for formatting and error message for a VBox status code. + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param rc The VBox status code. + * @param pszFormat Format string for additional messages. Can be NULL. + * @param ... Format arguments, optional. + */ + DECLCALLBACKMEMBER(int, pfnVBoxError,(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(3, 4); + + /** + * Command helper for formatting and error message for a VBox status code. + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param rc The VBox status code. + * @param pszFormat Format string for additional messages. Can be NULL. + * @param args Format arguments, optional. + */ + DECLCALLBACKMEMBER(int, pfnVBoxErrorV,(PDBGCCMDHLP pCmdHlp, int rc, + const char *pszFormat, va_list args)) RT_IPRT_FORMAT_ATTR(3, 0); + + /** + * Command helper for reading memory specified by a DBGC variable. + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param pvBuffer Where to store the read data. + * @param cbRead Number of bytes to read. + * @param pVarPointer DBGC variable specifying where to start reading. + * @param pcbRead Where to store the number of bytes actually read. + * This optional, but it's useful when read GC virtual memory where a + * page in the requested range might not be present. + * If not specified not-present failure or end of a HC physical page + * will cause failure. + */ + DECLCALLBACKMEMBER(int, pfnMemRead,(PDBGCCMDHLP pCmdHlp, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead)); + + /** + * Command helper for writing memory specified by a DBGC variable. + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param pvBuffer What to write. + * @param cbWrite Number of bytes to write. + * @param pVarPointer DBGC variable specifying where to start reading. + * @param pcbWritten Where to store the number of bytes written. + * This is optional. If NULL be aware that some of the buffer + * might have been written to the specified address. + */ + DECLCALLBACKMEMBER(int, pfnMemWrite,(PDBGCCMDHLP pCmdHlp, const void *pvBuffer, size_t cbWrite, PCDBGCVAR pVarPointer, size_t *pcbWritten)); + + /** + * Executes command an expression. + * (Hopefully the parser and functions are fully reentrant.) + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param pszExpr The expression. Format string with the format DBGC extensions. + * @param ... Format arguments. + */ + DECLCALLBACKMEMBER(int, pfnExec,(PDBGCCMDHLP pCmdHlp, const char *pszExpr, ...)) RT_IPRT_FORMAT_ATTR(2, 3); + + /** + * Evaluates an expression. + * (Hopefully the parser and functions are fully reentrant.) + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param pResult Where to store the result. + * @param pszExpr The expression. Format string with the format DBGC extensions. + * @param va Format arguments. + */ + DECLCALLBACKMEMBER(int, pfnEvalV,(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, + const char *pszExpr, va_list va)) RT_IPRT_FORMAT_ATTR(3, 0); + + /** + * Print an error and fail the current command. + * + * @returns VBox status code to pass upwards. + * + * @param pCmdHlp Pointer to the command callback structure. + * @param pCmd The failing command. + * @param pszFormat The error message format string. + * @param va Format arguments. + */ + DECLCALLBACKMEMBER(int, pfnFailV,(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, + const char *pszFormat, va_list va)) RT_IPRT_FORMAT_ATTR(3, 0); + + /** + * Print an error and fail the current command. + * + * @returns VBox status code to pass upwards. + * + * @param pCmdHlp Pointer to the command callback structure. + * @param pCmd The failing command. + * @param rc The status code indicating the failure. This will + * be appended to the message after a colon (': '). + * @param pszFormat The error message format string. + * @param va Format arguments. + * + * @see DBGCCmdHlpFailRc + */ + DECLCALLBACKMEMBER(int, pfnFailRcV,(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int rc, + const char *pszFormat, va_list va)) RT_IPRT_FORMAT_ATTR(4, 0); + + /** + * Parser error. + * + * @returns VBox status code to pass upwards. + * + * @param pCmdHlp Pointer to the command callback structure. + * @param pCmd The failing command, can be NULL but shouldn't. + * @param iArg The offending argument, -1 when lazy. + * @param pszExpr The expression. + * @param iLine The line number. + */ + DECLCALLBACKMEMBER(int, pfnParserError,(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int iArg, const char *pszExpr, unsigned iLine)); + + /** + * Converts a DBGC variable to a DBGF address structure. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pVar The variable to convert. + * @param pAddress The target address. + */ + DECLCALLBACKMEMBER(int, pfnVarToDbgfAddr,(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress)); + + /** + * Converts a DBGF address structure to a DBGC variable. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pAddress The source address. + * @param pResult The result variable. + */ + DECLCALLBACKMEMBER(int, pfnVarFromDbgfAddr,(PDBGCCMDHLP pCmdHlp, PCDBGFADDRESS pAddress, PDBGCVAR pResult)); + + /** + * Converts a DBGC variable to a 64-bit number. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pVar The variable to convert. + * @param pu64Number Where to store the number. + */ + DECLCALLBACKMEMBER(int, pfnVarToNumber,(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t *pu64Number)); + + /** + * Converts a DBGC variable to a boolean. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pVar The variable to convert. + * @param pf Where to store the boolean. + */ + DECLCALLBACKMEMBER(int, pfnVarToBool,(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf)); + + /** + * Get the range of a variable in bytes, resolving symbols if necessary. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pVar The variable to convert. + * @param cbElement Conversion factor for element ranges. + * @param cbDefault The default range. + * @param pcbRange The length of the range. + */ + DECLCALLBACKMEMBER(int, pfnVarGetRange,(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t cbElement, uint64_t cbDefault, + uint64_t *pcbRange)); + + /** + * Converts a variable to one with the specified type. + * + * This preserves the range. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pVar The variable to convert. + * @param enmToType The target type. + * @param fConvSyms If @c true, then attempt to resolve symbols. + * @param pResult The output variable. Can be the same as @a pVar. + */ + DECLCALLBACKMEMBER(int, pfnVarConvert,(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, DBGCVARTYPE enmToType, bool fConvSyms, + PDBGCVAR pResult)); + + /** + * Gets a DBGF output helper that directs the output to the debugger + * console. + * + * @returns Pointer to the helper structure. + * @param pCmdHlp Pointer to the command callback structure. + */ + DECLCALLBACKMEMBER(PCDBGFINFOHLP, pfnGetDbgfOutputHlp,(PDBGCCMDHLP pCmdHlp)); + + /** + * Gets the ID currently selected CPU. + * + * @returns Current CPU ID. + * @param pCmdHlp Pointer to the command callback structure. + */ + DECLCALLBACKMEMBER(VMCPUID, pfnGetCurrentCpu,(PDBGCCMDHLP pCmdHlp)); + + /** + * Gets the mode the currently selected CPU is running in, in the current + * context. + * + * @returns Current CPU mode. + * @param pCmdHlp Pointer to the command callback structure. + */ + DECLCALLBACKMEMBER(CPUMMODE, pfnGetCpuMode,(PDBGCCMDHLP pCmdHlp)); + + /** + * Prints the register set of the given CPU. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param idCpu The CPU ID to print the register set of. + * @param f64BitMode True to dump 64-bit state, false to dump 32-bit state, + * -1 to use the current CPU mode. + * @param fTerse Flag to indicate whether to dump the complete register set. + */ + DECLCALLBACKMEMBER(int, pfnRegPrintf, (PDBGCCMDHLP pCmdHlp, VMCPUID idCpu, int f64BitMode, bool fTerse)); + + /** End marker (DBGCCMDHLP_MAGIC). */ + uint32_t u32EndMarker; +} DBGCCMDHLP; + +/** Magic value for DBGCCMDHLP::u32Magic. (Fyodor Mikhaylovich Dostoyevsky) */ +#define DBGCCMDHLP_MAGIC UINT32_C(18211111) + + +#if defined(IN_RING3) || defined(IN_SLICKEDIT) + +/** + * Command helper for writing formatted text to the debug console. + * + * @returns VBox status. + * @param pCmdHlp Pointer to the command callback structure. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param ... Arguments specified in the format string. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(2, 3) DBGCCmdHlpPrintf(PDBGCCMDHLP pCmdHlp, const char *pszFormat, ...) +{ + va_list va; + int rc; + + va_start(va, pszFormat); + rc = pCmdHlp->pfnPrintfV(pCmdHlp, NULL, pszFormat, va); + va_end(va); + + return rc; +} + +/** + * Command helper for writing formatted text to the debug console. + * + * @returns VBox status. + * @param pCmdHlp Pointer to the command callback structure. + * @param pcbWritten Where to store the amount of written characters on success. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param ... Arguments specified in the format string. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(3, 4) DBGCCmdHlpPrintfEx(PDBGCCMDHLP pCmdHlp, size_t *pcbWritten, + const char *pszFormat, ...) +{ + va_list va; + int rc; + + va_start(va, pszFormat); + rc = pCmdHlp->pfnPrintfV(pCmdHlp, pcbWritten, pszFormat, va); + va_end(va); + + return rc; +} + +/** + * Command helper for writing formatted text to the debug console. + * + * @returns Number of bytes written. + * @param pCmdHlp Pointer to the command callback structure. + * @param pszFormat The format string. This may use all IPRT extensions as + * well as the debugger ones. + * @param ... Arguments specified in the format string. + */ +DECLINLINE(size_t) RT_IPRT_FORMAT_ATTR(2, 3) DBGCCmdHlpPrintfLen(PDBGCCMDHLP pCmdHlp, const char *pszFormat, ...) +{ + va_list va; + int rc; + size_t cbWritten = 0; + + va_start(va, pszFormat); + rc = pCmdHlp->pfnPrintfV(pCmdHlp, &cbWritten, pszFormat, va); + va_end(va); + + return RT_SUCCESS(rc) ? cbWritten : 0; +} + +/** + * @copydoc DBGCCMDHLP::pfnStrPrintf + */ +DECLINLINE(size_t) RT_IPRT_FORMAT_ATTR(4, 5) DBGCCmdHlpStrPrintf(PDBGCCMDHLP pCmdHlp, char *pszBuf, size_t cbBuf, + const char *pszFormat, ...) +{ + va_list va; + size_t cch; + + va_start(va, pszFormat); + cch = pCmdHlp->pfnStrPrintfV(pCmdHlp, pszBuf, cbBuf, pszFormat, va); + va_end(va); + + return cch; +} + +/** + * @copydoc DBGCCMDHLP::pfnVBoxError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(3, 4) DBGCCmdHlpVBoxError(PDBGCCMDHLP pCmdHlp, int rc, const char *pszFormat, ...) +{ + va_list va; + + va_start(va, pszFormat); + rc = pCmdHlp->pfnVBoxErrorV(pCmdHlp, rc, pszFormat, va); + va_end(va); + + return rc; +} + +/** + * @copydoc DBGCCMDHLP::pfnMemRead + */ +DECLINLINE(int) DBGCCmdHlpMemRead(PDBGCCMDHLP pCmdHlp, void *pvBuffer, size_t cbRead, PCDBGCVAR pVarPointer, size_t *pcbRead) +{ + return pCmdHlp->pfnMemRead(pCmdHlp, pvBuffer, cbRead, pVarPointer, pcbRead); +} + +/** + * Evaluates an expression. + * (Hopefully the parser and functions are fully reentrant.) + * + * @returns VBox status code appropriate to return from a command. + * @param pCmdHlp Pointer to the command callback structure. + * @param pResult Where to store the result. + * @param pszExpr The expression. Format string with the format DBGC extensions. + * @param ... Format arguments. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(3, 4) DBGCCmdHlpEval(PDBGCCMDHLP pCmdHlp, PDBGCVAR pResult, const char *pszExpr, ...) +{ + va_list va; + int rc; + + va_start(va, pszExpr); + rc = pCmdHlp->pfnEvalV(pCmdHlp, pResult, pszExpr, va); + va_end(va); + + return rc; +} + +/** + * Print an error and fail the current command. + * + * @returns VBox status code to pass upwards. + * + * @param pCmdHlp Pointer to the command callback structure. + * @param pCmd The failing command. + * @param pszFormat The error message format string. + * @param ... Format arguments. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(3, 4) DBGCCmdHlpFail(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, const char *pszFormat, ...) +{ + va_list va; + int rc; + + va_start(va, pszFormat); + rc = pCmdHlp->pfnFailV(pCmdHlp, pCmd, pszFormat, va); + va_end(va); + + return rc; +} + +/** + * Print an error and fail the current command. + * + * Usage example: + * @code + int rc = VMMR3Something(pVM); + if (RT_FAILURE(rc)) + return DBGCCmdHlpFailRc(pCmdHlp, pCmd, rc, "VMMR3Something"); + return VINF_SUCCESS; + * @endcode + * + * @returns VBox status code to pass upwards. + * + * @param pCmdHlp Pointer to the command callback structure. + * @param pCmd The failing command. + * @param rc The status code indicating the failure. + * @param pszFormat The error message format string. + * @param ... Format arguments. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 5) DBGCCmdHlpFailRc(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int rc, + const char *pszFormat, ...) +{ + va_list va; + + va_start(va, pszFormat); + rc = pCmdHlp->pfnFailRcV(pCmdHlp, pCmd, rc, pszFormat, va); + va_end(va); + + return rc; +} + +/** + * @copydoc DBGCCMDHLP::pfnParserError + */ +DECLINLINE(int) DBGCCmdHlpParserError(PDBGCCMDHLP pCmdHlp, PCDBGCCMD pCmd, int iArg, const char *pszExpr, unsigned iLine) +{ + return pCmdHlp->pfnParserError(pCmdHlp, pCmd, iArg, pszExpr, iLine); +} + +/** Assert+return like macro for checking parser sanity. + * Returns with failure if the precodition is not met. */ +#define DBGC_CMDHLP_ASSERT_PARSER_RET(pCmdHlp, pCmd, iArg, expr) \ + do { \ + if (!(expr)) \ + return DBGCCmdHlpParserError(pCmdHlp, pCmd, iArg, #expr, __LINE__); \ + } while (0) + +/** Assert+return like macro that the VM handle is present. + * Returns with failure if the VM handle is NIL. */ +#define DBGC_CMDHLP_REQ_UVM_RET(pCmdHlp, pCmd, pUVM) \ + do { \ + if (!(pUVM)) \ + return DBGCCmdHlpFail(pCmdHlp, pCmd, "No VM selected"); \ + } while (0) + +/** + * @copydoc DBGCCMDHLP::pfnVarToDbgfAddr + */ +DECLINLINE(int) DBGCCmdHlpVarToDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PDBGFADDRESS pAddress) +{ + return pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, pVar, pAddress); +} + +/** + * @copydoc DBGCCMDHLP::pfnVarFromDbgfAddr + */ +DECLINLINE(int) DBGCCmdHlpVarFromDbgfAddr(PDBGCCMDHLP pCmdHlp, PCDBGFADDRESS pAddress, PDBGCVAR pResult) +{ + return pCmdHlp->pfnVarFromDbgfAddr(pCmdHlp, pAddress, pResult); +} + +/** + * Converts an variable to a flat address. + * + * @returns VBox status code. + * @param pCmdHlp Pointer to the command callback structure. + * @param pVar The variable to convert. + * @param pFlatPtr Where to store the flat address. + */ +DECLINLINE(int) DBGCCmdHlpVarToFlatAddr(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, PRTGCPTR pFlatPtr) +{ + DBGFADDRESS Addr; + int rc = pCmdHlp->pfnVarToDbgfAddr(pCmdHlp, pVar, &Addr); + if (RT_SUCCESS(rc)) + *pFlatPtr = Addr.FlatPtr; + return rc; +} + +/** + * @copydoc DBGCCMDHLP::pfnVarToNumber + */ +DECLINLINE(int) DBGCCmdHlpVarToNumber(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t *pu64Number) +{ + return pCmdHlp->pfnVarToNumber(pCmdHlp, pVar, pu64Number); +} + +/** + * @copydoc DBGCCMDHLP::pfnVarToBool + */ +DECLINLINE(int) DBGCCmdHlpVarToBool(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, bool *pf) +{ + return pCmdHlp->pfnVarToBool(pCmdHlp, pVar, pf); +} + +/** + * @copydoc DBGCCMDHLP::pfnVarGetRange + */ +DECLINLINE(int) DBGCCmdHlpVarGetRange(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, uint64_t cbElement, uint64_t cbDefault, uint64_t *pcbRange) +{ + return pCmdHlp->pfnVarGetRange(pCmdHlp, pVar, cbElement, cbDefault, pcbRange); +} + +/** + * @copydoc DBGCCMDHLP::pfnVarConvert + */ +DECLINLINE(int) DBGCCmdHlpConvert(PDBGCCMDHLP pCmdHlp, PCDBGCVAR pVar, DBGCVARTYPE enmToType, bool fConvSyms, PDBGCVAR pResult) +{ + return pCmdHlp->pfnVarConvert(pCmdHlp, pVar, enmToType, fConvSyms, pResult); +} + +/** + * @copydoc DBGCCMDHLP::pfnGetDbgfOutputHlp + */ +DECLINLINE(PCDBGFINFOHLP) DBGCCmdHlpGetDbgfOutputHlp(PDBGCCMDHLP pCmdHlp) +{ + return pCmdHlp->pfnGetDbgfOutputHlp(pCmdHlp); +} + +/** + * @copydoc DBGCCMDHLP::pfnGetCurrentCpu + */ +DECLINLINE(VMCPUID) DBGCCmdHlpGetCurrentCpu(PDBGCCMDHLP pCmdHlp) +{ + return pCmdHlp->pfnGetCurrentCpu(pCmdHlp); +} + +/** + * @copydoc DBGCCMDHLP::pfnGetCpuMode + */ +DECLINLINE(CPUMMODE) DBGCCmdHlpGetCpuMode(PDBGCCMDHLP pCmdHlp) +{ + return pCmdHlp->pfnGetCpuMode(pCmdHlp); +} + +/** + * @copydoc DBGCCMDHLP::pfnRegPrintf + */ +DECLINLINE(int) DBGCCmdHlpRegPrintf(PDBGCCMDHLP pCmdHlp, VMCPUID idCpu, int f64BitMode, bool fTerse) +{ + return pCmdHlp->pfnRegPrintf(pCmdHlp, idCpu, f64BitMode, fTerse); +} + +#endif /* IN_RING3 */ + + + +/** + * Command handler. + * + * The console will call the handler for a command once it's finished + * parsing the user input. The command handler function is responsible + * for executing the command itself. + * + * @returns VBox status. + * @param pCmd Pointer to the command descriptor (as registered). + * @param pCmdHlp Pointer to command helper functions. + * @param pUVM The user mode VM handle, can in theory be NULL. + * @param paArgs Pointer to (readonly) array of arguments. + * @param cArgs Number of arguments in the array. + */ +typedef DECLCALLBACKTYPE(int, FNDBGCCMD,(PCDBGCCMD pCmd, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs)); +/** Pointer to a FNDBGCCMD() function. */ +typedef FNDBGCCMD *PFNDBGCCMD; + +/** + * DBGC command descriptor. + */ +typedef struct DBGCCMD +{ + /** Command string. */ + const char *pszCmd; + /** Minimum number of arguments. */ + unsigned cArgsMin; + /** Max number of arguments. */ + unsigned cArgsMax; + /** Argument descriptors (array). */ + PCDBGCVARDESC paArgDescs; + /** Number of argument descriptors. */ + unsigned cArgDescs; + /** flags. (reserved for now) */ + unsigned fFlags; + /** Handler function. */ + PFNDBGCCMD pfnHandler; + /** Command syntax. */ + const char *pszSyntax; + /** Command description. */ + const char *pszDescription; +} DBGCCMD; + +/** DBGCCMD Flags. + * @{ + */ +/** @} */ + + +/** + * Function handler. + * + * The console will call the handler for a command once it's finished + * parsing the user input. The command handler function is responsible + * for executing the command itself. + * + * @returns VBox status. + * @param pFunc Pointer to the function descriptor (as registered). + * @param pCmdHlp Pointer to command helper functions. + * @param pUVM The user mode VM handle, can in theory be NULL. + * @param paArgs Pointer to (readonly) array of arguments. + * @param cArgs Number of arguments in the array. + * @param pResult Where to return the result. + */ +typedef DECLCALLBACKTYPE(int, FNDBGCFUNC,(PCDBGCFUNC pFunc, PDBGCCMDHLP pCmdHlp, PUVM pUVM, PCDBGCVAR paArgs, unsigned cArgs, + PDBGCVAR pResult)); +/** Pointer to a FNDBGCFUNC() function. */ +typedef FNDBGCFUNC *PFNDBGCFUNC; + +/** + * DBGC function descriptor. + */ +typedef struct DBGCFUNC +{ + /** Command string. */ + const char *pszFuncNm; + /** Minimum number of arguments. */ + unsigned cArgsMin; + /** Max number of arguments. */ + unsigned cArgsMax; + /** Argument descriptors (array). */ + PCDBGCVARDESC paArgDescs; + /** Number of argument descriptors. */ + unsigned cArgDescs; + /** flags. (reserved for now) */ + unsigned fFlags; + /** Handler function. */ + PFNDBGCFUNC pfnHandler; + /** Function syntax. */ + const char *pszSyntax; + /** Function description. */ + const char *pszDescription; +} DBGCFUNC; + + +/** Pointer to a const I/O callback table. */ +typedef const struct DBGCIO *PCDBGCIO; + +/** + * I/O callback table. + */ +typedef struct DBGCIO +{ + /** + * Destroys the given I/O instance. + * + * @returns nothing. + * @param pIo Pointer to the I/O structure supplied by the I/O provider. + */ + DECLCALLBACKMEMBER(void, pfnDestroy, (PCDBGCIO pIo)); + + /** + * Wait for input available for reading. + * + * @returns Flag whether there is input ready upon return. + * @retval true if there is input ready. + * @retval false if there not input ready. + * @param pIo Pointer to the I/O structure supplied by + * the I/O provider. The backend can use this to find it's instance data. + * @param cMillies Number of milliseconds to wait on input data. + */ + DECLCALLBACKMEMBER(bool, pfnInput, (PCDBGCIO pIo, uint32_t cMillies)); + + /** + * Read input. + * + * @returns VBox status code. + * @param pIo Pointer to the I/O structure supplied by + * the I/O provider. The backend can use this to find it's instance data. + * @param pvBuf Where to put the bytes we read. + * @param cbBuf Maximum nymber of bytes to read. + * @param pcbRead Where to store the number of bytes actually read. + * If NULL the entire buffer must be filled for a + * successful return. + */ + DECLCALLBACKMEMBER(int, pfnRead, (PCDBGCIO pIo, void *pvBuf, size_t cbBuf, size_t *pcbRead)); + + /** + * Write (output). + * + * @returns VBox status code. + * @param pIo Pointer to the I/O structure supplied by + * the I/O provider. The backend can use this to find it's instance data. + * @param pvBuf What to write. + * @param cbBuf Number of bytes to write. + * @param pcbWritten Where to store the number of bytes actually written. + * If NULL the entire buffer must be successfully written. + */ + DECLCALLBACKMEMBER(int, pfnWrite, (PCDBGCIO pIo, const void *pvBuf, size_t cbBuf, size_t *pcbWritten)); + + /** + * Marks the beginning of a new packet being sent - optional. + * + * @returns VBox status code. + * @param pIo Pointer to the I/O structure supplied by + * the I/O provider. The backend can use this to find it's instance data. + * @param cbPktHint Size of the packet in bytes, serves as a hint for the I/O provider to arrange buffers. + * Give 0 if size is unknown upfront. + */ + DECLCALLBACKMEMBER(int, pfnPktBegin, (PCDBGCIO pIo, size_t cbPktHint)); + + /** + * Marks the end of the packet - optional. + * + * @returns VBox status code. + * @param pIo Pointer to the I/O structure supplied by + * the I/O provider. The backend can use this to find it's instance data. + * + * @note Some I/O providers might decide to send data only when this is called not in the + * DBGCIO::pfnWrite callback. + */ + DECLCALLBACKMEMBER(int, pfnPktEnd, (PCDBGCIO pIo)); + + /** + * Ready / busy notification. + * + * @returns nothing. + * @param pIo Pointer to the I/O structure supplied by + * the I/O provider. The backend can use this to find it's instance data. + * @param fReady Whether it's ready (true) or busy (false). + */ + DECLCALLBACKMEMBER(void, pfnSetReady, (PCDBGCIO pIo, bool fReady)); + +} DBGCIO; +/** Pointer to an I/O callback table. */ +typedef DBGCIO *PDBGCIO; + + +DBGDECL(int) DBGCCreate(PUVM pUVM, PCDBGCIO pIo, unsigned fFlags); +DBGDECL(int) DBGCRegisterCommands(PCDBGCCMD paCommands, unsigned cCommands); +DBGDECL(int) DBGCDeregisterCommands(PCDBGCCMD paCommands, unsigned cCommands); + +DBGDECL(int) DBGCIoCreate(PUVM pUVM, void **ppvData); +DBGDECL(int) DBGCIoTerminate(PUVM pUVM, void *pvData); + +/** @} */ + +#endif /* IN_RING3 */ + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_dbg_h */ diff --git a/include/VBox/dbggui.h b/include/VBox/dbggui.h new file mode 100644 index 00000000..88c0b46d --- /dev/null +++ b/include/VBox/dbggui.h @@ -0,0 +1,191 @@ +/** @file + * DBGGUI - The VirtualBox Debugger GUI. (VBoxDbg) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_dbggui_h +#define VBOX_INCLUDED_dbggui_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_dbggui VirtualBox Debugger GUI + * @ingroup grp_dbg + * @{ + */ + +#ifdef RT_OS_WINDOWS +struct ISession; +#else +class ISession; +#endif + +/** Pointer to the debugger GUI instance structure. */ +typedef struct DBGGUI *PDBGGUI; + +/** Virtual method table for the debugger GUI. */ +typedef struct DBGGUIVT +{ + /** The version. (DBGGUIVT_VERSION) */ + uint32_t u32Version; + /** @copydoc DBGGuiDestroy */ + DECLCALLBACKMEMBER(int, pfnDestroy,(PDBGGUI pGui)); + /** @copydoc DBGGuiAdjustRelativePos */ + DECLCALLBACKMEMBER(void, pfnAdjustRelativePos,(PDBGGUI pGui, int x, int y, unsigned cx, unsigned cy)); + /** @copydoc DBGGuiShowStatistics */ + DECLCALLBACKMEMBER(int, pfnShowStatistics,(PDBGGUI pGui, const char *pszFilter, const char *pszExpand)); + /** @copydoc DBGGuiShowCommandLine */ + DECLCALLBACKMEMBER(int, pfnShowCommandLine,(PDBGGUI pGui)); + /** @copydoc DBGGuiSetParent */ + DECLCALLBACKMEMBER(void, pfnSetParent,(PDBGGUI pGui, void *pvParent)); + /** @copydoc DBGGuiSetMenu */ + DECLCALLBACKMEMBER(void, pfnSetMenu,(PDBGGUI pGui, void *pvMenu)); + /** The end version. (DBGGUIVT_VERSION) */ + uint32_t u32EndVersion; +} DBGGUIVT; +/** Pointer to the virtual method table for the debugger GUI. */ +typedef DBGGUIVT const *PCDBGGUIVT; +/** The u32Version value. + * The first byte is the minor version, the 2nd byte is major version number. + * The high 16-bit word is a magic. */ +#define DBGGUIVT_VERSION UINT32_C(0xbead0200) +/** Macro for determining whether two versions are compatible or not. + * @returns boolean result. + * @param uVer1 The first version number. + * @param uVer2 The second version number. + */ +#define DBGGUIVT_ARE_VERSIONS_COMPATIBLE(uVer1, uVer2) \ + ( ((uVer1) & UINT32_C(0xffffff00)) == ((uVer2) & UINT32_C(0xffffff00)) ) + + +/** + * Creates the debugger GUI. + * + * @returns VBox status code. + * @param pSession The VirtualBox session. + * @param ppGui Where to store the pointer to the debugger instance. + * @param ppGuiVT Where to store the virtual method table pointer. + * Optional. + */ +DBGDECL(int) DBGGuiCreate(ISession *pSession, PDBGGUI *ppGui, PCDBGGUIVT *ppGuiVT); +/** @copydoc DBGGuiCreate */ +typedef DECLCALLBACKTYPE(int, FNDBGGUICREATE,(ISession *pSession, PDBGGUI *ppGui, PCDBGGUIVT *ppGuiVT)); +/** Pointer to DBGGuiCreate. */ +typedef FNDBGGUICREATE *PFNDBGGUICREATE; + +/** + * Creates the debugger GUI given a VM handle. + * + * @returns VBox status code. + * @param pUVM The VM handle. + * @param pVMM The VMM function table. + * @param ppGui Where to store the pointer to the debugger instance. + * @param ppGuiVT Where to store the virtual method table pointer. + * Optional. + */ +DBGDECL(int) DBGGuiCreateForVM(PUVM pUVM, PCVMMR3VTABLE pVMM, PDBGGUI *ppGui, PCDBGGUIVT *ppGuiVT); +/** @copydoc DBGGuiCreateForVM */ +typedef DECLCALLBACKTYPE(int, FNDBGGUICREATEFORVM,(PUVM pUVM, PCVMMR3VTABLE pVMM, PDBGGUI *ppGui, PCDBGGUIVT *ppGuiVT)); +/** Pointer to DBGGuiCreateForVM. */ +typedef FNDBGGUICREATEFORVM *PFNDBGGUICREATEFORVM; + +/** + * Destroys the debugger GUI. + * + * @returns VBox status code. + * @param pGui The instance returned by DBGGuiCreate(). + */ +DBGDECL(int) DBGGuiDestroy(PDBGGUI pGui); + +/** + * Notifies the debugger GUI that the console window (or whatever) has changed + * size or position. + * + * @param pGui The instance returned by DBGGuiCreate(). + * @param x The x-coordinate of the window the debugger is relative to. + * @param y The y-coordinate of the window the debugger is relative to. + * @param cx The width of the window the debugger is relative to. + * @param cy The height of the window the debugger is relative to. + */ +DBGDECL(void) DBGGuiAdjustRelativePos(PDBGGUI pGui, int x, int y, unsigned cx, unsigned cy); + +/** + * Shows the default statistics window. + * + * @returns VBox status code. + * @param pGui The instance returned by DBGGuiCreate(). + * @param pszFilter Filter pattern. + * @param pszExpand Expand pattern. + */ +DBGDECL(int) DBGGuiShowStatistics(PDBGGUI pGui, const char *pszFilter, const char *pszExpand); + +/** + * Shows the default command line window. + * + * @returns VBox status code. + * @param pGui The instance returned by DBGGuiCreate(). + */ +DBGDECL(int) DBGGuiShowCommandLine(PDBGGUI pGui); + +/** + * Sets the parent windows. + * + * @param pGui The instance returned by DBGGuiCreate(). + * @param pvParent Pointer to a QWidget object. + * + * @remarks This will no affect any existing windows, so call it right after + * creating the thing. + */ +DBGDECL(void) DBGGuiSetParent(PDBGGUI pGui, void *pvParent); + +/** + * Sets the debug menu object. + * + * @param pGui The instance returned by DBGGuiCreate(). + * @param pvMenu Pointer to a QMenu object. + * + * @remarks Call right after creation or risk losing menu item. + */ +DBGDECL(void) DBGGuiSetMenu(PDBGGUI pGui, void *pvMenu); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_dbggui_h */ + diff --git a/include/VBox/dbus-calls.h b/include/VBox/dbus-calls.h new file mode 100644 index 00000000..4b9cfadb --- /dev/null +++ b/include/VBox/dbus-calls.h @@ -0,0 +1,180 @@ +/** @file + * Stubs for dynamically loading libdbus-1 and the symbols which are needed by + * VirtualBox. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/** The file name of the DBus library */ +#define RT_RUNTIME_LOADER_LIB_NAME "libdbus-1.so.3" + +/** The name of the loader function */ +#define RT_RUNTIME_LOADER_FUNCTION RTDBusLoadLib + +/** The following are the symbols which we need from the DBus library. */ +#define RT_RUNTIME_LOADER_INSERT_SYMBOLS \ + RT_PROXY_STUB(dbus_error_init, void, (DBusError *error), \ + (error)) \ + RT_PROXY_STUB(dbus_error_is_set, dbus_bool_t, (const DBusError *error), \ + (error)) \ + RT_PROXY_STUB(dbus_bus_get, DBusConnection *, \ + (DBusBusType type, DBusError *error), (type, error)) \ + RT_PROXY_STUB(dbus_bus_get_private, DBusConnection *, \ + (DBusBusType type, DBusError *error), (type, error)) \ + RT_PROXY_STUB(dbus_error_free, void, (DBusError *error), \ + (error)) \ + RT_PROXY_STUB(dbus_free_string_array, void, (char **str_array), \ + (str_array)) \ + RT_PROXY_STUB(dbus_connection_ref, DBusConnection *, (DBusConnection *connection), \ + (connection)) \ + RT_PROXY_STUB(dbus_connection_unref, void, (DBusConnection *connection), \ + (connection)) \ + RT_PROXY_STUB(dbus_connection_close, void, (DBusConnection *connection), \ + (connection)) \ + RT_PROXY_STUB(dbus_connection_send, dbus_bool_t, \ + (DBusConnection *connection, DBusMessage *message, dbus_uint32_t *serial), \ + (connection, message, serial)) \ + RT_PROXY_STUB(dbus_connection_flush, void, (DBusConnection *connection), \ + (connection)) \ + RT_PROXY_STUB(dbus_connection_set_exit_on_disconnect, void, \ + (DBusConnection *connection, dbus_bool_t boolean), \ + (connection, boolean)) \ + RT_PROXY_STUB(dbus_bus_name_has_owner, dbus_bool_t, \ + (DBusConnection *connection, const char *string, DBusError *error), \ + (connection, string, error)) \ + RT_PROXY_STUB(dbus_bus_add_match, void, \ + (DBusConnection *connection, const char *string, \ + DBusError *error), \ + (connection, string, error)) \ + RT_PROXY_STUB(dbus_bus_remove_match, void, \ + (DBusConnection *connection, const char *string, \ + DBusError *error), \ + (connection, string, error)) \ + RT_PROXY_STUB(dbus_message_append_args_valist, dbus_bool_t, \ + (DBusMessage *message, int first_arg_type, va_list var_args), \ + (message, first_arg_type, var_args)) \ + RT_PROXY_STUB(dbus_message_get_args_valist, dbus_bool_t, \ + (DBusMessage *message, DBusError *error, int first_arg_type, va_list var_args), \ + (message, error, first_arg_type, var_args)) \ + RT_PROXY_STUB(dbus_message_get_type, int, \ + (DBusMessage *message), \ + (message)) \ + RT_PROXY_STUB(dbus_message_iter_open_container, dbus_bool_t, \ + (DBusMessageIter *iter, int type, const char *contained_signature, DBusMessageIter *sub), \ + (iter, type, contained_signature, sub)) \ + RT_PROXY_STUB(dbus_message_iter_close_container, dbus_bool_t, \ + (DBusMessageIter *iter, DBusMessageIter *sub), \ + (iter, sub)) \ + RT_PROXY_STUB(dbus_message_iter_append_fixed_array, dbus_bool_t, \ + (DBusMessageIter *iter, int element_type, const void *value, int n_elements), \ + (iter, element_type, value, n_elements)) \ + RT_PROXY_STUB(dbus_message_unref, void, (DBusMessage *message), \ + (message)) \ + RT_PROXY_STUB(dbus_message_new_method_call, DBusMessage*, \ + (const char *string1, const char *string2, const char *string3, \ + const char *string4), \ + (string1, string2, string3, string4)) \ + RT_PROXY_STUB(dbus_message_iter_init_append, void, \ + (DBusMessage *message, DBusMessageIter *iter), \ + (message, iter)) \ + RT_PROXY_STUB(dbus_message_iter_append_basic, dbus_bool_t, \ + (DBusMessageIter *iter, int val, const void *string), \ + (iter, val, string)) \ + RT_PROXY_STUB(dbus_connection_send_with_reply_and_block, DBusMessage *, \ + (DBusConnection *connection, DBusMessage *message, int val, \ + DBusError *error), \ + (connection, message, val, error)) \ + RT_PROXY_STUB(dbus_message_iter_init, dbus_bool_t, \ + (DBusMessage *message, DBusMessageIter *iter), \ + (message, iter)) \ + RT_PROXY_STUB(dbus_message_get_signature, char *, (DBusMessage *message), \ + (message)) \ + RT_PROXY_STUB(dbus_message_iter_get_signature, char *, (DBusMessageIter *iter), \ + (iter)) \ + RT_PROXY_STUB(dbus_message_iter_get_arg_type, int, (DBusMessageIter *iter), \ + (iter)) \ + RT_PROXY_STUB(dbus_message_iter_get_element_type, int, \ + (DBusMessageIter *iter), (iter)) \ + RT_PROXY_STUB(dbus_message_iter_recurse, void, \ + (DBusMessageIter *iter1, DBusMessageIter *iter2), \ + (iter1, iter2)) \ + RT_PROXY_STUB(dbus_message_iter_get_basic, void, \ + (DBusMessageIter *iter, void *pvoid), (iter, pvoid)) \ + RT_PROXY_STUB(dbus_message_iter_has_next, dbus_bool_t, \ + (DBusMessageIter *iter), (iter)) \ + RT_PROXY_STUB(dbus_message_iter_next, dbus_bool_t, (DBusMessageIter *iter), \ + (iter)) \ + RT_PROXY_STUB(dbus_message_iter_abandon_container_if_open, void, \ + (DBusMessageIter *iter, DBusMessageIter *sub), (iter, sub)) \ + RT_PROXY_STUB(dbus_connection_add_filter, dbus_bool_t, \ + (DBusConnection *connection, \ + DBusHandleMessageFunction function1, void *pvoid, \ + DBusFreeFunction function2), \ + (connection, function1, pvoid, function2)) \ + RT_PROXY_STUB(dbus_connection_remove_filter, void, \ + (DBusConnection *connection, \ + DBusHandleMessageFunction function, void *pvoid), \ + (connection, function, pvoid)) \ + RT_PROXY_STUB(dbus_connection_read_write, dbus_bool_t, \ + (DBusConnection *connection, int val), (connection, val)) \ + RT_PROXY_STUB(dbus_connection_read_write_dispatch, dbus_bool_t, \ + (DBusConnection *connection, int val), (connection, val)) \ + RT_PROXY_STUB(dbus_message_is_signal, dbus_bool_t, \ + (DBusMessage *message, const char *string1, \ + const char *string2), \ + (message, string1, string2)) \ + RT_PROXY_STUB(dbus_connection_pop_message, DBusMessage *, \ + (DBusConnection *connection), (connection)) \ + RT_PROXY_STUB(dbus_set_error_from_message, dbus_bool_t, \ + (DBusError *error, DBusMessage *message), (error, message)) \ + RT_PROXY_STUB(dbus_free, void, \ + (void *memory), (memory)) + +#ifdef VBOX_DBUS_GENERATE_HEADER +# define RT_RUNTIME_LOADER_GENERATE_HEADER +# define RT_RUNTIME_LOADER_GENERATE_DECLS +# include +# undef RT_RUNTIME_LOADER_GENERATE_HEADER +# undef RT_RUNTIME_LOADER_GENERATE_DECLS + +#elif defined(VBOX_DBUS_GENERATE_BODY) +# define RT_RUNTIME_LOADER_GENERATE_BODY_STUBS +# include +# undef RT_RUNTIME_LOADER_GENERATE_BODY_STUBS + +#else +# error This file should only be included to generate stubs for loading the DBus library at runtime +#endif + +#undef RT_RUNTIME_LOADER_LIB_NAME +#undef RT_RUNTIME_LOADER_INSERT_SYMBOLS + diff --git a/include/VBox/dbus.h b/include/VBox/dbus.h new file mode 100644 index 00000000..1b3993c1 --- /dev/null +++ b/include/VBox/dbus.h @@ -0,0 +1,139 @@ +/** @file + * Module to dynamically load libdbus and load all symbols which are needed by + * VirtualBox. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_dbus_h +#define VBOX_INCLUDED_dbus_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +#ifndef __cplusplus +# error "This header requires C++ to avoid name clashes." +#endif + +/** Types and defines from the dbus header files which we need. These are + * taken more or less verbatim from the DBus public interface header files. */ +struct DBusError +{ + const char *name; + const char *message; + unsigned int dummy1 : 1; + unsigned int dummy2 : 1; + unsigned int dummy3 : 1; + unsigned int dummy4 : 1; + unsigned int dummy5 : 1; + void *padding1; +}; +typedef struct DBusError DBusError; + +struct DBusConnection; +typedef struct DBusConnection DBusConnection; + +typedef uint32_t dbus_bool_t; +typedef uint32_t dbus_uint32_t; +typedef enum { DBUS_BUS_SESSION, DBUS_BUS_SYSTEM, DBUS_BUS_STARTER } DBusBusType; + +struct DBusMessage; +typedef struct DBusMessage DBusMessage; + +struct DBusMessageIter +{ + void *dummy1; + void *dummy2; + dbus_uint32_t dummy3; + int dummy4; + int dummy5; + int dummy6; + int dummy7; + int dummy8; + int dummy9; + int dummy10; + int dummy11; + int pad1; + int pad2; + void *pad3; +}; +typedef struct DBusMessageIter DBusMessageIter; + +#define DBUS_ERROR_NO_MEMORY "org.freedesktop.DBus.Error.NoMemory" + +/* Message types. */ +#define DBUS_MESSAGE_TYPE_INVALID 0 +#define DBUS_MESSAGE_TYPE_METHOD_CALL 1 +#define DBUS_MESSAGE_TYPE_METHOD_RETURN 2 +#define DBUS_MESSAGE_TYPE_ERROR 3 +#define DBUS_MESSAGE_TYPE_SIGNAL 4 + +/* Primitive types. */ +#define DBUS_TYPE_INVALID ((int) '\0') +#define DBUS_TYPE_BOOLEAN ((int) 'b') +#define DBUS_TYPE_INT32 ((int) 'i') +#define DBUS_TYPE_UINT32 ((int) 'u') +#define DBUS_TYPE_DOUBLE ((int) 'd') +#define DBUS_TYPE_STRING ((int) 's') +#define DBUS_TYPE_STRING_AS_STRING "s" + +/* Compound types. */ +#define DBUS_TYPE_OBJECT_PATH ((int) 'o') +#define DBUS_TYPE_ARRAY ((int) 'a') +#define DBUS_TYPE_ARRAY_AS_STRING "a" +#define DBUS_TYPE_DICT_ENTRY ((int) 'e') +#define DBUS_TYPE_DICT_ENTRY_AS_STRING "e" +#define DBUS_TYPE_STRUCT ((int) 'r') + +typedef enum +{ + DBUS_HANDLER_RESULT_HANDLED, + DBUS_HANDLER_RESULT_NOT_YET_HANDLED, + DBUS_HANDLER_RESULT_NEED_MEMORY +} DBusHandlerResult; + +typedef DBusHandlerResult (* DBusHandleMessageFunction)(DBusConnection *, + DBusMessage *, void *); +typedef void (* DBusFreeFunction) (void *); + +/* Declarations of the functions that we need from libdbus-1 */ +#define VBOX_DBUS_GENERATE_HEADER + +#include + +#undef VBOX_DBUS_GENERATE_HEADER + +#endif /* !VBOX_INCLUDED_dbus_h */ + diff --git a/include/VBox/dis.h b/include/VBox/dis.h new file mode 100644 index 00000000..f20c895e --- /dev/null +++ b/include/VBox/dis.h @@ -0,0 +1,912 @@ +/** @file + * DIS - The VirtualBox Disassembler. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_dis_h +#define VBOX_INCLUDED_dis_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_dis VBox Disassembler + * @{ */ + +/** @name Prefix byte flags (DISSTATE::fPrefix). + * @{ + */ +#define DISPREFIX_NONE UINT8_C(0x00) +/** non-default address size. */ +#define DISPREFIX_ADDRSIZE UINT8_C(0x01) +/** non-default operand size. */ +#define DISPREFIX_OPSIZE UINT8_C(0x02) +/** lock prefix. */ +#define DISPREFIX_LOCK UINT8_C(0x04) +/** segment prefix. */ +#define DISPREFIX_SEG UINT8_C(0x08) +/** rep(e) prefix (not a prefix, but we'll treat is as one). */ +#define DISPREFIX_REP UINT8_C(0x10) +/** rep(e) prefix (not a prefix, but we'll treat is as one). */ +#define DISPREFIX_REPNE UINT8_C(0x20) +/** REX prefix (64 bits) */ +#define DISPREFIX_REX UINT8_C(0x40) +/** @} */ + +/** @name VEX.Lvvvv prefix destination register flag. + * @{ + */ +#define VEX_LEN256 UINT8_C(0x01) +#define VEXREG_IS256B(x) ((x) & VEX_LEN256) +/* Convert second byte of VEX prefix to internal format */ +#define VEX_2B2INT(x) ((((x) >> 2) & 0x1f)) +#define VEX_HAS_REX_R(x) (!((x) & 0x80)) + +#define DISPREFIX_VEX_FLAG_W UINT8_C(0x01) + /** @} */ + +/** @name 64 bits prefix byte flags (DISSTATE::fRexPrefix). + * Requires VBox/disopcode.h. + * @{ + */ +#define DISPREFIX_REX_OP_2_FLAGS(a) (a - OP_PARM_REX_START) +/*#define DISPREFIX_REX_FLAGS DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX) - 0, which is no flag */ +#define DISPREFIX_REX_FLAGS_B DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_B) +#define DISPREFIX_REX_FLAGS_X DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_X) +#define DISPREFIX_REX_FLAGS_XB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_XB) +#define DISPREFIX_REX_FLAGS_R DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_R) +#define DISPREFIX_REX_FLAGS_RB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_RB) +#define DISPREFIX_REX_FLAGS_RX DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_RX) +#define DISPREFIX_REX_FLAGS_RXB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_RXB) +#define DISPREFIX_REX_FLAGS_W DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_W) +#define DISPREFIX_REX_FLAGS_WB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WB) +#define DISPREFIX_REX_FLAGS_WX DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WX) +#define DISPREFIX_REX_FLAGS_WXB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WXB) +#define DISPREFIX_REX_FLAGS_WR DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WR) +#define DISPREFIX_REX_FLAGS_WRB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WRB) +#define DISPREFIX_REX_FLAGS_WRX DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WRX) +#define DISPREFIX_REX_FLAGS_WRXB DISPREFIX_REX_OP_2_FLAGS(OP_PARM_REX_WRXB) +/** @} */ +AssertCompile(RT_IS_POWER_OF_TWO(DISPREFIX_REX_FLAGS_B)); +AssertCompile(RT_IS_POWER_OF_TWO(DISPREFIX_REX_FLAGS_X)); +AssertCompile(RT_IS_POWER_OF_TWO(DISPREFIX_REX_FLAGS_W)); +AssertCompile(RT_IS_POWER_OF_TWO(DISPREFIX_REX_FLAGS_R)); + +/** @name Operand type (DISOPCODE::fOpType). + * @{ + */ +#define DISOPTYPE_INVALID RT_BIT_32(0) +#define DISOPTYPE_HARMLESS RT_BIT_32(1) +#define DISOPTYPE_CONTROLFLOW RT_BIT_32(2) +#define DISOPTYPE_POTENTIALLY_DANGEROUS RT_BIT_32(3) +#define DISOPTYPE_DANGEROUS RT_BIT_32(4) +#define DISOPTYPE_PORTIO RT_BIT_32(5) +#define DISOPTYPE_PRIVILEGED RT_BIT_32(6) +#define DISOPTYPE_PRIVILEGED_NOTRAP RT_BIT_32(7) +#define DISOPTYPE_UNCOND_CONTROLFLOW RT_BIT_32(8) +#define DISOPTYPE_RELATIVE_CONTROLFLOW RT_BIT_32(9) +#define DISOPTYPE_COND_CONTROLFLOW RT_BIT_32(10) +#define DISOPTYPE_INTERRUPT RT_BIT_32(11) +#define DISOPTYPE_ILLEGAL RT_BIT_32(12) +#define DISOPTYPE_RRM_DANGEROUS RT_BIT_32(14) /**< Some additional dangerous ones when recompiling raw r0. */ +#define DISOPTYPE_RRM_DANGEROUS_16 RT_BIT_32(15) /**< Some additional dangerous ones when recompiling 16-bit raw r0. */ +#define DISOPTYPE_RRM_MASK (DISOPTYPE_RRM_DANGEROUS | DISOPTYPE_RRM_DANGEROUS_16) +#define DISOPTYPE_INHIBIT_IRQS RT_BIT_32(16) /**< Will or can inhibit irqs (sti, pop ss, mov ss) */ +#define DISOPTYPE_PORTIO_READ RT_BIT_32(17) +#define DISOPTYPE_PORTIO_WRITE RT_BIT_32(18) +#define DISOPTYPE_INVALID_64 RT_BIT_32(19) /**< Invalid in 64 bits mode */ +#define DISOPTYPE_ONLY_64 RT_BIT_32(20) /**< Only valid in 64 bits mode */ +#define DISOPTYPE_DEFAULT_64_OP_SIZE RT_BIT_32(21) /**< Default 64 bits operand size */ +#define DISOPTYPE_FORCED_64_OP_SIZE RT_BIT_32(22) /**< Forced 64 bits operand size; regardless of prefix bytes */ +#define DISOPTYPE_REXB_EXTENDS_OPREG RT_BIT_32(23) /**< REX.B extends the register field in the opcode byte */ +#define DISOPTYPE_MOD_FIXED_11 RT_BIT_32(24) /**< modrm.mod is always 11b */ +#define DISOPTYPE_FORCED_32_OP_SIZE_X86 RT_BIT_32(25) /**< Forced 32 bits operand size; regardless of prefix bytes (only in 16 & 32 bits mode!) */ +#define DISOPTYPE_AVX RT_BIT_32(28) /**< AVX,AVX2,++ instruction. Not implemented yet! */ +#define DISOPTYPE_SSE RT_BIT_32(29) /**< SSE,SSE2,SSE3,SSE4,++ instruction. Not implemented yet! */ +#define DISOPTYPE_MMX RT_BIT_32(30) /**< MMX,MMXExt,3DNow,++ instruction. Not implemented yet! */ +#define DISOPTYPE_FPU RT_BIT_32(31) /**< FPU instruction. Not implemented yet! */ +#define DISOPTYPE_ALL UINT32_C(0xffffffff) +/** @} */ + +/** @name Parameter usage flags. + * @{ + */ +#define DISUSE_BASE RT_BIT_64(0) +#define DISUSE_INDEX RT_BIT_64(1) +#define DISUSE_SCALE RT_BIT_64(2) +#define DISUSE_REG_GEN8 RT_BIT_64(3) +#define DISUSE_REG_GEN16 RT_BIT_64(4) +#define DISUSE_REG_GEN32 RT_BIT_64(5) +#define DISUSE_REG_GEN64 RT_BIT_64(6) +#define DISUSE_REG_FP RT_BIT_64(7) +#define DISUSE_REG_MMX RT_BIT_64(8) +#define DISUSE_REG_XMM RT_BIT_64(9) +#define DISUSE_REG_YMM RT_BIT_64(10) +#define DISUSE_REG_CR RT_BIT_64(11) +#define DISUSE_REG_DBG RT_BIT_64(12) +#define DISUSE_REG_SEG RT_BIT_64(13) +#define DISUSE_REG_TEST RT_BIT_64(14) +#define DISUSE_DISPLACEMENT8 RT_BIT_64(15) +#define DISUSE_DISPLACEMENT16 RT_BIT_64(16) +#define DISUSE_DISPLACEMENT32 RT_BIT_64(17) +#define DISUSE_DISPLACEMENT64 RT_BIT_64(18) +#define DISUSE_RIPDISPLACEMENT32 RT_BIT_64(19) +#define DISUSE_IMMEDIATE8 RT_BIT_64(20) +#define DISUSE_IMMEDIATE8_REL RT_BIT_64(21) +#define DISUSE_IMMEDIATE16 RT_BIT_64(22) +#define DISUSE_IMMEDIATE16_REL RT_BIT_64(23) +#define DISUSE_IMMEDIATE32 RT_BIT_64(24) +#define DISUSE_IMMEDIATE32_REL RT_BIT_64(25) +#define DISUSE_IMMEDIATE64 RT_BIT_64(26) +#define DISUSE_IMMEDIATE64_REL RT_BIT_64(27) +#define DISUSE_IMMEDIATE_ADDR_0_32 RT_BIT_64(28) +#define DISUSE_IMMEDIATE_ADDR_16_32 RT_BIT_64(29) +#define DISUSE_IMMEDIATE_ADDR_0_16 RT_BIT_64(30) +#define DISUSE_IMMEDIATE_ADDR_16_16 RT_BIT_64(31) +/** DS:ESI */ +#define DISUSE_POINTER_DS_BASED RT_BIT_64(32) +/** ES:EDI */ +#define DISUSE_POINTER_ES_BASED RT_BIT_64(33) +#define DISUSE_IMMEDIATE16_SX8 RT_BIT_64(34) +#define DISUSE_IMMEDIATE32_SX8 RT_BIT_64(35) +#define DISUSE_IMMEDIATE64_SX8 RT_BIT_64(36) + +/** Mask of immediate use flags. */ +#define DISUSE_IMMEDIATE ( DISUSE_IMMEDIATE8 \ + | DISUSE_IMMEDIATE16 \ + | DISUSE_IMMEDIATE32 \ + | DISUSE_IMMEDIATE64 \ + | DISUSE_IMMEDIATE8_REL \ + | DISUSE_IMMEDIATE16_REL \ + | DISUSE_IMMEDIATE32_REL \ + | DISUSE_IMMEDIATE64_REL \ + | DISUSE_IMMEDIATE_ADDR_0_32 \ + | DISUSE_IMMEDIATE_ADDR_16_32 \ + | DISUSE_IMMEDIATE_ADDR_0_16 \ + | DISUSE_IMMEDIATE_ADDR_16_16 \ + | DISUSE_IMMEDIATE16_SX8 \ + | DISUSE_IMMEDIATE32_SX8 \ + | DISUSE_IMMEDIATE64_SX8) +/** Check if the use flags indicates an effective address. */ +#define DISUSE_IS_EFFECTIVE_ADDR(a_fUseFlags) (!!( (a_fUseFlags) \ + & ( DISUSE_BASE \ + | DISUSE_INDEX \ + | DISUSE_DISPLACEMENT32 \ + | DISUSE_DISPLACEMENT64 \ + | DISUSE_DISPLACEMENT16 \ + | DISUSE_DISPLACEMENT8 \ + | DISUSE_RIPDISPLACEMENT32) )) +/** @} */ + +/** @name 64-bit general register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxGenReg and DISOPPARAM::Index.idxGenReg. + * @note Safe to assume same values as the 16-bit and 32-bit general registers. + * @{ + */ +#define DISGREG_RAX UINT8_C(0) +#define DISGREG_RCX UINT8_C(1) +#define DISGREG_RDX UINT8_C(2) +#define DISGREG_RBX UINT8_C(3) +#define DISGREG_RSP UINT8_C(4) +#define DISGREG_RBP UINT8_C(5) +#define DISGREG_RSI UINT8_C(6) +#define DISGREG_RDI UINT8_C(7) +#define DISGREG_R8 UINT8_C(8) +#define DISGREG_R9 UINT8_C(9) +#define DISGREG_R10 UINT8_C(10) +#define DISGREG_R11 UINT8_C(11) +#define DISGREG_R12 UINT8_C(12) +#define DISGREG_R13 UINT8_C(13) +#define DISGREG_R14 UINT8_C(14) +#define DISGREG_R15 UINT8_C(15) +/** @} */ + +/** @name 32-bit general register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxGenReg and DISOPPARAM::Index.idxGenReg. + * @note Safe to assume same values as the 16-bit and 64-bit general registers. + * @{ + */ +#define DISGREG_EAX UINT8_C(0) +#define DISGREG_ECX UINT8_C(1) +#define DISGREG_EDX UINT8_C(2) +#define DISGREG_EBX UINT8_C(3) +#define DISGREG_ESP UINT8_C(4) +#define DISGREG_EBP UINT8_C(5) +#define DISGREG_ESI UINT8_C(6) +#define DISGREG_EDI UINT8_C(7) +#define DISGREG_R8D UINT8_C(8) +#define DISGREG_R9D UINT8_C(9) +#define DISGREG_R10D UINT8_C(10) +#define DISGREG_R11D UINT8_C(11) +#define DISGREG_R12D UINT8_C(12) +#define DISGREG_R13D UINT8_C(13) +#define DISGREG_R14D UINT8_C(14) +#define DISGREG_R15D UINT8_C(15) +/** @} */ + +/** @name 16-bit general register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxGenReg and DISOPPARAM::Index.idxGenReg. + * @note Safe to assume same values as the 32-bit and 64-bit general registers. + * @{ + */ +#define DISGREG_AX UINT8_C(0) +#define DISGREG_CX UINT8_C(1) +#define DISGREG_DX UINT8_C(2) +#define DISGREG_BX UINT8_C(3) +#define DISGREG_SP UINT8_C(4) +#define DISGREG_BP UINT8_C(5) +#define DISGREG_SI UINT8_C(6) +#define DISGREG_DI UINT8_C(7) +#define DISGREG_R8W UINT8_C(8) +#define DISGREG_R9W UINT8_C(9) +#define DISGREG_R10W UINT8_C(10) +#define DISGREG_R11W UINT8_C(11) +#define DISGREG_R12W UINT8_C(12) +#define DISGREG_R13W UINT8_C(13) +#define DISGREG_R14W UINT8_C(14) +#define DISGREG_R15W UINT8_C(15) +/** @} */ + +/** @name 8-bit general register indexes. + * This mostly (?) matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxGenReg and DISOPPARAM::Index.idxGenReg. + * @{ + */ +#define DISGREG_AL UINT8_C(0) +#define DISGREG_CL UINT8_C(1) +#define DISGREG_DL UINT8_C(2) +#define DISGREG_BL UINT8_C(3) +#define DISGREG_AH UINT8_C(4) +#define DISGREG_CH UINT8_C(5) +#define DISGREG_DH UINT8_C(6) +#define DISGREG_BH UINT8_C(7) +#define DISGREG_R8B UINT8_C(8) +#define DISGREG_R9B UINT8_C(9) +#define DISGREG_R10B UINT8_C(10) +#define DISGREG_R11B UINT8_C(11) +#define DISGREG_R12B UINT8_C(12) +#define DISGREG_R13B UINT8_C(13) +#define DISGREG_R14B UINT8_C(14) +#define DISGREG_R15B UINT8_C(15) +#define DISGREG_SPL UINT8_C(16) +#define DISGREG_BPL UINT8_C(17) +#define DISGREG_SIL UINT8_C(18) +#define DISGREG_DIL UINT8_C(19) +/** @} */ + +/** @name Segment registerindexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxSegReg. + * @{ + */ +typedef enum +{ + DISSELREG_ES = 0, + DISSELREG_CS = 1, + DISSELREG_SS = 2, + DISSELREG_DS = 3, + DISSELREG_FS = 4, + DISSELREG_GS = 5, + /** End of the valid register index values. */ + DISSELREG_END, + /** The usual 32-bit paranoia. */ + DIS_SEGREG_32BIT_HACK = 0x7fffffff +} DISSELREG; +/** @} */ + +/** @name FPU register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxFpuReg. + * @{ + */ +#define DISFPREG_ST0 UINT8_C(0) +#define DISFPREG_ST1 UINT8_C(1) +#define DISFPREG_ST2 UINT8_C(2) +#define DISFPREG_ST3 UINT8_C(3) +#define DISFPREG_ST4 UINT8_C(4) +#define DISFPREG_ST5 UINT8_C(5) +#define DISFPREG_ST6 UINT8_C(6) +#define DISFPREG_ST7 UINT8_C(7) +/** @} */ + +/** @name Control register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxCtrlReg. + * @{ + */ +#define DISCREG_CR0 UINT8_C(0) +#define DISCREG_CR1 UINT8_C(1) +#define DISCREG_CR2 UINT8_C(2) +#define DISCREG_CR3 UINT8_C(3) +#define DISCREG_CR4 UINT8_C(4) +#define DISCREG_CR8 UINT8_C(8) +/** @} */ + +/** @name Debug register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxDbgReg. + * @{ + */ +#define DISDREG_DR0 UINT8_C(0) +#define DISDREG_DR1 UINT8_C(1) +#define DISDREG_DR2 UINT8_C(2) +#define DISDREG_DR3 UINT8_C(3) +#define DISDREG_DR4 UINT8_C(4) +#define DISDREG_DR5 UINT8_C(5) +#define DISDREG_DR6 UINT8_C(6) +#define DISDREG_DR7 UINT8_C(7) +/** @} */ + +/** @name MMX register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxMmxReg. + * @{ + */ +#define DISMREG_MMX0 UINT8_C(0) +#define DISMREG_MMX1 UINT8_C(1) +#define DISMREG_MMX2 UINT8_C(2) +#define DISMREG_MMX3 UINT8_C(3) +#define DISMREG_MMX4 UINT8_C(4) +#define DISMREG_MMX5 UINT8_C(5) +#define DISMREG_MMX6 UINT8_C(6) +#define DISMREG_MMX7 UINT8_C(7) +/** @} */ + +/** @name SSE register indexes. + * This matches the AMD64 register encoding. It is found used in + * DISOPPARAM::Base.idxXmmReg. + * @{ + */ +#define DISXREG_XMM0 UINT8_C(0) +#define DISXREG_XMM1 UINT8_C(1) +#define DISXREG_XMM2 UINT8_C(2) +#define DISXREG_XMM3 UINT8_C(3) +#define DISXREG_XMM4 UINT8_C(4) +#define DISXREG_XMM5 UINT8_C(5) +#define DISXREG_XMM6 UINT8_C(6) +#define DISXREG_XMM7 UINT8_C(7) +/** @} */ + + +/** + * Opcode parameter (operand) details. + */ +typedef struct DISOPPARAM +{ + /** A combination of DISUSE_XXX. */ + uint64_t fUse; + /** Immediate value or address, applicable if any of the flags included in + * DISUSE_IMMEDIATE are set in fUse. */ + uint64_t uValue; + /** Disposition. */ + union + { + /** 64-bit displacement, applicable if DISUSE_DISPLACEMENT64 is set in fUse. */ + int64_t i64; + uint64_t u64; + /** 32-bit displacement, applicable if DISUSE_DISPLACEMENT32 or + * DISUSE_RIPDISPLACEMENT32 is set in fUse. */ + int32_t i32; + uint32_t u32; + /** 16-bit displacement, applicable if DISUSE_DISPLACEMENT16 is set in fUse. */ + int32_t i16; + uint32_t u16; + /** 8-bit displacement, applicable if DISUSE_DISPLACEMENT8 is set in fUse. */ + int32_t i8; + uint32_t u8; + } uDisp; + /** The base register from ModR/M or SIB, applicable if DISUSE_BASE is + * set in fUse. */ + union + { + /** General register index (DISGREG_XXX), applicable if DISUSE_REG_GEN8, + * DISUSE_REG_GEN16, DISUSE_REG_GEN32 or DISUSE_REG_GEN64 is set in fUse. */ + uint8_t idxGenReg; + /** FPU stack register index (DISFPREG_XXX), applicable if DISUSE_REG_FP is + * set in fUse. 1:1 indexes. */ + uint8_t idxFpuReg; + /** MMX register index (DISMREG_XXX), applicable if DISUSE_REG_MMX is + * set in fUse. 1:1 indexes. */ + uint8_t idxMmxReg; + /** SSE register index (DISXREG_XXX), applicable if DISUSE_REG_XMM is + * set in fUse. 1:1 indexes. */ + uint8_t idxXmmReg; + /** SSE2 register index (DISYREG_XXX), applicable if DISUSE_REG_YMM is + * set in fUse. 1:1 indexes. */ + uint8_t idxYmmReg; + /** Segment register index (DISSELREG_XXX), applicable if DISUSE_REG_SEG is + * set in fUse. */ + uint8_t idxSegReg; + /** Test register, TR0-TR7, present on early IA32 CPUs, applicable if + * DISUSE_REG_TEST is set in fUse. No index defines for these. */ + uint8_t idxTestReg; + /** Control register index (DISCREG_XXX), applicable if DISUSE_REG_CR is + * set in fUse. 1:1 indexes. */ + uint8_t idxCtrlReg; + /** Debug register index (DISDREG_XXX), applicable if DISUSE_REG_DBG is + * set in fUse. 1:1 indexes. */ + uint8_t idxDbgReg; + } Base; + /** The SIB index register meaning, applicable if DISUSE_INDEX is + * set in fUse. */ + union + { + /** General register index (DISGREG_XXX), applicable if DISUSE_REG_GEN8, + * DISUSE_REG_GEN16, DISUSE_REG_GEN32 or DISUSE_REG_GEN64 is set in fUse. */ + uint8_t idxGenReg; + /** XMM register index (DISXREG_XXX), applicable if DISUSE_REG_XMM + * is set in fUse. */ + uint8_t idxXmmReg; + /** YMM register index (DISXREG_XXX), applicable if DISUSE_REG_YMM + * is set in fUse. */ + uint8_t idxYmmReg; + } Index; + /** 2, 4 or 8, if DISUSE_SCALE is set in fUse. */ + uint8_t uScale; + /** Parameter size. */ + uint8_t cb; + /** Copy of the corresponding DISOPCODE::fParam1 / DISOPCODE::fParam2 / + * DISOPCODE::fParam3. */ + uint32_t fParam; +} DISOPPARAM; +AssertCompileSize(DISOPPARAM, 32); +/** Pointer to opcode parameter. */ +typedef DISOPPARAM *PDISOPPARAM; +/** Pointer to opcode parameter. */ +typedef const DISOPPARAM *PCDISOPPARAM; + + +#if (defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64)) && defined(DIS_CORE_ONLY) +# define DISOPCODE_BITFIELD(a_cBits) : a_cBits +#else +# define DISOPCODE_BITFIELD(a_cBits) +#endif + +/** + * Opcode descriptor. + */ +#if !defined(DIS_CORE_ONLY) || defined(DOXYGEN_RUNNING) +typedef struct DISOPCODE +{ +# define DISOPCODE_FORMAT 0 + /** Mnemonic and operand formatting. */ + const char *pszOpcode; + /** Parameter \#1 parser index. */ + uint8_t idxParse1; + /** Parameter \#2 parser index. */ + uint8_t idxParse2; + /** Parameter \#3 parser index. */ + uint8_t idxParse3; + /** Parameter \#4 parser index. */ + uint8_t idxParse4; + /** The opcode identifier. This DIS specific, @see grp_dis_opcodes and + * VBox/disopcode.h. */ + uint16_t uOpcode; + /** Parameter \#1 info, @see grp_dis_opparam. */ + uint16_t fParam1; + /** Parameter \#2 info, @see grp_dis_opparam. */ + uint16_t fParam2; + /** Parameter \#3 info, @see grp_dis_opparam. */ + uint16_t fParam3; + /** Parameter \#4 info, @see grp_dis_opparam. */ + uint16_t fParam4; + /** padding unused */ + uint16_t uPadding; + /** Operand type flags, DISOPTYPE_XXX. */ + uint32_t fOpType; +} DISOPCODE; +#else +# pragma pack(1) +typedef struct DISOPCODE +{ +#if 1 /*!defined(RT_ARCH_X86) && !defined(RT_ARCH_AMD64) - probably not worth it for ~4K, costs 2-3% speed. */ + /* 16 bytes (trick is to make sure the bitfields doesn't cross dwords): */ +# define DISOPCODE_FORMAT 16 + uint32_t fOpType; + uint16_t uOpcode; + uint8_t idxParse1; + uint8_t idxParse2; + uint32_t fParam1 : 12; /* 1st dword: 12+12+8 = 0x20 (32) */ + uint32_t fParam2 : 12; + uint32_t idxParse3 : 8; + uint32_t fParam3 : 12; /* 2nd dword: 12+12+8 = 0x20 (32) */ + uint32_t fParam4 : 12; + uint32_t idxParse4 : 8; +#else /* 15 bytes: */ +# define DISOPCODE_FORMAT 15 + uint64_t uOpcode : 10; /* 1st qword: 10+12+12+12+6+6+6 = 0x40 (64) */ + uint64_t idxParse1 : 6; + uint64_t idxParse2 : 6; + uint64_t idxParse3 : 6; + uint64_t fParam1 : 12; + uint64_t fParam2 : 12; + uint64_t fParam3 : 12; + uint32_t fOpType; + uint16_t fParam4; + uint8_t idxParse4; +#endif +} DISOPCODE; +# pragma pack() +AssertCompile(sizeof(DISOPCODE) == DISOPCODE_FORMAT); +#endif +AssertCompile(DISOPCODE_FORMAT != 15); /* Needs fixing before use as disopcode.h now has more than 1024 opcode values. */ +/** Pointer to const opcode. */ +typedef const struct DISOPCODE *PCDISOPCODE; + + +/** + * Callback for reading instruction bytes. + * + * @returns VBox status code, bytes in DISSTATE::abInstr and byte count in + * DISSTATE::cbCachedInstr. + * @param pDis Pointer to the disassembler state. The user + * argument can be found in DISSTATE::pvUser if needed. + * @param offInstr The offset relative to the start of the instruction. + * + * To get the source address, add this to + * DISSTATE::uInstrAddr. + * + * To calculate the destination buffer address, use it + * as an index into DISSTATE::abInstr. + * + * @param cbMinRead The minimum number of bytes to read. + * @param cbMaxRead The maximum number of bytes that may be read. + */ +typedef DECLCALLBACKTYPE(int, FNDISREADBYTES,(PDISSTATE pDis, uint8_t offInstr, uint8_t cbMinRead, uint8_t cbMaxRead)); +/** Pointer to a opcode byte reader. */ +typedef FNDISREADBYTES *PFNDISREADBYTES; + +/** Parser callback. + * @remark no DECLCALLBACK() here because it's considered to be internal and + * there is no point in enforcing CDECL. */ +typedef size_t FNDISPARSE(size_t offInstr, PCDISOPCODE pOp, PDISSTATE pDis, PDISOPPARAM pParam); +/** Pointer to a disassembler parser function. */ +typedef FNDISPARSE *PFNDISPARSE; +/** Pointer to a const disassembler parser function pointer. */ +typedef PFNDISPARSE const *PCPFNDISPARSE; + +/** + * The diassembler state and result. + */ +typedef struct DISSTATE +{ + /** The number of valid bytes in abInstr. */ + uint8_t cbCachedInstr; + /** SIB fields. */ + union + { + /** Bitfield view */ + struct + { + uint8_t Base; + uint8_t Index; + uint8_t Scale; + } Bits; + } SIB; + /** ModRM fields. */ + union + { + /** Bitfield view */ + struct + { + uint8_t Rm; + uint8_t Reg; + uint8_t Mod; + } Bits; + } ModRM; + /** The CPU mode (DISCPUMODE). */ + uint8_t uCpuMode; + /** The addressing mode (DISCPUMODE). */ + uint8_t uAddrMode; + /** The operand mode (DISCPUMODE). */ + uint8_t uOpMode; + /** Per instruction prefix settings. */ + uint8_t fPrefix; + /** REX prefix value (64 bits only). */ + uint8_t fRexPrefix; + /** Segment prefix value (DISSELREG). */ + uint8_t idxSegPrefix; + /** Last prefix byte (for SSE2 extension tables). */ + uint8_t bLastPrefix; + /** Last significant opcode byte of instruction. */ + uint8_t bOpCode; + /** The size of the prefix bytes. */ + uint8_t cbPrefix; + /** The instruction size. */ + uint8_t cbInstr; + /** VEX presence flag, destination register and size + * @todo r=bird: There is no VEX presence flage here, just ~vvvv and L. */ + uint8_t bVexDestReg; + /** VEX.W flag */ + uint8_t bVexWFlag; + /** Unused bytes. */ + uint8_t abUnused[1]; + /** Internal: instruction filter */ + uint32_t fFilter; + /** Internal: pointer to disassembly function table */ + PCPFNDISPARSE pfnDisasmFnTable; +#if ARCH_BITS == 32 + uint32_t uPtrPadding1; +#endif + /** Pointer to the current instruction. */ + PCDISOPCODE pCurInstr; +#if ARCH_BITS == 32 + uint32_t uPtrPadding2; +#endif + /** The instruction bytes. */ + uint8_t abInstr[16]; + /** SIB displacment. */ + int32_t i32SibDisp; + + /** Return code set by a worker function like the opcode bytes readers. */ + int32_t rc; + /** The address of the instruction. */ + RTUINTPTR uInstrAddr; + /** Optional read function */ + PFNDISREADBYTES pfnReadBytes; +#if ARCH_BITS == 32 + uint32_t uPadding3; +#endif + /** User data supplied as an argument to the APIs. */ + void *pvUser; +#if ARCH_BITS == 32 + uint32_t uPadding4; +#endif + /** Parameters. */ + DISOPPARAM Param1; + DISOPPARAM Param2; + DISOPPARAM Param3; + DISOPPARAM Param4; +} DISSTATE; +AssertCompileSize(DISSTATE, 0xd8); + +/** @deprecated Use DISSTATE and change Cpu and DisState to Dis. */ +typedef DISSTATE DISCPUSTATE; + + + +DISDECL(int) DISInstrToStr(void const *pvInstr, DISCPUMODE enmCpuMode, + PDISSTATE pDis, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput); +DISDECL(int) DISInstrToStrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser, + PDISSTATE pDis, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput); +DISDECL(int) DISInstrToStrEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, + PFNDISREADBYTES pfnReadBytes, void *pvUser, uint32_t uFilter, + PDISSTATE pDis, uint32_t *pcbInstr, char *pszOutput, size_t cbOutput); + +DISDECL(int) DISInstr(void const *pvInstr, DISCPUMODE enmCpuMode, PDISSTATE pDis, uint32_t *pcbInstr); +DISDECL(int) DISInstrWithReader(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, PFNDISREADBYTES pfnReadBytes, void *pvUser, + PDISSTATE pDis, uint32_t *pcbInstr); +DISDECL(int) DISInstrEx(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t uFilter, + PFNDISREADBYTES pfnReadBytes, void *pvUser, + PDISSTATE pDis, uint32_t *pcbInstr); +DISDECL(int) DISInstrWithPrefetchedBytes(RTUINTPTR uInstrAddr, DISCPUMODE enmCpuMode, uint32_t fFilter, + void const *pvPrefetched, size_t cbPretched, + PFNDISREADBYTES pfnReadBytes, void *pvUser, + PDISSTATE pDis, uint32_t *pcbInstr); + +DISDECL(uint8_t) DISGetParamSize(PCDISSTATE pDis, PCDISOPPARAM pParam); +#if 0 /* unused */ +DISDECL(DISSELREG) DISDetectSegReg(PCDISSTATE pDis, PCDISOPPARAM pParam); +DISDECL(uint8_t) DISQuerySegPrefixByte(PCDISSTATE pDis); +#endif + +#if 0 /* Needs refactoring if we want to use this again, CPUMCTXCORE is history. */ +/** @name Flags returned by DISQueryParamVal (DISQPVPARAMVAL::flags). + * @{ + */ +#define DISQPV_FLAG_8 UINT8_C(0x01) +#define DISQPV_FLAG_16 UINT8_C(0x02) +#define DISQPV_FLAG_32 UINT8_C(0x04) +#define DISQPV_FLAG_64 UINT8_C(0x08) +#define DISQPV_FLAG_FARPTR16 UINT8_C(0x10) +#define DISQPV_FLAG_FARPTR32 UINT8_C(0x20) +/** @} */ + +/** @name Types returned by DISQueryParamVal (DISQPVPARAMVAL::flags). + * @{ */ +#define DISQPV_TYPE_REGISTER UINT8_C(1) +#define DISQPV_TYPE_ADDRESS UINT8_C(2) +#define DISQPV_TYPE_IMMEDIATE UINT8_C(3) +/** @} */ + +typedef struct +{ + union + { + uint8_t val8; + uint16_t val16; + uint32_t val32; + uint64_t val64; + + int8_t i8; + int16_t i16; + int32_t i32; + int64_t i64; + + struct + { + uint16_t sel; + uint32_t offset; + } farptr; + } val; + + uint8_t type; + uint8_t size; + uint8_t flags; +} DISQPVPARAMVAL; +/** Pointer to opcode parameter value. */ +typedef DISQPVPARAMVAL *PDISQPVPARAMVAL; + +/** Indicates which parameter DISQueryParamVal should operate on. */ +typedef enum DISQPVWHICH +{ + DISQPVWHICH_DST = 1, + DISQPVWHICH_SRC, + DISQPVWHAT_32_BIT_HACK = 0x7fffffff +} DISQPVWHICH; +DISDECL(int) DISQueryParamVal(PCPUMCTXCORE pCtx, PCDISSTATE pDis, PCDISOPPARAM pParam, PDISQPVPARAMVAL pParamVal, DISQPVWHICH parmtype); +DISDECL(int) DISQueryParamRegPtr(PCPUMCTXCORE pCtx, PCDISSTATE pDis, PCDISOPPARAM pParam, void **ppReg, size_t *pcbSize); + +DISDECL(int) DISFetchReg8(PCCPUMCTXCORE pCtx, unsigned reg8, uint8_t *pVal); +DISDECL(int) DISFetchReg16(PCCPUMCTXCORE pCtx, unsigned reg16, uint16_t *pVal); +DISDECL(int) DISFetchReg32(PCCPUMCTXCORE pCtx, unsigned reg32, uint32_t *pVal); +DISDECL(int) DISFetchReg64(PCCPUMCTXCORE pCtx, unsigned reg64, uint64_t *pVal); +DISDECL(int) DISFetchRegSeg(PCCPUMCTXCORE pCtx, DISSELREG sel, RTSEL *pVal); +DISDECL(int) DISWriteReg8(PCPUMCTXCORE pRegFrame, unsigned reg8, uint8_t val8); +DISDECL(int) DISWriteReg16(PCPUMCTXCORE pRegFrame, unsigned reg32, uint16_t val16); +DISDECL(int) DISWriteReg32(PCPUMCTXCORE pRegFrame, unsigned reg32, uint32_t val32); +DISDECL(int) DISWriteReg64(PCPUMCTXCORE pRegFrame, unsigned reg64, uint64_t val64); +DISDECL(int) DISWriteRegSeg(PCPUMCTXCORE pCtx, DISSELREG sel, RTSEL val); +DISDECL(int) DISPtrReg8(PCPUMCTXCORE pCtx, unsigned reg8, uint8_t **ppReg); +DISDECL(int) DISPtrReg16(PCPUMCTXCORE pCtx, unsigned reg16, uint16_t **ppReg); +DISDECL(int) DISPtrReg32(PCPUMCTXCORE pCtx, unsigned reg32, uint32_t **ppReg); +DISDECL(int) DISPtrReg64(PCPUMCTXCORE pCtx, unsigned reg64, uint64_t **ppReg); +#endif /* obsolete */ + + +/** + * Try resolve an address into a symbol name. + * + * For use with DISFormatYasmEx(), DISFormatMasmEx() and DISFormatGasEx(). + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success, pszBuf contains the full symbol name. + * @retval VINF_BUFFER_OVERFLOW if pszBuf is too small the symbol name. The + * content of pszBuf is truncated and zero terminated. + * @retval VERR_SYMBOL_NOT_FOUND if no matching symbol was found for the address. + * + * @param pDis Pointer to the disassembler CPU state. + * @param u32Sel The selector value. Use DIS_FMT_SEL_IS_REG, DIS_FMT_SEL_GET_VALUE, + * DIS_FMT_SEL_GET_REG to access this. + * @param uAddress The segment address. + * @param pszBuf Where to store the symbol name + * @param cchBuf The size of the buffer. + * @param poff If not a perfect match, then this is where the offset from the return + * symbol to the specified address is returned. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNDISGETSYMBOL,(PCDISSTATE pDis, uint32_t u32Sel, RTUINTPTR uAddress, char *pszBuf, size_t cchBuf, + RTINTPTR *poff, void *pvUser)); +/** Pointer to a FNDISGETSYMBOL(). */ +typedef FNDISGETSYMBOL *PFNDISGETSYMBOL; + +/** + * Checks if the FNDISGETSYMBOL argument u32Sel is a register or not. + */ +#define DIS_FMT_SEL_IS_REG(u32Sel) ( !!((u32Sel) & RT_BIT(31)) ) + +/** + * Extracts the selector value from the FNDISGETSYMBOL argument u32Sel. + * @returns Selector value. + */ +#define DIS_FMT_SEL_GET_VALUE(u32Sel) ( (RTSEL)(u32Sel) ) + +/** + * Extracts the register number from the FNDISGETSYMBOL argument u32Sel. + * @returns USE_REG_CS, USE_REG_SS, USE_REG_DS, USE_REG_ES, USE_REG_FS or USE_REG_FS. + */ +#define DIS_FMT_SEL_GET_REG(u32Sel) ( ((u32Sel) >> 16) & 0xf ) + +/** @internal */ +#define DIS_FMT_SEL_FROM_REG(uReg) ( ((uReg) << 16) | RT_BIT(31) | 0xffff ) +/** @internal */ +#define DIS_FMT_SEL_FROM_VALUE(Sel) ( (Sel) & 0xffff ) + + +/** @name Flags for use with DISFormatYasmEx(), DISFormatMasmEx() and DISFormatGasEx(). + * @{ + */ +/** Put the address to the right. */ +#define DIS_FMT_FLAGS_ADDR_RIGHT RT_BIT_32(0) +/** Put the address to the left. */ +#define DIS_FMT_FLAGS_ADDR_LEFT RT_BIT_32(1) +/** Put the address in comments. + * For some assemblers this implies placing it to the right. */ +#define DIS_FMT_FLAGS_ADDR_COMMENT RT_BIT_32(2) +/** Put the instruction bytes to the right of the disassembly. */ +#define DIS_FMT_FLAGS_BYTES_RIGHT RT_BIT_32(3) +/** Put the instruction bytes to the left of the disassembly. */ +#define DIS_FMT_FLAGS_BYTES_LEFT RT_BIT_32(4) +/** Put the instruction bytes in comments. + * For some assemblers this implies placing the bytes to the right. */ +#define DIS_FMT_FLAGS_BYTES_COMMENT RT_BIT_32(5) +/** Put the bytes in square brackets. */ +#define DIS_FMT_FLAGS_BYTES_BRACKETS RT_BIT_32(6) +/** Put spaces between the bytes. */ +#define DIS_FMT_FLAGS_BYTES_SPACED RT_BIT_32(7) +/** Display the relative +/- offset of branch instructions that uses relative addresses, + * and put the target address in parenthesis. */ +#define DIS_FMT_FLAGS_RELATIVE_BRANCH RT_BIT_32(8) +/** Strict assembly. The assembly should, when ever possible, make the + * assembler reproduce the exact same binary. (Refers to the yasm + * strict keyword.) */ +#define DIS_FMT_FLAGS_STRICT RT_BIT_32(9) +/** Checks if the given flags are a valid combination. */ +#define DIS_FMT_FLAGS_IS_VALID(fFlags) \ + ( !((fFlags) & ~UINT32_C(0x000003ff)) \ + && ((fFlags) & (DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT)) != (DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT) \ + && ( !((fFlags) & DIS_FMT_FLAGS_ADDR_COMMENT) \ + || (fFlags & (DIS_FMT_FLAGS_ADDR_RIGHT | DIS_FMT_FLAGS_ADDR_LEFT)) ) \ + && ((fFlags) & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_LEFT)) != (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_LEFT) \ + && ( !((fFlags) & (DIS_FMT_FLAGS_BYTES_COMMENT | DIS_FMT_FLAGS_BYTES_BRACKETS)) \ + || (fFlags & (DIS_FMT_FLAGS_BYTES_RIGHT | DIS_FMT_FLAGS_BYTES_LEFT)) ) \ + ) +/** @} */ + +DISDECL(size_t) DISFormatYasm( PCDISSTATE pDis, char *pszBuf, size_t cchBuf); +DISDECL(size_t) DISFormatYasmEx(PCDISSTATE pDis, char *pszBuf, size_t cchBuf, uint32_t fFlags, PFNDISGETSYMBOL pfnGetSymbol, void *pvUser); +DISDECL(size_t) DISFormatMasm( PCDISSTATE pDis, char *pszBuf, size_t cchBuf); +DISDECL(size_t) DISFormatMasmEx(PCDISSTATE pDis, char *pszBuf, size_t cchBuf, uint32_t fFlags, PFNDISGETSYMBOL pfnGetSymbol, void *pvUser); +DISDECL(size_t) DISFormatGas( PCDISSTATE pDis, char *pszBuf, size_t cchBuf); +DISDECL(size_t) DISFormatGasEx( PCDISSTATE pDis, char *pszBuf, size_t cchBuf, uint32_t fFlags, PFNDISGETSYMBOL pfnGetSymbol, void *pvUser); + +/** @todo DISAnnotate(PCDISSTATE pDis, char *pszBuf, size_t cchBuf, register + * reader, memory reader); */ + +DISDECL(bool) DISFormatYasmIsOddEncoding(PDISSTATE pDis); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_dis_h */ + diff --git a/include/VBox/disopcode.h b/include/VBox/disopcode.h new file mode 100644 index 00000000..5732f5c5 --- /dev/null +++ b/include/VBox/disopcode.h @@ -0,0 +1,1469 @@ +/** @file + * Disassembler - Opcodes + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_disopcode_h +#define VBOX_INCLUDED_disopcode_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#define MODRM_MOD(a) (a>>6) +#define MODRM_REG(a) ((a>>3)&0x7) +#define MODRM_RM(a) (a&0x7) +#define MAKE_MODRM(mod, reg, rm) (((mod&3) << 6) | ((reg&7) << 3) | (rm&7)) + +#define SIB_SCALE(a) (a>>6) +#define SIB_INDEX(a) ((a>>3)&0x7) +#define SIB_BASE(a) (a&0x7) + + +/** @defgroup grp_dis_opcodes Opcodes (DISOPCODE::uOpCode) + * @ingroup grp_dis + * @{ + */ +enum OPCODES +{ +/** @name Full Intel X86 opcode list + * @{ */ + OP_INVALID = 0, + OP_OPSIZE, + OP_ADDRSIZE, + OP_SEG, + OP_REPNE, + OP_REPE, + OP_REX, + OP_LOCK, +#ifndef IN_SLICKEDIT + OP_LAST_PREFIX = OP_LOCK, /**< Last prefix for disassembler. */ +#else + OP_LAST_PREFIX = 7, /**< Last prefix for disassembler. */ +#endif + OP_AND, + OP_OR, + OP_DAA, + OP_SUB, + OP_DAS, + OP_XOR, + OP_AAA, + OP_CMP, + OP_IMM_GRP1, + OP_AAS, + OP_INC, + OP_DEC, + OP_PUSHA, + OP_POPA, + OP_BOUND, + OP_ARPL, + OP_PUSH, + OP_POP, + OP_IMUL, + OP_INSB, + OP_INSWD, + OP_OUTSB, + OP_OUTSWD, + OP_JO, + OP_JNO, + OP_JC, + OP_JNC, + OP_JE, + OP_JNE, + OP_JBE, + OP_JNBE, + OP_JS, + OP_JNS, + OP_JP, + OP_JNP, + OP_JL, + OP_JNL, + OP_JLE, + OP_JNLE, + OP_ADD, + OP_TEST, + OP_XCHG, + OP_MOV, + OP_LEA, + OP_NOP, + OP_CBW, + OP_CWD, + OP_CALL, + OP_WAIT, + OP_PUSHF, + OP_POPF, + OP_SAHF, + OP_LAHF, + OP_MOVSB, + OP_MOVSWD, + OP_CMPSB, + OP_CMPWD, + OP_STOSB, + OP_STOSWD, + OP_LODSB, + OP_LODSWD, + OP_SCASB, + OP_SCASWD, + OP_SHIFT_GRP2, + OP_RETN, + OP_LES, + OP_LDS, + OP_ENTER, + OP_LEAVE, + OP_RETF, + OP_INT1, + OP_INT3, + OP_INT, + OP_INTO, + OP_IRET, + OP_AAM, + OP_AAD, + OP_SALC, + OP_XLAT, + OP_ESCF0, + OP_ESCF1, + OP_ESCF2, + OP_ESCF3, + OP_ESCF4, + OP_ESCF5, + OP_ESCF6, + OP_ESCF7, + OP_LOOPNE, + OP_LOOPE, + OP_LOOP, + OP_JECXZ, + OP_IN, + OP_OUT, + OP_JMP, + OP_2B_ESC, + OP_ADC, + OP_SBB, + OP_HLT, + OP_CMC, + OP_UNARY_GRP3, + OP_CLC, + OP_STC, + OP_CLI, + OP_STI, + OP_CLD, + OP_STD, + OP_INC_GRP4, + OP_IND_GRP5, + OP_GRP6, + OP_GRP7, + OP_LAR, + OP_LSL, + OP_SYSCALL, + OP_CLTS, + OP_SYSRET, + OP_INVD, + OP_WBINVD, + OP_ILLUD2, + OP_FEMMS, + OP_3DNOW, + OP_MOVUPS, + OP_MOVLPS, + OP_MOVHLPS = OP_MOVLPS, /**< @todo OP_MOVHLPS */ + OP_UNPCKLPS, + OP_MOVHPS, + OP_MOVLHPS = OP_MOVHPS, /**< @todo OP_MOVLHPS */ + OP_UNPCKHPS, + OP_PREFETCH_GRP16, + OP_MOV_CR, + OP_MOVAPS, + OP_CVTPI2PS, + OP_MOVNTPS, + OP_CVTTPS2PI, + OP_CVTPS2PI, + OP_UCOMISS, + OP_COMISS, + OP_WRMSR, + OP_RDTSC, + OP_RDTSCP, + OP_RDMSR, + OP_RDPMC, + OP_SYSENTER, + OP_SYSEXIT, + OP_GETSEC, + OP_PAUSE, + OP_CMOVO, + OP_CMOVNO, + OP_CMOVC, + OP_CMOVNC, + OP_CMOVZ, + OP_CMOVNZ, + OP_CMOVBE, + OP_CMOVNBE, + OP_CMOVS, + OP_CMOVNS, + OP_CMOVP, + OP_CMOVNP, + OP_CMOVL, + OP_CMOVNL, + OP_CMOVLE, + OP_CMOVNLE, + OP_MOVMSKPS, + OP_SQRTPS, + OP_RSQRTPS, + OP_RCPPS, + OP_ANDPS, + OP_ANDNPS, + OP_ORPS, + OP_XORPS, + OP_ADDPS, + OP_MULPS, + OP_CVTPS2PD, + OP_CVTDQ2PS, + OP_SUBPS, + OP_MINPS, + OP_DIVPS, + OP_MAXPS, + OP_PUNPCKLBW, + OP_PUNPCKLWD, + OP_PUNPCKLDQ, + OP_PACKSSWB, + OP_PCMPGTB, + OP_PCMPGTW, + OP_PCMPGTD, + OP_PCMPGTQ, + OP_PACKUSWB, + OP_PUNPCKHBW, + OP_PUNPCKHWD, + OP_PUNPCKHDQ, + OP_PACKSSDW, + OP_MOVD, + OP_MOVQ, + OP_PSHUFW, + OP_3B_ESC4, + OP_3B_ESC5, + OP_PCMPEQB, + OP_PCMPEQW, + OP_PCMPEQD, + OP_PCMPEQQ, + OP_SETO, + OP_SETNO, + OP_SETC, + OP_SETNC, + OP_SETE, + OP_SETNE, + OP_SETBE, + OP_SETNBE, + OP_SETS, + OP_SETNS, + OP_SETP, + OP_SETNP, + OP_SETL, + OP_SETNL, + OP_SETLE, + OP_SETNLE, + OP_CPUID, + OP_BT, + OP_SHLD, + OP_RSM, + OP_BTS, + OP_SHRD, + OP_GRP15, + OP_CMPXCHG, + OP_LSS, + OP_BTR, + OP_LFS, + OP_LGS, + OP_MOVZX, + OP_GRP10_INV, + OP_GRP8, + OP_BTC, + OP_BSF, + OP_BSR, + OP_MOVSX, + OP_XADD, + OP_CMPPS, + OP_MOVNTI, + OP_PINSRW, + OP_PEXTRW, + OP_SHUFPS, + OP_GRP9, + OP_BSWAP, + OP_ADDSUBPS, + OP_ADDSUBPD, + OP_PSRLW, + OP_PSRLD, + OP_PSRLQ, + OP_PADDQ, + OP_PMULLW, + OP_PMOVMSKB, + OP_PSUBUSB, + OP_PSUBUSW, + OP_PMINUB, + OP_PAND, + OP_PADDUSB, + OP_PADDUSW, + OP_PMAXUB, + OP_PANDN, + OP_PAVGB, + OP_PSRAW, + OP_PSRAD, + OP_PAVGW, + OP_PMULHUW, + OP_PMULHW, + OP_MOVNTQ, + OP_PSUBSB, + OP_PSUBSW, + OP_PMINSW, + OP_POR, + OP_PADDSB, + OP_PADDSW, + OP_PMAXSW, + OP_PXOR, + OP_LDDQU, + OP_PSLLW, + OP_PSLLD, + OP_PSSQ, + OP_PMULUDQ, + OP_PMADDWD, + OP_PSADBW, + OP_MASKMOVQ, + OP_PSUBB, + OP_PSUBW, + OP_PSUBD, + OP_PSUBQ, + OP_PADDB, + OP_PADDW, + OP_PADDD, + OP_MOVUPD, + OP_MOVLPD, + OP_UNPCKLPD, + OP_UNPCKHPD, + OP_MOVHPD, + OP_MOVAPD, + OP_CVTPI2PD, + OP_MOVNTPD, + OP_CVTTPD2PI, + OP_CVTPD2PI, + OP_UCOMISD, + OP_COMISD, + OP_MOVMSKPD, + OP_SQRTPD, + OP_ANDPD, + OP_ANDNPD, + OP_ORPD, + OP_XORPD, + OP_ADDPD, + OP_MULPD, + OP_CVTPD2PS, + OP_CVTPS2DQ, + OP_SUBPD, + OP_MINPD, + OP_DIVPD, + OP_MAXPD, + OP_GRP12, + OP_GRP13, + OP_GRP14, + OP_GRP17, + OP_EMMS, + OP_MMX_UD78, + OP_MMX_UD79, + OP_MMX_UD7A, + OP_MMX_UD7B, + OP_MMX_UD7C, + OP_MMX_UD7D, + OP_PUNPCKLQDQ, + OP_PUNPCKHQDQ, + OP_MOVDQA, + OP_PSHUFD, + OP_CMPPD, + OP_SHUFPD, + OP_CVTTPD2DQ, + OP_MOVNTDQ, + OP_MOVNTDQA, + OP_PACKUSDW, + OP_PSHUFB, + OP_PHADDW, + OP_PHADDD, + OP_PHADDSW, + OP_HADDPS, + OP_HADDPD, + OP_PMADDUBSW, + OP_PHSUBW, + OP_PHSUBD, + OP_PHSUBSW, + OP_HSUBPS, + OP_HSUBPD, + OP_PSIGNB, + OP_PSIGNW, + OP_PSIGND, + OP_PMULHRSW, + OP_PERMILPS, + OP_PERMILPD, + OP_TESTPS, + OP_TESTPD, + OP_PBLENDVB, + OP_CVTPH2PS, + OP_BLENDVPS, + OP_BLENDVPD, + OP_PERMPS, + OP_PERMD, + OP_PTEST, + OP_BROADCASTSS, + OP_BROADCASTSD, + OP_BROADCASTF128, + OP_PABSB, + OP_PABSW, + OP_PABSD, + OP_PMOVSXBW, + OP_PMOVSXBD, + OP_PMOVSXBQ, + OP_PMOVSXWD, + OP_PMOVSXWQ, + OP_PMOVSXDQ, + OP_PMOVZXBW, + OP_PMOVZXBD, + OP_PMOVZXBQ, + OP_PMOVZXWD, + OP_PMOVZXWQ, + OP_PMOVZXDQ, + OP_PMULDQ, + OP_PMINSB, + OP_PMINSD, + OP_PMINUW, + OP_PMINUD, + OP_PMAXSB, + OP_PMAXSD, + OP_PMAXUW, + OP_PMAXUD, + OP_PMULLD, + OP_PHMINPOSUW, + OP_PSRLVD, + OP_PSRAVD, + OP_PSLLVD, + OP_PBROADCASTD, + OP_PBROADCASTQ, + OP_PBROADCASTI128, + OP_PBROADCASTB, + OP_PBROADCASTW, + OP_PMASKMOVD, + OP_GATHER, + OP_FMADDSUB132PS, + OP_FMSUBADD132PS, + OP_FMADD132PS, + OP_FMADD132SS, + OP_FMSUB132PS, + OP_FMSUB132SS, + OP_FNMADD132PS, + OP_FNMADD132SS, + OP_FNMSUB132PS, + OP_FNMSUB132SS, + OP_FMADDSUB213PS, + OP_FMSUBADD213PS, + OP_FMADD213PS, + OP_FMADD213SS, + OP_FMSUB213PS, + OP_FMSUB213SS, + OP_FNMADD213PS, + OP_FNMADD213SS, + OP_FNMSUB213PS, + OP_FNMSUB213SS, + OP_FMADDSUB231PS, + OP_FMSUBADD231PS, + OP_FMADD231PS, + OP_FMADD231SS, + OP_FMSUB231PS, + OP_FMSUB231SS, + OP_FNMADD231PS, + OP_FNMADD231SS, + OP_FNMSUB231PS, + OP_FNMSUB231SS, + OP_AESIMC, + OP_AESENC, + OP_AESENCLAST, + OP_AESDEC, + OP_AESDECLAST, + OP_MOVBEGM, + OP_MOVBEMG, + OP_CRC32, + OP_POPCNT, + OP_TZCNT, + OP_LZCNT, + OP_ADCX, + OP_ADOX, + OP_ANDN, + OP_BZHI, + OP_BEXTR, + OP_BLSR, + OP_BLSMSK, + OP_BLSI, + OP_PEXT, + OP_PDEP, + OP_SHLX, + OP_SHRX, + OP_SARX, + OP_MULX, + OP_MASKMOVDQU, + OP_MASKMOVPS, + OP_MASKMOVPD, + OP_MOVSD, + OP_CVTSI2SD, + OP_CVTTSD2SI, + OP_CVTSD2SI, + OP_SQRTSD, + OP_ADDSD, + OP_MULSD, + OP_CVTSD2SS, + OP_SUBSD, + OP_MINSD, + OP_DIVSD, + OP_MAXSD, + OP_PSHUFLW, + OP_CMPSD, + OP_MOVDQ2Q, + OP_CVTPD2DQ, + OP_MOVSS, + OP_MOVSLDUP, + OP_MOVDDUP, + OP_MOVSHDUP, + OP_CVTSI2SS, + OP_CVTTSS2SI, + OP_CVTSS2SI, + OP_CVTSS2SD, + OP_SQRTSS, + OP_RSQRTSS, + OP_RCPSS, + OP_ADDSS, + OP_MULSS, + OP_CVTTPS2DQ, + OP_SUBSS, + OP_MINSS, + OP_DIVSS, + OP_MAXSS, + OP_MOVDQU, + OP_PSHUFHW, + OP_CMPSS, + OP_MOVQ2DQ, + OP_CVTDQ2PD, + OP_PERMQ, + OP_PERMPD, + OP_PBLENDD, + OP_PERM2F128, + OP_ROUNDPS, + OP_ROUNDPD, + OP_ROUNDSS, + OP_ROUNDSD, + OP_BLENDPS, + OP_BLENDPD, + OP_PBLENDW, + OP_PALIGNR, + OP_PEXTRB, + OP_PEXTRD, + OP_PEXTRQ, + OP_EXTRACTPS, + OP_INSERTF128, + OP_EXTRACTF128, + OP_CVTPS2PH, + OP_PINSRB, + OP_PINSRD, + OP_PINSRQ, + OP_INSERTPS, + OP_INSERTI128, + OP_EXTRACTI128, + OP_DPPS, + OP_DPPD, + OP_MPSADBW, + OP_PCLMULQDQ, + OP_PERM2I128, + OP_PCMPESTRM, + OP_PCMPESTRI, + OP_PCMPISTRM, + OP_PCMPISTRI, + OP_AESKEYGEN, + OP_RORX, + OP_RDRAND, + OP_RDSEED, + OP_MOVBE, + OP_VEX3B, + OP_VEX2B, +/** @} */ + +/** @name Floating point ops + * @{ */ + OP_FADD, + OP_FMUL, + OP_FCOM, + OP_FCOMP, + OP_FSUB, + OP_FSUBR, + OP_FDIV, + OP_FDIVR, + OP_FLD, + OP_FST, + OP_FSTP, + OP_FLDENV, + OP_FSTENV, + OP_FSTCW, + OP_FXCH, + OP_FNOP, + OP_FCHS, + OP_FABS, + OP_FLD1, + OP_FLDL2T, + OP_FLDL2E, + OP_FLDPI, + OP_FLDLG2, + OP_FLDLN2, + OP_FLDZ, + OP_F2XM1, + OP_FYL2X, + OP_FPTAN, + OP_FPATAN, + OP_FXTRACT, + OP_FREM1, + OP_FDECSTP, + OP_FINCSTP, + OP_FPREM, + OP_FYL2XP1, + OP_FSQRT, + OP_FSINCOS, + OP_FRNDINT, + OP_FSCALE, + OP_FSIN, + OP_FCOS, + OP_FIADD, + OP_FIMUL, + OP_FISUB, + OP_FISUBR, + OP_FIDIV, + OP_FIDIVR, + OP_FCMOVB, + OP_FCMOVE, + OP_FCMOVBE, + OP_FCMOVU, + OP_FUCOMPP, + OP_FILD, + OP_FIST, + OP_FISTP, + OP_FCMOVNB, + OP_FCMOVNE, + OP_FCMOVNBE, + OP_FCMOVNU, + OP_FCLEX, + OP_FINIT, + OP_FUCOMI, + OP_FCOMI, + OP_FRSTOR, + OP_FSAVE, + OP_FNSTSW, + OP_FFREE, + OP_FUCOM, + OP_FUCOMP, + OP_FICOM, + OP_FICOMP, + OP_FADDP, + OP_FMULP, + OP_FCOMPP, + OP_FSUBRP, + OP_FSUBP, + OP_FDIVRP, + OP_FDIVP, + OP_FBLD, + OP_FBSTP, + OP_FCOMIP, + OP_FUCOMIP, +/** @} */ + +/** @name 3DNow! + * @{ */ + OP_PI2FW, + OP_PI2FD, + OP_PF2IW, + OP_PF2ID, + OP_PFPNACC, + OP_PFCMPGE, + OP_PFMIN, + OP_PFRCP, + OP_PFRSQRT, + OP_PFSUB, + OP_PFADD, + OP_PFCMPGT, + OP_PFMAX, + OP_PFRCPIT1, + OP_PFRSQRTIT1, + OP_PFSUBR, + OP_PFACC, + OP_PFCMPEQ, + OP_PFMUL, + OP_PFRCPIT2, + OP_PFMULHRW, + OP_PFSWAPD, + OP_PAVGUSB, + OP_PFNACC, +/** @} */ + OP_ROL, + OP_ROR, + OP_RCL, + OP_RCR, + OP_SHL, + OP_SHR, + OP_SAR, + OP_NOT, + OP_NEG, + OP_MUL, + OP_DIV, + OP_IDIV, + OP_SLDT, + OP_STR, + OP_LLDT, + OP_LTR, + OP_VERR, + OP_VERW, + OP_SGDT, + OP_LGDT, + OP_SIDT, + OP_LIDT, + OP_SMSW, + OP_LMSW, + OP_INVLPG, + OP_CMPXCHG8B, + OP_PSLLQ, + OP_PSRLDQ, + OP_PSLLDQ, + OP_FXSAVE, + OP_FXRSTOR, + OP_LDMXCSR, + OP_STMXCSR, + OP_XSAVE, + OP_XSAVEOPT, + OP_XRSTOR, + OP_XGETBV, + OP_XSETBV, + OP_RDFSBASE, + OP_RDGSBASE, + OP_WRFSBASE, + OP_WRGSBASE, + OP_LFENCE, + OP_MFENCE, + OP_SFENCE, + OP_PREFETCH, + OP_MONITOR, + OP_MWAIT, + OP_CLFLUSH, + OP_CLFLUSHOPT, + OP_MOV_DR, + OP_MOV_TR, + OP_SWAPGS, + OP_UD1, + OP_UD2, +/** @name VT-x instructions + * @{ */ + OP_VMREAD, + OP_VMWRITE, + OP_VMCALL, + OP_VMXON, + OP_VMXOFF, + OP_VMCLEAR, + OP_VMLAUNCH, + OP_VMRESUME, + OP_VMPTRLD, + OP_VMPTRST, + OP_INVEPT, + OP_INVVPID, + OP_INVPCID, + OP_VMFUNC, +/** @} */ +/** @name AMD-V instructions + * @{ */ + OP_VMMCALL, + OP_VMRUN, + OP_VMLOAD, + OP_VMSAVE, + OP_CLGI, + OP_STGI, + OP_INVLPGA, + OP_SKINIT, +/** @} */ +/** @name 64 bits instruction + * @{ */ + OP_MOVSXD, +/** @} */ +/** @name AVX instructions + * @{ */ + /* Manual */ + OP_VSTMXCSR, + OP_VLDMXCSR, + OP_VPACKUSDW, + + /* Generated from tables: */ + OP_VADDPD, + OP_VADDPS, + OP_VADDSD, + OP_VADDSS, + OP_VADDSUBPD, + OP_VADDSUBPS, + OP_VAESDEC, + OP_VAESDECLAST, + OP_VAESENC, + OP_VAESENCLAST, + OP_VAESIMC, + OP_VAESKEYGEN, + OP_VANDNPD, + OP_VANDNPS, + OP_VANDPD, + OP_VANDPS, + OP_VBLENDPD, + OP_VBLENDPS, + OP_VBLENDVPD, + OP_VBLENDVPS, + OP_VBROADCASTF128, + OP_VBROADCASTSD, + OP_VBROADCASTSS, + OP_VCMPSD, + OP_VCMPSS, + OP_VCOMISD, + OP_VCOMISS, + OP_VCVTDQ2PD, + OP_VCVTDQ2PS, + OP_VCVTPD2DQ, + OP_VCVTPD2PS, + OP_VCVTPH2PS, + OP_VCVTPS2DQ, + OP_VCVTPS2PD, + OP_VCVTPS2PH, + OP_VCVTSD2SS, + OP_VCVTSI2SS, + OP_VCVTSS2SD, + OP_VCVTSS2SI, + OP_VCVTTPD2DQ, + OP_VCVTTPS2DQ, + OP_VCVTTSS2SI, + OP_VDIVPD, + OP_VDIVPS, + OP_VDIVSD, + OP_VDIVSS, + OP_VDPPD, + OP_VDPPS, + OP_VEXTRACTF128, + OP_VEXTRACTI128, + OP_VEXTRACTPS, + OP_VFMADD132PS, + OP_VFMADD132SS, + OP_VFMADD213PS, + OP_VFMADD213SS, + OP_VFMADD231PS, + OP_VFMADD231SS, + OP_VFMADDSUB132PS, + OP_VFMADDSUB213PS, + OP_VFMADDSUB231PS, + OP_VFMSUB132PS, + OP_VFMSUB132SS, + OP_VFMSUB213PS, + OP_VFMSUB213SS, + OP_VFMSUB231PS, + OP_VFMSUB231SS, + OP_VFMSUBADD132PS, + OP_VFMSUBADD213PS, + OP_VFMSUBADD231PS, + OP_VFNMADD132PS, + OP_VFNMADD132SS, + OP_VFNMADD213PS, + OP_VFNMADD213SS, + OP_VFNMADD231PS, + OP_VFNMADD231SS, + OP_VFNMSUB132PS, + OP_VFNMSUB132SS, + OP_VFNMSUB213PS, + OP_VFNMSUB213SS, + OP_VFNMSUB231PS, + OP_VFNMSUB231SS, + OP_VGATHER, + OP_VHADDPD, + OP_VHADDPS, + OP_VHSUBPD, + OP_VHSUBPS, + OP_VINSERTF128, + OP_VINSERTI128, + OP_VINSERTPS, + OP_VLDDQU, + OP_VMASKMOVDQU, + OP_VMASKMOVPD, + OP_VMASKMOVPS, + OP_VMAXPD, + OP_VMAXPS, + OP_VMAXSD, + OP_VMAXSS, + OP_VMINPD, + OP_VMINPS, + OP_VMINSD, + OP_VMINSS, + OP_VMOVAPD, + OP_VMOVAPS, + OP_VMOVD, + OP_VMOVDDUP, + OP_VMOVDQA, + OP_VMOVDQU, + OP_VMOVHPD, + OP_VMOVHPS, + OP_VMOVLHPS = OP_VMOVHPS, /**< @todo OP_VMOVHPS */ + OP_VMOVLPD, + OP_VMOVLPS, + OP_VMOVHLPS = OP_VMOVLPS, /**< @todo OP_VMOVLPS */ + OP_VMOVMSKPD, + OP_VMOVMSKPS, + OP_VMOVNTDQ, + OP_VMOVNTDQA, + OP_VMOVNTPD, + OP_VMOVNTPS, + OP_VMOVQ, + OP_VMOVSD, + OP_VMOVSHDUP, + OP_VMOVSLDUP, + OP_VMOVSS, + OP_VMOVUPD, + OP_VMOVUPS, + OP_VMPSADBW, + OP_VMULPD, + OP_VMULPS, + OP_VMULSD, + OP_VMULSS, + OP_VORPD, + OP_VORPS, + OP_VPABSB, + OP_VPABSD, + OP_VPABSW, + OP_VPACKSSDW, + OP_VPACKSSWB, + OP_VPACKUSWB, + OP_VPADDB, + OP_VPADDD, + OP_VPADDQ, + OP_VPADDSB, + OP_VPADDSW, + OP_VPADDUSB, + OP_VPADDUSW, + OP_VPADDW, + OP_VPALIGNR, + OP_VPAND, + OP_VPANDN, + OP_VPAVGB, + OP_VPAVGW, + OP_VPBLENDD, + OP_VPBLENDVB, + OP_VPBLENDW, + OP_VPBROADCASTB, + OP_VPBROADCASTD, + OP_VPBROADCASTI128, + OP_VPBROADCASTQ, + OP_VPBROADCASTW, + OP_VPCLMULQDQ, + OP_VPCMPEQB, + OP_VPCMPEQD, + OP_VPCMPEQQ, + OP_VPCMPEQW, + OP_VPCMPESTRI, + OP_VPCMPESTRM, + OP_VPCMPGTB, + OP_VPCMPGTD, + OP_VPCMPGTQ, + OP_VPCMPGTW, + OP_VPCMPISTRI, + OP_VPCMPISTRM, + OP_VPERM2F128, + OP_VPERM2I128, + OP_VPERMD, + OP_VPERMILPD, + OP_VPERMILPS, + OP_VPERMPD, + OP_VPERMPS, + OP_VPERMQ, + OP_VPEXTRB, + OP_VPEXTRD, + OP_VPEXTRW, + OP_VPEXTRQ, + OP_VPHADDD, + OP_VPHADDSW, + OP_VPHADDW, + OP_VPHMINPOSUW, + OP_VPHSUBD, + OP_VPHSUBSW, + OP_VPHSUBW, + OP_VPINSRB, + OP_VPINSRD, + OP_VPINSRW, + OP_VPINSRQ, + OP_VPMADDUBSW, + OP_VPMADDWD, + OP_VPMASKMOVD, + OP_VPMAXSB, + OP_VPMAXSD, + OP_VPMAXSW, + OP_VPMAXUB, + OP_VPMAXUD, + OP_VPMAXUW, + OP_VPMINSB, + OP_VPMINSD, + OP_VPMINSW, + OP_VPMINUB, + OP_VPMINUD, + OP_VPMINUW, + OP_VPMOVMSKB, + OP_VPMOVSXBW, + OP_VPMOVSXBD, + OP_VPMOVSXBQ, + OP_VPMOVSXWD, + OP_VPMOVSXWQ, + OP_VPMOVSXDQ, + OP_VPMOVZXBW, + OP_VPMOVZXBD, + OP_VPMOVZXBQ, + OP_VPMOVZXWD, + OP_VPMOVZXWQ, + OP_VPMOVZXDQ, + OP_VPMULDQ, + OP_VPMULHRSW, + OP_VPMULHUW, + OP_VPMULHW, + OP_VPMULLD, + OP_VPMULLW, + OP_VPMULUDQ, + OP_VPOR, + OP_VPSADBW, + OP_VPSHUFB, + OP_VPSHUFD, + OP_VPSHUFHW, + OP_VPSHUFLW, + OP_VPSIGNB, + OP_VPSIGND, + OP_VPSIGNW, + OP_VPSLLD, + OP_VPSLLQ, + OP_VPSLLVD, + OP_VPSLLW, + OP_VPSRAD, + OP_VPSRAVD, + OP_VPSRAW, + OP_VPSRLD, + OP_VPSRLQ, + OP_VPSRLVD, + OP_VPSRLW, + OP_VPSUBB, + OP_VPSUBD, + OP_VPSUBQ, + OP_VPSUBSB, + OP_VPSUBSW, + OP_VPSUBUSB, + OP_VPSUBUSW, + OP_VPSUBW, + OP_VPTEST, + OP_VPUNPCKHBW, + OP_VPUNPCKHDQ, + OP_VPUNPCKHQDQ, + OP_VPUNPCKHWD, + OP_VPUNPCKLBW, + OP_VPUNPCKLDQ, + OP_VPUNPCKLQDQ, + OP_VPUNPCKLWD, + OP_VPXOR, + OP_VRCPPS, + OP_VRCPSS, + OP_VROUNDPD, + OP_VROUNDPS, + OP_VROUNDSD, + OP_VROUNDSS, + OP_VRSQRTPS, + OP_VRSQRTSS, + OP_VSHUFPD, + OP_VSHUFPS, + OP_VSQRTPD, + OP_VSQRTPS, + OP_VSQRTSD, + OP_VSQRTSS, + OP_VSUBPD, + OP_VSUBPS, + OP_VSUBSD, + OP_VSUBSS, + OP_VTESTPD, + OP_VTESTPS, + OP_VUCOMISD, + OP_VUCOMISS, + OP_VUNPCKHPD, + OP_VUNPCKHPS, + OP_VUNPCKLPD, + OP_VUNPCKLPS, + OP_VVPACKUSDW, + OP_VXORPD, + OP_VXORPS, + OP_VZEROALL, + +/** @} */ + OP_END_OF_OPCODES +}; +AssertCompile(OP_LOCK == 7); +#if 0 +AssertCompile(OP_END_OF_OPCODES < 1024 /* see 15 byte DISOPCODE variant */); +#endif +/** @} */ + + +/** @defgroup grp_dis_opparam Opcode parameters (DISOPCODE::fParam1, + * DISOPCODE::fParam2, DISOPCODE::fParam3) + * @ingroup grp_dis + * @{ + */ + +/** + * @remarks Register order is important for translations!! + */ +enum OP_PARM +{ + OP_PARM_NONE, + + OP_PARM_REG_EAX, + OP_PARM_REG_GEN32_START = OP_PARM_REG_EAX, + OP_PARM_REG_ECX, + OP_PARM_REG_EDX, + OP_PARM_REG_EBX, + OP_PARM_REG_ESP, + OP_PARM_REG_EBP, + OP_PARM_REG_ESI, + OP_PARM_REG_EDI, + OP_PARM_REG_GEN32_END = OP_PARM_REG_EDI, + + OP_PARM_REG_ES, + OP_PARM_REG_SEG_START = OP_PARM_REG_ES, + OP_PARM_REG_CS, + OP_PARM_REG_SS, + OP_PARM_REG_DS, + OP_PARM_REG_FS, + OP_PARM_REG_GS, + OP_PARM_REG_SEG_END = OP_PARM_REG_GS, + + OP_PARM_REG_AX, + OP_PARM_REG_GEN16_START = OP_PARM_REG_AX, + OP_PARM_REG_CX, + OP_PARM_REG_DX, + OP_PARM_REG_BX, + OP_PARM_REG_SP, + OP_PARM_REG_BP, + OP_PARM_REG_SI, + OP_PARM_REG_DI, + OP_PARM_REG_GEN16_END = OP_PARM_REG_DI, + + OP_PARM_REG_AL, + OP_PARM_REG_GEN8_START = OP_PARM_REG_AL, + OP_PARM_REG_CL, + OP_PARM_REG_DL, + OP_PARM_REG_BL, + OP_PARM_REG_AH, + OP_PARM_REG_CH, + OP_PARM_REG_DH, + OP_PARM_REG_BH, + OP_PARM_REG_GEN8_END = OP_PARM_REG_BH, + + OP_PARM_REGFP_0, + OP_PARM_REG_FP_START = OP_PARM_REGFP_0, + OP_PARM_REGFP_1, + OP_PARM_REGFP_2, + OP_PARM_REGFP_3, + OP_PARM_REGFP_4, + OP_PARM_REGFP_5, + OP_PARM_REGFP_6, + OP_PARM_REGFP_7, + OP_PARM_REG_FP_END = OP_PARM_REGFP_7, + + OP_PARM_NTA, + OP_PARM_T0, + OP_PARM_T1, + OP_PARM_T2, + OP_PARM_1, + + OP_PARM_REX, + OP_PARM_REX_START = OP_PARM_REX, + OP_PARM_REX_B, + OP_PARM_REX_X, + OP_PARM_REX_XB, + OP_PARM_REX_R, + OP_PARM_REX_RB, + OP_PARM_REX_RX, + OP_PARM_REX_RXB, + OP_PARM_REX_W, + OP_PARM_REX_WB, + OP_PARM_REX_WX, + OP_PARM_REX_WXB, + OP_PARM_REX_WR, + OP_PARM_REX_WRB, + OP_PARM_REX_WRX, + OP_PARM_REX_WRXB, + + OP_PARM_REG_RAX, + OP_PARM_REG_GEN64_START = OP_PARM_REG_RAX, + OP_PARM_REG_RCX, + OP_PARM_REG_RDX, + OP_PARM_REG_RBX, + OP_PARM_REG_RSP, + OP_PARM_REG_RBP, + OP_PARM_REG_RSI, + OP_PARM_REG_RDI, + OP_PARM_REG_R8, + OP_PARM_REG_R9, + OP_PARM_REG_R10, + OP_PARM_REG_R11, + OP_PARM_REG_R12, + OP_PARM_REG_R13, + OP_PARM_REG_R14, + OP_PARM_REG_R15, + OP_PARM_REG_GEN64_END = OP_PARM_REG_R15 +}; + + +/* 8-bit GRP aliases (for IEM). */ +#define OP_PARM_AL OP_PARM_REG_AL + +/* GPR aliases for op-size specified register sizes (for IEM). */ +#define OP_PARM_rAX OP_PARM_REG_EAX +#define OP_PARM_rCX OP_PARM_REG_ECX +#define OP_PARM_rDX OP_PARM_REG_EDX +#define OP_PARM_rBX OP_PARM_REG_EBX +#define OP_PARM_rSP OP_PARM_REG_ESP +#define OP_PARM_rBP OP_PARM_REG_EBP +#define OP_PARM_rSI OP_PARM_REG_ESI +#define OP_PARM_rDI OP_PARM_REG_EDI + +/* SREG aliases (for IEM). */ +#define OP_PARM_ES OP_PARM_REG_ES +#define OP_PARM_CS OP_PARM_REG_CS +#define OP_PARM_SS OP_PARM_REG_SS +#define OP_PARM_DS OP_PARM_REG_DS +#define OP_PARM_FS OP_PARM_REG_FS +#define OP_PARM_GS OP_PARM_REG_GS + +/* + * Note! We don't document anything here if we can help it, because it we love + * wasting other peoples time figuring out crypting crap. The new VEX + * stuff of course uphelds this vexing tradition. Aaaaaaaaaaaaaaaaaaarg! + */ + +#define OP_PARM_VTYPE(a) ((unsigned)a & 0xFE0) +#define OP_PARM_VSUBTYPE(a) ((unsigned)a & 0x01F) + +#define OP_PARM_A 0x100 +#define OP_PARM_VARIABLE OP_PARM_A +#define OP_PARM_E 0x120 +#define OP_PARM_F 0x140 +#define OP_PARM_G 0x160 +#define OP_PARM_I 0x180 +#define OP_PARM_J 0x1A0 +#define OP_PARM_M 0x1C0 +#define OP_PARM_O 0x1E0 +#define OP_PARM_R 0x200 +#define OP_PARM_X 0x220 +#define OP_PARM_Y 0x240 + +/* Grouped rare parameters for optimization purposes */ +#define IS_OP_PARM_RARE(a) ((a & 0xF00) >= 0x300) +#define OP_PARM_C 0x300 /* control register */ +#define OP_PARM_D 0x320 /* debug register */ +#define OP_PARM_S 0x340 /* segment register */ +#define OP_PARM_T 0x360 /* test register */ +#define OP_PARM_Q 0x380 +#define OP_PARM_P 0x3A0 /* mmx register */ +#define OP_PARM_W 0x3C0 /* xmm register */ +#define OP_PARM_V 0x3E0 +#define OP_PARM_U 0x400 /* The R/M field of the ModR/M byte selects XMM/YMM register. */ +#define OP_PARM_B 0x420 /* VEX.vvvv field select general purpose register. */ +#define OP_PARM_H 0x440 +#define OP_PARM_L 0x460 + +#define OP_PARM_NONE 0 +#define OP_PARM_a 0x1 /**< Operand to bound instruction. */ +#define OP_PARM_b 0x2 /**< Byte (always). */ +#define OP_PARM_d 0x3 /**< Double word (always). */ +#define OP_PARM_dq 0x4 /**< Double quad word (always). */ +#define OP_PARM_p 0x5 /**< Far pointer (subject to opsize). */ +#define OP_PARM_pd 0x6 /**< 128-bit or 256-bit double precision floating point data. */ +#define OP_PARM_pi 0x7 /**< Quad word MMX register. */ +#define OP_PARM_ps 0x8 /**< 128-bit or 256-bit single precision floating point data. */ +#define OP_PARM_q 0xA /**< Quad word (always). */ +#define OP_PARM_s 0xB /**< Descriptor table size (SIDT/LIDT/SGDT/LGDT). */ +#define OP_PARM_sd 0xC /**< Scalar element of 128-bit double precision floating point data. */ +#define OP_PARM_ss 0xD /**< Scalar element of 128-bit single precision floating point data. */ +#define OP_PARM_v 0xE /**< Word, double word, or quad word depending on opsize. */ +#define OP_PARM_w 0xF /**< Word (always). */ +#define OP_PARM_x 0x10 /**< Double quad word (dq) or quad quad word (qq) depending on opsize. */ +#define OP_PARM_y 0x11 /**< Double word or quad word depending on opsize. */ +#define OP_PARM_z 0x12 /**< Word (16-bit opsize) or double word (32-bit/64-bit opsize). */ +#define OP_PARM_qq 0x13 /**< Quad quad word. */ + + +#define OP_PARM_Ap (OP_PARM_A+OP_PARM_p) +#define OP_PARM_By (OP_PARM_B+OP_PARM_y) +#define OP_PARM_Cd (OP_PARM_C+OP_PARM_d) +#define OP_PARM_Dd (OP_PARM_D+OP_PARM_d) +#define OP_PARM_Eb (OP_PARM_E+OP_PARM_b) +#define OP_PARM_Ed (OP_PARM_E+OP_PARM_d) +#define OP_PARM_Ep (OP_PARM_E+OP_PARM_p) +#define OP_PARM_Ev (OP_PARM_E+OP_PARM_v) +#define OP_PARM_Ew (OP_PARM_E+OP_PARM_w) +#define OP_PARM_Ey (OP_PARM_E+OP_PARM_y) +#define OP_PARM_Fv (OP_PARM_F+OP_PARM_v) +#define OP_PARM_Gb (OP_PARM_G+OP_PARM_b) +#define OP_PARM_Gd (OP_PARM_G+OP_PARM_d) +#define OP_PARM_Gv (OP_PARM_G+OP_PARM_v) +#define OP_PARM_Gw (OP_PARM_G+OP_PARM_w) +#define OP_PARM_Gy (OP_PARM_G+OP_PARM_y) +#define OP_PARM_Hq (OP_PARM_H+OP_PARM_q) +#define OP_PARM_Hps (OP_PARM_H+OP_PARM_ps) +#define OP_PARM_Hpd (OP_PARM_H+OP_PARM_pd) +#define OP_PARM_Hdq (OP_PARM_H+OP_PARM_dq) +#define OP_PARM_Hqq (OP_PARM_H+OP_PARM_qq) +#define OP_PARM_Hsd (OP_PARM_H+OP_PARM_sd) +#define OP_PARM_Hss (OP_PARM_H+OP_PARM_ss) +#define OP_PARM_Hx (OP_PARM_H+OP_PARM_x) +#define OP_PARM_Ib (OP_PARM_I+OP_PARM_b) +#define OP_PARM_Id (OP_PARM_I+OP_PARM_d) +#define OP_PARM_Iq (OP_PARM_I+OP_PARM_q) +#define OP_PARM_Iw (OP_PARM_I+OP_PARM_w) +#define OP_PARM_Iv (OP_PARM_I+OP_PARM_v) +#define OP_PARM_Iz (OP_PARM_I+OP_PARM_z) +#define OP_PARM_Jb (OP_PARM_J+OP_PARM_b) +#define OP_PARM_Jv (OP_PARM_J+OP_PARM_v) +#define OP_PARM_Ma (OP_PARM_M+OP_PARM_a) +#define OP_PARM_Mb (OP_PARM_M+OP_PARM_b) +#define OP_PARM_Mw (OP_PARM_M+OP_PARM_w) +#define OP_PARM_Md (OP_PARM_M+OP_PARM_d) +#define OP_PARM_Mp (OP_PARM_M+OP_PARM_p) +#define OP_PARM_Mq (OP_PARM_M+OP_PARM_q) +#define OP_PARM_Mdq (OP_PARM_M+OP_PARM_dq) +#define OP_PARM_Ms (OP_PARM_M+OP_PARM_s) +#define OP_PARM_Mx (OP_PARM_M+OP_PARM_x) +#define OP_PARM_My (OP_PARM_M+OP_PARM_y) +#define OP_PARM_Mps (OP_PARM_M+OP_PARM_ps) +#define OP_PARM_Mpd (OP_PARM_M+OP_PARM_pd) +#define OP_PARM_Ob (OP_PARM_O+OP_PARM_b) +#define OP_PARM_Ov (OP_PARM_O+OP_PARM_v) +#define OP_PARM_Pq (OP_PARM_P+OP_PARM_q) +#define OP_PARM_Pd (OP_PARM_P+OP_PARM_d) +#define OP_PARM_Qd (OP_PARM_Q+OP_PARM_d) +#define OP_PARM_Qq (OP_PARM_Q+OP_PARM_q) +#define OP_PARM_Rd (OP_PARM_R+OP_PARM_d) +#define OP_PARM_Rw (OP_PARM_R+OP_PARM_w) +#define OP_PARM_Ry (OP_PARM_R+OP_PARM_y) +#define OP_PARM_Sw (OP_PARM_S+OP_PARM_w) +#define OP_PARM_Td (OP_PARM_T+OP_PARM_d) +#define OP_PARM_Ux (OP_PARM_U+OP_PARM_x) +#define OP_PARM_Vq (OP_PARM_V+OP_PARM_q) +#define OP_PARM_Vx (OP_PARM_V+OP_PARM_x) +#define OP_PARM_Vy (OP_PARM_V+OP_PARM_y) +#define OP_PARM_Wq (OP_PARM_W+OP_PARM_q) +/*#define OP_PARM_Ws (OP_PARM_W+OP_PARM_s) - wtf? Same as lgdt (OP_PARM_Ms)?*/ +#define OP_PARM_Wx (OP_PARM_W+OP_PARM_x) +#define OP_PARM_Xb (OP_PARM_X+OP_PARM_b) +#define OP_PARM_Xv (OP_PARM_X+OP_PARM_v) +#define OP_PARM_Yb (OP_PARM_Y+OP_PARM_b) +#define OP_PARM_Yv (OP_PARM_Y+OP_PARM_v) + +#define OP_PARM_Vps (OP_PARM_V+OP_PARM_ps) +#define OP_PARM_Vss (OP_PARM_V+OP_PARM_ss) +#define OP_PARM_Vpd (OP_PARM_V+OP_PARM_pd) +#define OP_PARM_Vdq (OP_PARM_V+OP_PARM_dq) +#define OP_PARM_Wps (OP_PARM_W+OP_PARM_ps) +#define OP_PARM_Wpd (OP_PARM_W+OP_PARM_pd) +#define OP_PARM_Wss (OP_PARM_W+OP_PARM_ss) +#define OP_PARM_Ww (OP_PARM_W+OP_PARM_w) +#define OP_PARM_Wd (OP_PARM_W+OP_PARM_d) +#define OP_PARM_Wq (OP_PARM_W+OP_PARM_q) +#define OP_PARM_Wdq (OP_PARM_W+OP_PARM_dq) +#define OP_PARM_Wqq (OP_PARM_W+OP_PARM_qq) +#define OP_PARM_Ppi (OP_PARM_P+OP_PARM_pi) +#define OP_PARM_Qpi (OP_PARM_Q+OP_PARM_pi) +#define OP_PARM_Qdq (OP_PARM_Q+OP_PARM_dq) +#define OP_PARM_Vsd (OP_PARM_V+OP_PARM_sd) +#define OP_PARM_Wsd (OP_PARM_W+OP_PARM_sd) +#define OP_PARM_Vqq (OP_PARM_V+OP_PARM_qq) +#define OP_PARM_Pdq (OP_PARM_P+OP_PARM_dq) +#define OP_PARM_Ups (OP_PARM_U+OP_PARM_ps) +#define OP_PARM_Upd (OP_PARM_U+OP_PARM_pd) +#define OP_PARM_Udq (OP_PARM_U+OP_PARM_dq) +#define OP_PARM_Lx (OP_PARM_L+OP_PARM_x) + +/* For making IEM / bs3-cpu-generated-1 happy: */ +#define OP_PARM_Ed_WO OP_PARM_Ed /**< Annotates write only operand. */ +#define OP_PARM_Eq (OP_PARM_E+OP_PARM_q) +#define OP_PARM_Eq_WO OP_PARM_Eq /**< Annotates write only operand. */ +#define OP_PARM_Gv_RO OP_PARM_Gv /**< Annotates read only first operand (default is readwrite). */ +#define OP_PARM_HssHi OP_PARM_Hx /**< Register referenced by VEX.vvvv, bits [127:32]. */ +#define OP_PARM_HsdHi OP_PARM_Hx /**< Register referenced by VEX.vvvv, bits [127:64]. */ +#define OP_PARM_HqHi OP_PARM_Hx /**< Register referenced by VEX.vvvv, bits [127:64]. */ +#define OP_PARM_M_RO OP_PARM_M /**< Annotates read only memory of variable operand size (xrstor). */ +#define OP_PARM_M_RW OP_PARM_M /**< Annotates read-write memory of variable operand size (xsave). */ +#define OP_PARM_Mb_RO OP_PARM_Mb /**< Annotates read only memory byte operand. */ +#define OP_PARM_Md_RO OP_PARM_Md /**< Annotates read only memory operand. */ +#define OP_PARM_Md_WO OP_PARM_Md /**< Annotates write only memory operand. */ +#define OP_PARM_Mdq_WO OP_PARM_Mdq /**< Annotates write only memory operand. */ +#define OP_PARM_Mq_WO OP_PARM_Mq /**< Annotates write only memory quad word operand. */ +#define OP_PARM_Mps_WO OP_PARM_Mps /**< Annotates write only memory operand. */ +#define OP_PARM_Mpd_WO OP_PARM_Mpd /**< Annotates write only memory operand. */ +#define OP_PARM_Mx_WO OP_PARM_Mx /**< Annotates write only memory operand. */ +#define OP_PARM_PdZx_WO OP_PARM_Pd /**< Annotates write only operand and zero extends to 64-bit. */ +#define OP_PARM_Pq_WO OP_PARM_Pq /**< Annotates write only operand. */ +#define OP_PARM_Qq_WO OP_PARM_Qq /**< Annotates write only operand. */ +#define OP_PARM_Nq OP_PARM_Qq /**< Missing 'N' class (MMX reg selected by modrm.mem) in disasm. */ +#define OP_PARM_Uq (OP_PARM_U+OP_PARM_q) +#define OP_PARM_UqHi (OP_PARM_U+OP_PARM_dq) +#define OP_PARM_Uss (OP_PARM_U+OP_PARM_ss) +#define OP_PARM_Uss_WO OP_PARM_Uss /**< Annotates write only operand. */ +#define OP_PARM_Usd (OP_PARM_U+OP_PARM_sd) +#define OP_PARM_Usd_WO OP_PARM_Usd /**< Annotates write only operand. */ +#define OP_PARM_Vd (OP_PARM_V+OP_PARM_d) +#define OP_PARM_Vd_WO OP_PARM_Vd /**< Annotates write only operand. */ +#define OP_PARM_VdZx_WO OP_PARM_Vd /**< Annotates that the registers get their upper bits cleared */ +#define OP_PARM_Vdq_WO OP_PARM_Vdq /**< Annotates that only YMM/XMM[127:64] are accessed. */ +#define OP_PARM_Vpd_WO OP_PARM_Vpd /**< Annotates write only operand. */ +#define OP_PARM_Vps_WO OP_PARM_Vps /**< Annotates write only operand. */ +#define OP_PARM_Vq_WO OP_PARM_Vq /**< Annotates write only operand. */ +#define OP_PARM_VqHi OP_PARM_Vdq /**< Annotates that only YMM/XMM[127:64] are accessed. */ +#define OP_PARM_VqHi_WO OP_PARM_Vdq /**< Annotates that only YMM/XMM[127:64] are written. */ +#define OP_PARM_VqZx_WO OP_PARM_Vq /**< Annotates that the registers get their upper bits cleared */ +#define OP_PARM_VsdZx_WO OP_PARM_Vsd /**< Annotates that the registers get their upper bits cleared. */ +#define OP_PARM_VssZx_WO OP_PARM_Vss /**< Annotates that the registers get their upper bits cleared. */ +#define OP_PARM_Vss_WO OP_PARM_Vss /**< Annotates write only operand. */ +#define OP_PARM_Vsd_WO OP_PARM_Vsd /**< Annotates write only operand. */ +#define OP_PARM_Vx_WO OP_PARM_Vx /**< Annotates write only operand. */ +#define OP_PARM_Wpd_WO OP_PARM_Wpd /**< Annotates write only operand. */ +#define OP_PARM_Wps_WO OP_PARM_Wps /**< Annotates write only operand. */ +#define OP_PARM_Wq_WO OP_PARM_Wq /**< Annotates write only operand. */ +#define OP_PARM_WqZxReg_WO OP_PARM_Wq /**< Annotates that register targets get their upper bits cleared. */ +#define OP_PARM_Wss_WO OP_PARM_Wss /**< Annotates write only operand. */ +#define OP_PARM_Wsd_WO OP_PARM_Wsd /**< Annotates write only operand. */ +#define OP_PARM_Wx_WO OP_PARM_Wx /**< Annotates write only operand. */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_disopcode_h */ + diff --git a/include/VBox/err.h b/include/VBox/err.h new file mode 100644 index 00000000..983d9454 --- /dev/null +++ b/include/VBox/err.h @@ -0,0 +1,3148 @@ +/** @file + * VirtualBox Status Codes. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_err_h +#define VBOX_INCLUDED_err_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_err VBox Error Codes + * @{ + */ + +/* SED-START */ + +/** @name Misc. Status Codes + * @{ + */ +/** Failed to allocate VM memory. */ +#define VERR_NO_VM_MEMORY (-1000) +/** RC is toasted and the VMM should be terminated at once, but no need to + * panic about it :-) */ +#define VERR_DONT_PANIC (-1001) +/** Unsupported CPU. */ +#define VERR_UNSUPPORTED_CPU (-1002) +/** Unsupported CPU mode. */ +#define VERR_UNSUPPORTED_CPU_MODE (-1003) +/** Page not present. */ +#define VERR_PAGE_NOT_PRESENT (-1004) +/** Invalid/Corrupted configuration file. */ +#define VERR_CFG_INVALID_FORMAT (-1005) +/** No configuration value exists. */ +#define VERR_CFG_NO_VALUE (-1006) +/** Selector not present. */ +#define VERR_SELECTOR_NOT_PRESENT (-1007) +/** Not code selector. */ +#define VERR_NOT_CODE_SELECTOR (-1008) +/** Not data selector. */ +#define VERR_NOT_DATA_SELECTOR (-1009) +/** Out of selector bounds. */ +#define VERR_OUT_OF_SELECTOR_BOUNDS (-1010) +/** Invalid selector. Usually beyond table limits. */ +#define VERR_INVALID_SELECTOR (-1011) +/** Invalid requested privilege level. */ +#define VERR_INVALID_RPL (-1012) +/** PML4 entry not present. */ +#define VERR_PAGE_MAP_LEVEL4_NOT_PRESENT (-1013) +/** Page directory pointer not present. */ +#define VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT (-1014) +/** Raw mode doesn't support SMP. */ +#define VERR_RAW_MODE_INVALID_SMP (-1015) +/** Invalid VM handle. */ +#define VERR_INVALID_VM_HANDLE (-1016) +/** Invalid VM handle. */ +#define VERR_INVALID_VMCPU_HANDLE (-1017) +/** Invalid Virtual CPU ID. */ +#define VERR_INVALID_CPU_ID (-1018) +/** Too many VCPUs. */ +#define VERR_TOO_MANY_CPUS (-1019) +/** The service was disabled on the host. + * Returned by pfnInit in VBoxService to indicated a non-fatal error that + * should results in the particular service being disabled. */ +#define VERR_SERVICE_DISABLED (-1020) +/** The requested feature is not supported in raw-mode. */ +#define VERR_NOT_SUP_IN_RAW_MODE (-1021) +/** Invalid CPU index. */ +#define VERR_INVALID_CPU_INDEX (-1022) +/** This VirtualBox build does not support raw-mode. */ +#define VERR_RAW_MODE_NOT_SUPPORTED (-1023) +/** Essential fields in the shared VM structure doesn't match the global one. */ +#define VERR_INCONSISTENT_VM_HANDLE (-1024) +/** The VM has been restored. */ +#define VERR_VM_RESTORED (-1025) +/** The requested feature is not supported by NEM. */ +#define VERR_NOT_SUP_BY_NEM (-1026) +/** @} */ + + +/** @name Execution Monitor/Manager (EM) Status Codes + * + * The order of the status codes between VINF_EM_FIRST and VINF_EM_LAST + * are of vital importance. The lower the number the higher importance + * as a scheduling instruction. + * @{ + */ +/** First scheduling related status code. */ +#define VINF_EM_FIRST 1100 +/** Indicating that the VM is being terminated and that the execution + * shall stop. */ +#define VINF_EM_TERMINATE 1100 +/** Hypervisor code was stepped. + * EM will first send this to the debugger, and if the issue isn't + * resolved there it will enter guru meditation. */ +#define VINF_EM_DBG_HYPER_STEPPED 1101 +/** Hit a breakpoint in the hypervisor code, + * EM will first send this to the debugger, and if the issue isn't + * resolved there it will enter guru meditation. */ +#define VINF_EM_DBG_HYPER_BREAKPOINT 1102 +/** Hit a possible assertion in the hypervisor code, + * EM will first send this to the debugger, and if the issue isn't + * resolved there it will enter guru meditation. */ +#define VINF_EM_DBG_HYPER_ASSERTION 1103 +/** Generic debug event, suspend the VM for debugging. */ +#define VINF_EM_DBG_EVENT 1104 +/** Indicating that the VM should be suspended for debugging because + * the developer wants to inspect the VM state. */ +#define VINF_EM_DBG_STOP 1105 +/** Indicating success single stepping and that EM should report that + * event to the debugger. */ +#define VINF_EM_DBG_STEPPED 1106 +/** Indicating that a breakpoint was hit and that EM should notify the debugger + * and in the event there is no debugger fail fatally. */ +#define VINF_EM_DBG_BREAKPOINT 1107 +/** Indicating that EM should single step an instruction. + * The instruction is stepped in the current execution mode (RAW/REM). */ +#define VINF_EM_DBG_STEP 1108 +/** Indicating that the VM is being turned off and that the EM should + * exit to the VM awaiting the destruction request. */ +#define VINF_EM_OFF 1109 +/** Indicating that the VM has been suspended and that the thread + * should wait for request telling it what to do next. */ +#define VINF_EM_SUSPEND 1110 +/** Indicating that the VM has been reset and that scheduling goes + * back to startup defaults. */ +#define VINF_EM_RESET 1111 +/** Indicating that the VM has executed a halt instruction and that + * the emulation thread should wait for an interrupt before resuming + * execution. */ +#define VINF_EM_HALT 1112 +/** Indicating that the VM has been resumed and that the thread should + * start executing. */ +#define VINF_EM_RESUME 1113 +/** Indicating that we've got an out-of-memory condition and that we need + * to take the appropriate actions to deal with this. + * @remarks It might seem odd at first that this has lower priority than VINF_EM_HALT, + * VINF_EM_SUSPEND, and VINF_EM_RESUME. The reason is that these events are + * vital to correctly operating the VM. Also, they can't normally occur together + * with an out-of-memory condition, and even if that should happen the condition + * will be rediscovered before executing any more code. */ +#define VINF_EM_NO_MEMORY 1114 +/** The fatal variant of VINF_EM_NO_MEMORY. */ +#define VERR_EM_NO_MEMORY (-1114) +/** Indicating that a rescheduling to recompiled execution. + * Typically caused by raw-mode executing code which is difficult/slow + * to virtualize rawly. + * @remarks Important to have a higher priority (lower number) than the other rescheduling status codes. */ +#define VINF_EM_RESCHEDULE_REM 1115 +/** Indicating that a rescheduling to vmx-mode execution (HM/NEM). + * Typically caused by REM detecting that hardware-accelerated raw-mode execution is possible. */ +#define VINF_EM_RESCHEDULE_HM 1116 +/** Indicating that a rescheduling to raw-mode execution. + * Typically caused by REM detecting that raw-mode execution is possible. + * @remarks Important to have a higher priority (lower number) than VINF_EM_RESCHEDULE. */ +#define VINF_EM_RESCHEDULE_RAW 1117 +/** Indicating that a rescheduling now is required. Typically caused by + * interrupts having changed the EIP. */ +#define VINF_EM_RESCHEDULE 1118 +/** PARAV call */ +#define VINF_EM_RESCHEDULE_PARAV 1119 +/** Go back into wait for SIPI mode */ +#define VINF_EM_WAIT_SIPI 1120 +/** Last scheduling related status code. (inclusive) */ +#define VINF_EM_LAST 1120 + +/** Reason for leaving RC: Guest trap which couldn't be handled in RC. + * The trap is generally forwarded to the REM and executed there. */ +#define VINF_EM_RAW_GUEST_TRAP 1121 +/** Reason for leaving RC: Interrupted by external interrupt. + * The interrupt needed to be handled by the host OS. */ +#define VINF_EM_RAW_INTERRUPT 1122 +/** Reason for leaving RC: Interrupted by external interrupt while in hypervisor + * code. The interrupt needed to be handled by the host OS and hypervisor + * execution must be resumed. VM state is not complete at this point. */ +#define VINF_EM_RAW_INTERRUPT_HYPER 1123 +/** Reason for leaving RC: A Ring switch was attempted. + * Normal cause of action is to execute this in REM. */ +#define VINF_EM_RAW_RING_SWITCH 1124 +/** Reason for leaving RC: A Ring switch was attempted using software interrupt. + * Normal cause of action is to execute this in REM. */ +#define VINF_EM_RAW_RING_SWITCH_INT 1125 +/** Reason for leaving RC: A privileged instruction was attempted executed. + * Normal cause of action is to execute this in REM. */ +#define VINF_EM_RAW_EXCEPTION_PRIVILEGED 1126 + +/** Reason for leaving RZ: Emulate instruction. */ +#define VINF_EM_RAW_EMULATE_INSTR 1127 +/** Reason for leaving RC: Unhandled TSS write. + * Recompiler gets control. */ +#define VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT 1128 +/** Reason for leaving RC: Unhandled LDT write. + * Recompiler gets control. */ +#define VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT 1129 +/** Reason for leaving RC: Unhandled IDT write. + * Recompiler gets control. */ +#define VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT 1130 +/** Reason for leaving RC: Partly handled GDT write. + * Recompiler gets control. */ +#define VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT 1131 +/** Reason for leaving RC: jump inside generated patch jump. + * Fatal error. */ +#define VERR_EM_RAW_PATCH_CONFLICT (-1133) +/** Reason for leaving RZ: Ring-3 operation pending. */ +#define VINF_EM_RAW_TO_R3 1135 +/** Reason for leaving RZ: Timer pending. */ +#define VINF_EM_RAW_TIMER_PENDING 1136 +/** Reason for leaving RC: Interrupt pending (guest). */ +#define VINF_EM_RAW_INTERRUPT_PENDING 1137 +/** Reason for leaving RC: Encountered a stale selector. */ +#define VINF_EM_RAW_STALE_SELECTOR 1138 +/** Reason for leaving RC: The IRET resuming guest code trapped. */ +#define VINF_EM_RAW_IRET_TRAP 1139 +/** The interpreter was unable to deal with the instruction at hand. */ +#define VERR_EM_INTERPRETER (-1148) +/** Internal EM error caused by an unknown warning or informational status code. */ +#define VERR_EM_INTERNAL_ERROR (-1149) +/** Pending VM request packet. */ +#define VINF_EM_PENDING_REQUEST 1150 +/** Start instruction stepping (debug only). */ +#define VINF_EM_RAW_EMULATE_DBG_STEP 1151 +/** Patch TPR access instruction. */ +#define VINF_EM_HM_PATCH_TPR_INSTR 1152 +/** Unexpected guest mapping conflict detected. */ +#define VERR_EM_UNEXPECTED_MAPPING_CONFLICT (-1154) +/** Reason for leaving RC: A triple-fault condition. Currently, causes + * a guru meditation. */ +#define VINF_EM_TRIPLE_FAULT 1155 +/** The specified execution engine cannot execute guest code in the current + * state. */ +#define VERR_EM_CANNOT_EXEC_GUEST (-1156) +/** Reason for leaving RC: Inject a TRPM event. */ +#define VINF_EM_RAW_INJECT_TRPM_EVENT 1157 +/** Guest tried to trigger a CPU hang. The guest is probably up to no good. */ +#define VERR_EM_GUEST_CPU_HANG (-1158) +/** Reason for leaving RZ: Pending ring-3 IN instruction. */ +#define VINF_EM_PENDING_R3_IOPORT_READ 1159 +/** Reason for leaving RZ: Pending ring-3 OUT instruction. */ +#define VINF_EM_PENDING_R3_IOPORT_WRITE 1160 +/** Trick for resuming EMHistoryExec after a VMCPU_FF_IOM is handled. */ +#define VINF_EM_RESUME_R3_HISTORY_EXEC 1161 +/** Emulate split-lock access on SMP. */ +#define VINF_EM_EMULATE_SPLIT_LOCK 1162 +/** @} */ + + +/** @name Debugging Facility (DBGF) DBGF Status Codes + * @{ + */ +/** The function called requires the caller to be attached as a + * debugger to the VM. */ +#define VERR_DBGF_NOT_ATTACHED (-1200) +/** Someone (including the caller) was already attached as + * debugger to the VM. */ +#define VERR_DBGF_ALREADY_ATTACHED (-1201) +/** Tried to halt a VM or CPU that was already halted. */ +#define VWRN_DBGF_ALREADY_HALTED 1202 +/** The DBGF has no more free breakpoint slots. */ +#define VERR_DBGF_NO_MORE_BP_SLOTS (-1203) +/** The DBGF couldn't find the specified breakpoint. */ +#define VERR_DBGF_BP_NOT_FOUND (-1204) +/** Attempted to enabled a breakpoint which was already enabled. */ +#define VINF_DBGF_BP_ALREADY_ENABLED 1205 +/** Attempted to disabled a breakpoint which was already disabled. */ +#define VINF_DBGF_BP_ALREADY_DISABLED 1206 +/** The breakpoint already exists. */ +#define VINF_DBGF_BP_ALREADY_EXIST 1207 +/** The byte string was not found. */ +#define VERR_DBGF_MEM_NOT_FOUND (-1208) +/** The OS was not detected. */ +#define VERR_DBGF_OS_NOT_DETCTED (-1209) +/** The OS was not detected. */ +#define VINF_DBGF_OS_NOT_DETCTED 1209 +/** The specified register was not found. */ +#define VERR_DBGF_REGISTER_NOT_FOUND (-1210) +/** The value was truncated to fit. + * For queries this means that the register is wider than the queried value. + * For setters this means that the value is wider than the register. */ +#define VINF_DBGF_TRUNCATED_REGISTER 1211 +/** The value was zero extended to fit. + * For queries this means that the register is narrower than the queried value. + * For setters this means that the value is narrower than the register. */ +#define VINF_DBGF_ZERO_EXTENDED_REGISTER 1212 +/** The requested type conversion was not supported. */ +#define VERR_DBGF_UNSUPPORTED_CAST (-1213) +/** The register is read-only and cannot be modified. */ +#define VERR_DBGF_READ_ONLY_REGISTER (-1214) +/** Internal processing error \#1 in the DBGF register code. */ +#define VERR_DBGF_REG_IPE_1 (-1215) +/** Internal processing error \#2 in the DBGF register code. */ +#define VERR_DBGF_REG_IPE_2 (-1216) +/** Unhandled \#DB in hypervisor code. */ +#define VERR_DBGF_HYPER_DB_XCPT (-1217) +/** Internal processing error \#1 in the DBGF stack code. */ +#define VERR_DBGF_STACK_IPE_1 (-1218) +/** Internal processing error \#2 in the DBGF stack code. */ +#define VERR_DBGF_STACK_IPE_2 (-1219) +/** No trace buffer available, please change the VM config. */ +#define VERR_DBGF_NO_TRACE_BUFFER (-1220) +/** Internal processing error \#1 in the DBGF event tracing code. */ +#define VERR_DBGF_TRACER_IPE_1 (-1221) +/** Tried to resume a VM or CPU that is already fully running. */ +#define VWRN_DBGF_ALREADY_RUNNING (-1222) +/** Internal processing error \#1 in the DBGF core code. */ +#define VERR_DBGF_IPE_1 (-1223) +/** Returned by a breakpoint callback when guest execution should be suspended + * and the VM should be dropped into the debugger. */ +#define VINF_DBGF_BP_HALT (1224) +/** The breakpoint owner handle is still used by one or more breakpoints. */ +#define VERR_DBGF_OWNER_BUSY (-1225) +/** Number of tries to add an int3 breakpoint table to the lookup tables reached. */ +#define VERR_DBGF_BP_INT3_ADD_TRIES_REACHED (-1226) +/** Internal processing error \#1 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_1 (-1227) +/** Internal processing error \#2 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_2 (-1228) +/** Internal processing error \#3 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_3 (-1229) +/** Internal processing error \#4 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_4 (-1230) +/** Internal processing error \#5 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_5 (-1231) +/** Internal processing error \#6 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_6 (-1232) +/** Internal processing error \#7 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_7 (-1233) +/** Internal processing error \#8 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_8 (-1234) +/** Internal processing error \#9 in the DBGF breakpoint manager code. */ +#define VERR_DBGF_BP_IPE_9 (-1235) +/** Level 2 lookup failed because the L1 lookup table is corrupted. */ +#define VERR_DBGF_BP_L1_LOOKUP_FAILED (-1236) +/** Level 2 lookup failed because the L2 lookup table is corrupted. */ +#define VERR_DBGF_BP_L2_LOOKUP_FAILED (-1237) +/** The DBGF has no more free breakpoint owner handles. */ +#define VERR_DBGF_BP_OWNER_NO_MORE_HANDLES (-1238) +/** Reason for leaving RZ: Defer the owner callback invocation to Ring-3. */ +#define VINF_DBGF_R3_BP_OWNER_DEFER 1239 +/** The breakpoint owner callback returned an invalid status code. */ +#define VERR_DBGF_BP_OWNER_CALLBACK_WRONG_STATUS (-1240) +/** The operation was cancelled. */ +#define VERR_DBGF_CANCELLED (-1241) +/** @} */ + + +/** @name Patch Manager (PATM) Status Codes + * @{ + */ +/** Non fatal Patch Manager analysis phase warning */ +#define VWRN_CONTINUE_ANALYSIS 1400 +/** Non fatal Patch Manager recompile phase warning (mapped to VWRN_CONTINUE_ANALYSIS). */ +#define VWRN_CONTINUE_RECOMPILE VWRN_CONTINUE_ANALYSIS +/** Continue search (mapped to VWRN_CONTINUE_ANALYSIS). */ +#define VWRN_PATM_CONTINUE_SEARCH VWRN_CONTINUE_ANALYSIS +/** Patch installation refused (patch too complex or unsupported instructions ) */ +#define VERR_PATCHING_REFUSED (-1401) +/** Unable to find patch */ +#define VERR_PATCH_NOT_FOUND (-1402) +/** Patch disabled */ +#define VERR_PATCH_DISABLED (-1403) +/** Patch enabled */ +#define VWRN_PATCH_ENABLED 1404 +/** Patch was already disabled */ +#define VERR_PATCH_ALREADY_DISABLED (-1405) +/** Patch was already enabled */ +#define VERR_PATCH_ALREADY_ENABLED (-1406) +/** Patch was removed. */ +#define VWRN_PATCH_REMOVED 1407 + +/** Reason for leaving RC: \#GP with EIP pointing to patch code. */ +#define VINF_PATM_PATCH_TRAP_GP 1408 +/** First leave RC code. */ +#define VINF_PATM_LEAVE_RC_FIRST VINF_PATM_PATCH_TRAP_GP +/** Reason for leaving RC: \#PF with EIP pointing to patch code. */ +#define VINF_PATM_PATCH_TRAP_PF 1409 +/** Reason for leaving RC: int3 with EIP pointing to patch code. */ +#define VINF_PATM_PATCH_INT3 1410 +/** Reason for leaving RC: \#PF for monitored patch page. */ +#define VINF_PATM_CHECK_PATCH_PAGE 1411 +/** Reason for leaving RC: duplicate instruction called at current eip. */ +#define VINF_PATM_DUPLICATE_FUNCTION 1412 +/** Execute one instruction with the recompiler */ +#define VINF_PATCH_EMULATE_INSTR 1413 +/** Reason for leaving RC: attempt to patch MMIO write. */ +#define VINF_PATM_HC_MMIO_PATCH_WRITE 1414 +/** Reason for leaving RC: attempt to patch MMIO read. */ +#define VINF_PATM_HC_MMIO_PATCH_READ 1415 +/** Reason for leaving RC: pending irq after iret that sets IF. */ +#define VINF_PATM_PENDING_IRQ_AFTER_IRET 1416 +/** Last leave RC code. */ +#define VINF_PATM_LEAVE_RC_LAST VINF_PATM_PENDING_IRQ_AFTER_IRET + +/** No conflicts to resolve */ +#define VERR_PATCH_NO_CONFLICT (-1425) +/** Detected unsafe code for patching */ +#define VERR_PATM_UNSAFE_CODE (-1426) +/** Terminate search branch */ +#define VWRN_PATCH_END_BRANCH 1427 +/** Already patched */ +#define VERR_PATM_ALREADY_PATCHED (-1428) +/** Spinlock detection failed. */ +#define VINF_PATM_SPINLOCK_FAILED (1429) +/** Continue execution after patch trap. */ +#define VINF_PATCH_CONTINUE (1430) +/** The patch manager is not used because we're using HM and VT-x/AMD-V. */ +#define VERR_PATM_HM_IPE (-1431) +/** Unexpected trap in patch code. */ +#define VERR_PATM_IPE_TRAP_IN_PATCH_CODE (-1432) + +/** @} */ + + +/** @name Code Scanning and Analysis Manager (CSAM) Status Codes + * @{ + */ +/** Trap not handled */ +#define VWRN_CSAM_TRAP_NOT_HANDLED 1500 +/** Patch installed */ +#define VWRN_CSAM_INSTRUCTION_PATCHED 1501 +/** Page record not found */ +#define VWRN_CSAM_PAGE_NOT_FOUND 1502 +/** Reason for leaving RC: CSAM wants perform a task in ring-3. */ +#define VINF_CSAM_PENDING_ACTION 1503 +/** The CSAM is not used because we're using HM and VT-x/AMD-V. */ +#define VERR_CSAM_HM_IPE (-1504) +/** @} */ + + +/** @name Page Monitor/Manager (PGM) Status Codes + * @{ + */ +/** Attempt to create a GC mapping which conflicts with an existing mapping. */ +#define VERR_PGM_MAPPING_CONFLICT (-1600) +/** The physical handler range has no corresponding RAM range. + * If this is MMIO, see todo above the return. If not MMIO, then it's + * someone else's fault... */ +#define VERR_PGM_HANDLER_PHYSICAL_NO_RAM_RANGE (-1601) +/** Attempt to register an access handler for a virtual range of which a part + * was already handled. */ +#define VERR_PGM_HANDLER_VIRTUAL_CONFLICT (-1602) +/** Attempt to register an access handler for a physical range of which a part + * was already handled. */ +#define VERR_PGM_HANDLER_PHYSICAL_CONFLICT (-1603) +/** Invalid page directory specified to PGM. */ +#define VERR_PGM_INVALID_PAGE_DIRECTORY (-1604) +/** Invalid GC physical address. */ +#define VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS (-1605) +/** Invalid GC physical range. Usually used when a specified range crosses + * a RAM region boundary. */ +#define VERR_PGM_INVALID_GC_PHYSICAL_RANGE (-1606) +/** Specified access handler was not found. */ +#define VERR_PGM_HANDLER_NOT_FOUND (-1607) +/** Attempt to register a RAM range of which parts are already + * covered by existing RAM ranges. */ +#define VERR_PGM_RAM_CONFLICT (-1608) +/** Failed to add new mappings because the current mappings are fixed + * in guest os memory. */ +#define VERR_PGM_MAPPINGS_FIXED (-1609) +/** Failed to fix mappings because of a conflict with the intermediate code. */ +#define VERR_PGM_MAPPINGS_FIX_CONFLICT (-1610) +/** Failed to fix mappings because a mapping rejected the address. */ +#define VERR_PGM_MAPPINGS_FIX_REJECTED (-1611) +/** Failed to fix mappings because the proposed memory area was to small. */ +#define VERR_PGM_MAPPINGS_FIX_TOO_SMALL (-1612) +/** Reason for leaving RZ: The urge to syncing CR3. */ +#define VINF_PGM_SYNC_CR3 1613 +/** Page not marked for dirty bit tracking */ +#define VINF_PGM_NO_DIRTY_BIT_TRACKING 1614 +/** Page fault caused by dirty bit tracking; corrected */ +#define VINF_PGM_HANDLED_DIRTY_BIT_FAULT 1615 +/** Go ahead with the default Read/Write operation. + * This is returned by a R3 physical or virtual handler when it wants the + * PGMPhys[Read|Write] routine do the reading/writing. */ +#define VINF_PGM_HANDLER_DO_DEFAULT 1616 +/** The paging mode of the host is not supported yet. */ +#define VERR_PGM_UNSUPPORTED_HOST_PAGING_MODE (-1617) +/** The physical guest page is a reserved/MMIO page and does not have any HC + * address. */ +#define VERR_PGM_PHYS_PAGE_RESERVED (-1618) +/** No page directory available for the hypervisor. */ +#define VERR_PGM_NO_HYPERVISOR_ADDRESS (-1619) + + +/** The returned shadow page is cached. */ +#define VINF_PGM_CACHED_PAGE 1622 +/** Returned by handler registration, modification and deregistration + * when the shadow PTs could be updated because the guest page + * aliased or/and mapped by multiple PTs. */ +#define VINF_PGM_GCPHYS_ALIASED 1623 +/** SyncPage modified the PDE. + * This is an internal status code used to communicate back to the \#PF handler + * that the PDE was (probably) marked not-present and it should restart the instruction. */ +#define VINF_PGM_SYNCPAGE_MODIFIED_PDE 1625 +/** Physical range crosses dynamic ram chunk boundary; translation to HC ptr not safe. */ +#define VERR_PGM_GCPHYS_RANGE_CROSSES_BOUNDARY (-1626) +/** Conflict between the core memory and the intermediate paging context, try again. + * There are some very special conditions applying to the intermediate paging context + * (used during the world switches), and some times we continuously run into these + * when asking the host kernel for memory during VM init. Let us know if you run into + * this and we'll adjust the code so it tries harder to avoid it. + */ +#define VERR_PGM_INTERMEDIATE_PAGING_CONFLICT (-1627) +/** The shadow paging mode is not supported yet. */ +#define VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE (-1628) +/** The dynamic mapping cache for physical memory failed. */ +#define VERR_PGM_DYNMAP_FAILED (-1629) +/** The auto usage cache for the dynamic mapping set is full. */ +#define VERR_PGM_DYNMAP_FULL_SET (-1630) +/** The initialization of the dynamic mapping cache failed. */ +#define VERR_PGM_DYNMAP_SETUP_ERROR (-1631) +/** The expanding of the dynamic mapping cache failed. */ +#define VERR_PGM_DYNMAP_EXPAND_ERROR (-1632) +/** The page is unassigned (akin to VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS). */ +#define VERR_PGM_PHYS_TLB_UNASSIGNED (-1633) +/** Catch any access and route it thru PGM. */ +#define VERR_PGM_PHYS_TLB_CATCH_ALL (-1634) +/** Catch write access and route it thru PGM. */ +#define VINF_PGM_PHYS_TLB_CATCH_WRITE 1635 +/** Catch write access and route it thru PGM. */ +#define VERR_PGM_PHYS_TLB_CATCH_WRITE (-1635) +/** No CR3 root shadow page table. */ +#define VERR_PGM_NO_CR3_SHADOW_ROOT (-1636) +/** Trying to free a page with an invalid Page ID. */ +#define VERR_PGM_PHYS_INVALID_PAGE_ID (-1637) +/** PGMPhysWrite/Read hit a handler in Ring-0 or raw-mode context. */ +#define VERR_PGM_PHYS_WR_HIT_HANDLER (-1638) +/** Trying to free a page that isn't RAM. */ +#define VERR_PGM_PHYS_NOT_RAM (-1639) +/** Not ROM page. */ +#define VERR_PGM_PHYS_NOT_ROM (-1640) +/** Not MMIO page. */ +#define VERR_PGM_PHYS_NOT_MMIO (-1641) +/** Not MMIO2 page. */ +#define VERR_PGM_PHYS_NOT_MMIO2 (-1642) +/** Already aliased to a different page. */ +#define VERR_PGM_HANDLER_ALREADY_ALIASED (-1643) +/** Already aliased to the same page. */ +#define VINF_PGM_HANDLER_ALREADY_ALIASED (1643) +/** PGM pool flush pending - return to ring 3. */ +#define VINF_PGM_POOL_FLUSH_PENDING (1644) +/** Unable to use the range for a large page. */ +#define VERR_PGM_INVALID_LARGE_PAGE_RANGE (-1645) +/** Don't mess around with ballooned pages. */ +#define VERR_PGM_PHYS_PAGE_BALLOONED (-1646) +/** Internal processing error \#1 in page access handler code. */ +#define VERR_PGM_HANDLER_IPE_1 (-1647) + + +/** pgmPhysPageMapCommon encountered PGMPAGETYPE_MMIO2_ALIAS_MMIO. */ +#define VERR_PGM_MAP_MMIO2_ALIAS_MMIO (-1651) +/** Guest mappings are disabled. */ +#define VERR_PGM_MAPPINGS_DISABLED (-1652) +/** No guest mappings when SMP is enabled. */ +#define VERR_PGM_MAPPINGS_SMP (-1653) +/** Invalid saved page state. */ +#define VERR_PGM_INVALID_SAVED_PAGE_STATE (-1654) +/** Encountered an unexpected page type in the saved state. */ +#define VERR_PGM_LOAD_UNEXPECTED_PAGE_TYPE (-1655) +/** Encountered an unexpected page state in the saved state. */ +#define VERR_PGM_UNEXPECTED_PAGE_STATE (-1656) +/** Couldn't find MMIO2 range from saved state. */ +#define VERR_PGM_SAVED_MMIO2_RANGE_NOT_FOUND (-1657) +/** Couldn't find MMIO2 page from saved state. */ +#define VERR_PGM_SAVED_MMIO2_PAGE_NOT_FOUND (-1658) +/** Couldn't find ROM range from saved state. */ +#define VERR_PGM_SAVED_ROM_RANGE_NOT_FOUND (-1659) +/** Couldn't find ROM page from saved state. */ +#define VERR_PGM_SAVED_ROM_PAGE_NOT_FOUND (-1660) +/** ROM page mismatch between saved state and the VM. */ +#define VERR_PGM_SAVED_ROM_PAGE_PROT (-1661) +/** Unknown saved state record. */ +#define VERR_PGM_SAVED_REC_TYPE (-1662) +/** Internal processing error in the PGM dynmap (r0/rc). */ +#define VERR_PGM_DYNMAP_IPE (-1663) +/** Internal processing error in the PGM handy page allocator. */ +#define VERR_PGM_HANDY_PAGE_IPE (-1664) +/** Failed to map the guest PML4. */ +#define VERR_PGM_PML4_MAPPING (-1665) +/** Failed to obtain a pool page. */ +#define VERR_PGM_POOL_GET_PAGE_FAILED (-1666) +/** A PGM function was called in a mode where it isn't supposed to be used. */ +#define VERR_PGM_NOT_USED_IN_MODE (-1667) +/** The CR3 address specified memory we don't know about. */ +#define VERR_PGM_INVALID_CR3_ADDR (-1668) +/** One or the PDPEs specified memory we don't know about. */ +#define VERR_PGM_INVALID_PDPE_ADDR (-1669) +/** Internal processing error in the PGM physical handler code. */ +#define VERR_PGM_PHYS_HANDLER_IPE (-1670) +/** Internal processing error \#1 in the PGM physial page mapping code. */ +#define VERR_PGM_PHYS_PAGE_MAP_IPE_1 (-1671) +/** Internal processing error \#2 in the PGM physial page mapping code. */ +#define VERR_PGM_PHYS_PAGE_MAP_IPE_2 (-1672) +/** Internal processing error \#3 in the PGM physial page mapping code. */ +#define VERR_PGM_PHYS_PAGE_MAP_IPE_3 (-1673) +/** Internal processing error \#4 in the PGM physial page mapping code. */ +#define VERR_PGM_PHYS_PAGE_MAP_IPE_4 (-1674) +/** Too many loops looking for a page to reuse. */ +#define VERR_PGM_POOL_TOO_MANY_LOOPS (-1675) +/** Internal processing error related to guest mappings. */ +#define VERR_PGM_MAPPING_IPE (-1676) +/** An attempt was made to grow an already maxed out page pool. */ +#define VERR_PGM_POOL_MAXED_OUT_ALREADY (-1677) +/** Internal processing error in the page pool code. */ +#define VERR_PGM_POOL_IPE (-1678) +/** The write monitor is already engaged. */ +#define VERR_PGM_WRITE_MONITOR_ENGAGED (-1679) +/** Failed to get a guest page which is expected to be present. */ +#define VERR_PGM_PHYS_PAGE_GET_IPE (-1680) +/** We were given a NULL pPage parameter. */ +#define VERR_PGM_PHYS_NULL_PAGE_PARAM (-1681) +/** PCI passthru is not supported by this build. */ +#define VERR_PGM_PCI_PASSTHRU_MISCONFIG (-1682) +/** Too many MMIO2 ranges. */ +#define VERR_PGM_TOO_MANY_MMIO2_RANGES (-1683) +/** Internal processing error in the PGM physical page mapping code dealing + * with MMIO2 pages. */ +#define VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE (-1684) +/** Internal processing error in the PGM physcal page handling code related to + * MMIO/MMIO2. */ +#define VERR_PGM_PHYS_MMIO_EX_IPE (-1685) +/** Mode table internal error. */ +#define VERR_PGM_MODE_IPE (-1686) +/** Shadow mode 'none' internal error. */ +#define VERR_PGM_SHW_NONE_IPE (-1687) +/** One or more PAE PDPEs are invalid due to reserved bits being set. */ +#define VERR_PGM_PAE_PDPE_RSVD (-1688) +/** Attemted illegal operation in simplified memory management mode. */ +#define VERR_PGM_NOT_SUPPORTED_FOR_NEM_MODE (-1689) +/** @} */ + + +/** @name Memory Monitor (MM) Status Codes + * @{ + */ +/** Attempt to register a RAM range of which parts are already + * covered by existing RAM ranges. */ +#define VERR_MM_RAM_CONFLICT (-1700) +/** Hypervisor memory allocation failed. */ +#define VERR_MM_HYPER_NO_MEMORY (-1701) +/** A bad trap type ended up in mmGCRamTrap0eHandler. */ +#define VERR_MM_BAD_TRAP_TYPE_IPE (-1702) +/** @} */ + + +/** @name CPU Monitor (CPUM) Status Codes + * @{ + */ +/** The caller shall raise an \#GP(0) exception. */ +#define VERR_CPUM_RAISE_GP_0 (-1750) +/** Incompatible CPUM configuration. */ +#define VERR_CPUM_INCOMPATIBLE_CONFIG (-1751) +/** CPUMR3DisasmInstrCPU unexpectedly failed to determine the hidden + * parts of the CS register. */ +#define VERR_CPUM_HIDDEN_CS_LOAD_ERROR (-1752) +/** Couldn't find the end of CPUID sub-leaves. */ +#define VERR_CPUM_TOO_MANY_CPUID_SUBLEAVES (-1753) +/** CPUM internal processing error \#1. */ +#define VERR_CPUM_IPE_1 (-1754) +/** CPUM internal processing error \#2. */ +#define VERR_CPUM_IPE_2 (-1755) +/** The specified CPU cannot be found in the CPU database. */ +#define VERR_CPUM_DB_CPU_NOT_FOUND (-1756) +/** Invalid CPUMCPU offset in MSR range. */ +#define VERR_CPUM_MSR_BAD_CPUMCPU_OFFSET (-1757) +/** Return to ring-3 to read the MSR there. */ +#define VINF_CPUM_R3_MSR_READ (1758) +/** Return to ring-3 to write the MSR there. */ +#define VINF_CPUM_R3_MSR_WRITE (1759) +/** Too many CPUID leaves. */ +#define VERR_TOO_MANY_CPUID_LEAVES (-1760) +/** Invalid config value. */ +#define VERR_CPUM_INVALID_CONFIG_VALUE (-1761) +/** The loaded XSAVE component mask is not compatible with the host CPU + * or/and VM config. */ +#define VERR_CPUM_INCOMPATIBLE_XSAVE_COMP_MASK (-1762) +/** The loaded XSAVE component mask is not valid. */ +#define VERR_CPUM_INVALID_XSAVE_COMP_MASK (-1763) +/** The loaded XSAVE header is not valid. */ +#define VERR_CPUM_INVALID_XSAVE_HDR (-1764) +/** The loaded XCR0 register value is not valid. */ +#define VERR_CPUM_INVALID_XCR0 (-1765) +/** Indicates that we modified the host CR0 (FPU related). */ +#define VINF_CPUM_HOST_CR0_MODIFIED (1766) +/** Invalid/unsupported nested hardware virtualization configuration. */ +#define VERR_CPUM_INVALID_HWVIRT_CONFIG (-1767) +/** Invalid nested hardware virtualization feature combination. */ +#define VERR_CPUM_INVALID_HWVIRT_FEAT_COMBO (-1768) +/** @} */ + + +/** @name Save State Manager (SSM) Status Codes + * @{ + */ +/** The specified data unit already exist. */ +#define VERR_SSM_UNIT_EXISTS (-1800) +/** The specified data unit wasn't found. */ +#define VERR_SSM_UNIT_NOT_FOUND (-1801) +/** The specified data unit wasn't owned by caller. */ +#define VERR_SSM_UNIT_NOT_OWNER (-1802) + +/** General saved state file integrity error. */ +#define VERR_SSM_INTEGRITY (-1810) +/** The saved state file magic was not recognized. */ +#define VERR_SSM_INTEGRITY_MAGIC (-1811) +/** The saved state file version is not supported. */ +#define VERR_SSM_INTEGRITY_VERSION (-1812) +/** The saved state file size didn't match the one in the header. */ +#define VERR_SSM_INTEGRITY_SIZE (-1813) +/** The CRC of the saved state file did not match. */ +#define VERR_SSM_INTEGRITY_CRC (-1814) +/** The machine uuid field wasn't null. */ +#define VERR_SMM_INTEGRITY_MACHINE (-1815) +/** Saved state header integrity error. */ +#define VERR_SSM_INTEGRITY_HEADER (-1816) +/** Unit header integrity error. */ +#define VERR_SSM_INTEGRITY_UNIT (-1817) +/** Invalid unit magic (internal data tag). */ +#define VERR_SSM_INTEGRITY_UNIT_MAGIC (-1818) +/** The file contained a data unit which no-one wants. */ +#define VERR_SSM_INTEGRITY_UNIT_NOT_FOUND (-1819) +/** Incorrect version numbers in the header. */ +#define VERR_SSM_INTEGRITY_VBOX_VERSION (-1820) +/** Footer integrity error. */ +#define VERR_SSM_INTEGRITY_FOOTER (-1821) +/** Record header integrity error. */ +#define VERR_SSM_INTEGRITY_REC_HDR (-1822) +/** Termination record integrity error. */ +#define VERR_SSM_INTEGRITY_REC_TERM (-1823) +/** Termination record CRC mismatch. */ +#define VERR_SSM_INTEGRITY_REC_TERM_CRC (-1824) +/** Decompression integrity error. */ +#define VERR_SSM_INTEGRITY_DECOMPRESSION (-1825) +/** Saved state directory wintertides error. */ +#define VERR_SSM_INTEGRITY_DIR (-1826) +/** The saved state directory magic is wrong. */ +#define VERR_SSM_INTEGRITY_DIR_MAGIC (-1827) + +/** A data unit in the saved state file was defined but didn't any + * routine for processing it. */ +#define VERR_SSM_NO_LOAD_EXEC (-1830) +/** A restore routine attempted to load more data then the unit contained. */ +#define VERR_SSM_LOADED_TOO_MUCH (-1831) +/** Not in the correct state for the attempted operation. */ +#define VERR_SSM_INVALID_STATE (-1832) +/** Not in the correct state for the attempted operation. */ +#define VERR_SSM_LOADED_TOO_LITTLE (-1833) + +/** Unsupported data unit version. + * A SSM user returns this if it doesn't know the u32Version. */ +#define VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION (-1840) +/** The format of a data unit has changed. + * A SSM user returns this if it's not able to read the format for + * other reasons than u32Version. */ +#define VERR_SSM_DATA_UNIT_FORMAT_CHANGED (-1841) +/** The CPUID instruction returns different information when loading than when saved. + * Normally caused by hardware changes on the host, but could also be caused by + * changes in the BIOS setup. */ +#define VERR_SSM_LOAD_CPUID_MISMATCH (-1842) +/** The RAM size differs between the saved state and the VM config. */ +#define VERR_SSM_LOAD_MEMORY_SIZE_MISMATCH (-1843) +/** The state doesn't match the VM configuration in one or another way. + * (There are certain PCI reconfiguration which the OS could potentially + * do which can cause this problem. Check this out when it happens.) */ +#define VERR_SSM_LOAD_CONFIG_MISMATCH (-1844) +/** The virtual clock frequency differs too much. + * The clock source for the virtual time isn't reliable or the code have changed. */ +#define VERR_SSM_VIRTUAL_CLOCK_HZ (-1845) +/** A timeout occurred while waiting for async IDE operations to finish. */ +#define VERR_SSM_IDE_ASYNC_TIMEOUT (-1846) +/** One of the structure magics was wrong. */ +#define VERR_SSM_STRUCTURE_MAGIC (-1847) +/** The data in the saved state doesn't conform to expectations. */ +#define VERR_SSM_UNEXPECTED_DATA (-1848) +/** Trying to read a 64-bit guest physical address into a 32-bit variable. */ +#define VERR_SSM_GCPHYS_OVERFLOW (-1849) +/** Trying to read a 64-bit guest virtual address into a 32-bit variable. */ +#define VERR_SSM_GCPTR_OVERFLOW (-1850) +/** Vote for another pass. */ +#define VINF_SSM_VOTE_FOR_ANOTHER_PASS 1851 +/** Vote for done tell SSM not to call again until the final pass. */ +#define VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN 1852 +/** Vote for giving up. */ +#define VERR_SSM_VOTE_FOR_GIVING_UP (-1853) +/** Don't call again until the final pass. */ +#define VINF_SSM_DONT_CALL_AGAIN 1854 +/** Giving up a live snapshot/teleportation attempt because of too many + * passes. */ +#define VERR_SSM_TOO_MANY_PASSES (-1855) +/** Giving up a live snapshot/teleportation attempt because the state grew to + * big. */ +#define VERR_SSM_STATE_GREW_TOO_BIG (-1856) +/** Giving up a live snapshot attempt because we're low on disk space. */ +#define VERR_SSM_LOW_ON_DISK_SPACE (-1857) +/** The operation was cancelled. */ +#define VERR_SSM_CANCELLED (-1858) +/** Nothing that can be cancelled. */ +#define VERR_SSM_NO_PENDING_OPERATION (-1859) +/** The operation has already been cancelled. */ +#define VERR_SSM_ALREADY_CANCELLED (-1860) +/** The machine was powered off while saving. */ +#define VERR_SSM_LIVE_POWERED_OFF (-1861) +/** The live snapshot/teleportation operation was aborted because of a guru + * meditation. */ +#define VERR_SSM_LIVE_GURU_MEDITATION (-1862) +/** The live snapshot/teleportation operation was aborted because of a fatal + * runtime error. */ +#define VERR_SSM_LIVE_FATAL_ERROR (-1863) +/** The VM was suspended before or while saving, don't resume execution. */ +#define VINF_SSM_LIVE_SUSPENDED 1864 +/** Complex SSM field fed to SSMR3PutStruct or SSMR3GetStruct. Use the + * extended API. */ +#define VERR_SSM_FIELD_COMPLEX (-1864) +/** Invalid size of a SSM field with the specified transformation. */ +#define VERR_SSM_FIELD_INVALID_SIZE (-1865) +/** The specified field is outside the structure. */ +#define VERR_SSM_FIELD_OUT_OF_BOUNDS (-1866) +/** The field does not follow immediately the previous one. */ +#define VERR_SSM_FIELD_NOT_CONSECUTIVE (-1867) +/** The field contains an invalid callback or transformation index. */ +#define VERR_SSM_FIELD_INVALID_CALLBACK (-1868) +/** The field contains an invalid padding size. */ +#define VERR_SSM_FIELD_INVALID_PADDING_SIZE (-1869) +/** The field contains a value that is out of range. */ +#define VERR_SSM_FIELD_INVALID_VALUE (-1870) +/** Generic stream error. */ +#define VERR_SSM_STREAM_ERROR (-1871) +/** SSM did a callback for a pass we didn't expect. */ +#define VERR_SSM_UNEXPECTED_PASS (-1872) +/** Someone is trying to skip backwards in the stream... */ +#define VERR_SSM_SKIP_BACKWARDS (-1873) +/** Someone is trying to write a memory block which is too big to encode. */ +#define VERR_SSM_MEM_TOO_BIG (-1874) +/** Encountered an bad (/unknown) record type. */ +#define VERR_SSM_BAD_REC_TYPE (-1875) +/** Internal processing error \#1 in SSM code. */ +#define VERR_SSM_IPE_1 (-1876) +/** Internal processing error \#2 in SSM code. */ +#define VERR_SSM_IPE_2 (-1877) +/** Internal processing error \#3 in SSM code. */ +#define VERR_SSM_IPE_3 (-1878) +/** A field contained an transformation that should only be used when loading + * old states. */ +#define VERR_SSM_FIELD_LOAD_ONLY_TRANSFORMATION (-1879) +/** @} */ + + +/** @name Virtual Machine (VM) Status Codes + * @{ + */ +/** The specified at reset handler wasn't found. */ +#define VERR_VM_ATRESET_NOT_FOUND (-1900) +/** Invalid VM request type. + * For the VMR3ReqAlloc() case, the caller just specified an illegal enmType. For + * all the other occurrences it means indicates corruption, broken logic, or stupid + * interface user. */ +#define VERR_VM_REQUEST_INVALID_TYPE (-1901) +/** Invalid VM request state. + * The state of the request packet was not the expected and accepted one(s). Either + * the interface user screwed up, or we've got corruption/broken logic. */ +#define VERR_VM_REQUEST_STATE (-1902) +/** Invalid VM request packet. + * One or more of the VM controlled packet members didn't contain the correct + * values. Some thing's broken. */ +#define VERR_VM_REQUEST_INVALID_PACKAGE (-1903) +/** The status field has not been updated yet as the request is still + * pending completion. Someone queried the iStatus field before the request + * has been fully processed. */ +#define VERR_VM_REQUEST_STATUS_STILL_PENDING (-1904) +/** The request has been freed, don't read the status now. + * Someone is reading the iStatus field of a freed request packet. */ +#define VERR_VM_REQUEST_STATUS_FREED (-1905) +/** A VM api requiring EMT was called from another thread. + * Use the VMR3ReqCall() apis to call it! */ +#define VERR_VM_THREAD_NOT_EMT (-1906) +/** The VM state was invalid for the requested operation. + * Go check the 'VM Statechart Diagram.gif'. */ +#define VERR_VM_INVALID_VM_STATE (-1907) +/** The support driver is not installed. + * On linux, open returned ENOENT. */ +#define VERR_VM_DRIVER_NOT_INSTALLED (-1908) +/** The support driver is not accessible. + * On linux, open returned EPERM. */ +#define VERR_VM_DRIVER_NOT_ACCESSIBLE (-1909) +/** Was not able to load the support driver. + * On linux, open returned ENODEV. */ +#define VERR_VM_DRIVER_LOAD_ERROR (-1910) +/** Was not able to open the support driver. + * Generic open error used when none of the other ones fit. */ +#define VERR_VM_DRIVER_OPEN_ERROR (-1911) +/** The installed support driver doesn't match the version of the user. */ +#define VERR_VM_DRIVER_VERSION_MISMATCH (-1912) +/** Saving the VM state is temporarily not allowed. Try again later. */ +#define VERR_VM_SAVE_STATE_NOT_ALLOWED (-1913) +/** An EMT called an API which cannot be called on such a thread. */ +#define VERR_VM_THREAD_IS_EMT (-1914) +/** Encountered an unexpected VM state. */ +#define VERR_VM_UNEXPECTED_VM_STATE (-1915) +/** Unexpected unstable VM state. */ +#define VERR_VM_UNEXPECTED_UNSTABLE_STATE (-1916) +/** Too many arguments passed to a VM request / request corruption. */ +#define VERR_VM_REQUEST_TOO_MANY_ARGS_IPE (-1917) +/** Fatal EMT wait error. */ +#define VERR_VM_FATAL_WAIT_ERROR (-1918) +/** The VM request was killed at VM termination. */ +#define VERR_VM_REQUEST_KILLED (-1919) +/** @} */ + + +/** @name VBox Remote Desktop Protocol (VRDP) Status Codes + * @{ + */ +/** Successful completion of operation (mapped to generic iprt status code). */ +#define VINF_VRDP_SUCCESS VINF_SUCCESS +/** VRDP transport operation timed out (mapped to generic iprt status code). */ +#define VERR_VRDP_TIMEOUT VERR_TIMEOUT + +/** Unsupported ISO protocol feature */ +#define VERR_VRDP_ISO_UNSUPPORTED (-2000) +/** Security (en/decryption) engine error */ +#define VERR_VRDP_SEC_ENGINE_FAIL (-2001) +/** VRDP protocol violation */ +#define VERR_VRDP_PROTOCOL_ERROR (-2002) +/** Unsupported VRDP protocol feature */ +#define VERR_VRDP_NOT_SUPPORTED (-2003) +/** VRDP protocol violation, client sends less data than expected */ +#define VERR_VRDP_INSUFFICIENT_DATA (-2004) +/** Internal error, VRDP packet is in wrong operation mode */ +#define VERR_VRDP_INVALID_MODE (-2005) +/** Memory allocation failed */ +#define VERR_VRDP_NO_MEMORY (-2006) +/** Client has been rejected */ +#define VERR_VRDP_ACCESS_DENIED (-2007) +/** VRPD receives a packet that is not supported */ +#define VWRN_VRDP_PDU_NOT_SUPPORTED 2008 +/** VRDP script allowed the packet to be processed further */ +#define VINF_VRDP_PROCESS_PDU 2009 +/** VRDP script has completed its task */ +#define VINF_VRDP_OPERATION_COMPLETED 2010 +/** VRDP thread has started OK and will run */ +#define VINF_VRDP_THREAD_STARTED 2011 +/** Framebuffer is resized, terminate send bitmap procedure */ +#define VINF_VRDP_RESIZE_REQUESTED 2012 +/** Output can be enabled for the client. */ +#define VINF_VRDP_OUTPUT_ENABLE 2013 +/** @} */ + + +/** @name Configuration Manager (CFGM) Status Codes + * @{ + */ +/** The integer value was too big for the requested representation. */ +#define VERR_CFGM_INTEGER_TOO_BIG (-2100) +/** Child node was not found. */ +#define VERR_CFGM_CHILD_NOT_FOUND (-2101) +/** Path to child node was invalid (i.e. empty). */ +#define VERR_CFGM_INVALID_CHILD_PATH (-2102) +/** Value not found. */ +#define VERR_CFGM_VALUE_NOT_FOUND (-2103) +/** No parent node specified. */ +#define VERR_CFGM_NO_PARENT (-2104) +/** No node was specified. */ +#define VERR_CFGM_NO_NODE (-2105) +/** The value is not an integer. */ +#define VERR_CFGM_NOT_INTEGER (-2106) +/** The value is not a zero terminated character string. */ +#define VERR_CFGM_NOT_STRING (-2107) +/** The value is not a byte string. */ +#define VERR_CFGM_NOT_BYTES (-2108) +/** The specified string / bytes buffer was to small. Specify a larger one and retry. */ +#define VERR_CFGM_NOT_ENOUGH_SPACE (-2109) +/** The value is not a zero terminated password string. */ +#define VERR_CFGM_NOT_PASSWORD (-2110) +/** The path of a new node contained slashes or was empty. */ +#define VERR_CFGM_INVALID_NODE_PATH (-2160) +/** A new node couldn't be inserted because one with the same name exists. */ +#define VERR_CFGM_NODE_EXISTS (-2161) +/** A new leaf couldn't be inserted because one with the same name exists. */ +#define VERR_CFGM_LEAF_EXISTS (-2162) +/** An unknown config value was encountered. */ +#define VERR_CFGM_CONFIG_UNKNOWN_VALUE (-2163) +/** An unknown config node (key) was encountered. */ +#define VERR_CFGM_CONFIG_UNKNOWN_NODE (-2164) +/** Internal processing error \#1 in CFGM. */ +#define VERR_CFGM_IPE_1 (-2165) +/** @} */ + + +/** @name Time Manager (TM) Status Codes + * @{ + */ +/** The loaded timer state was incorrect. */ +#define VERR_TM_LOAD_STATE (-2200) +/** The timer was not in the correct state for the request operation. */ +#define VERR_TM_INVALID_STATE (-2201) +/** The timer was in a unknown state. Corruption or stupid coding error. */ +#define VERR_TM_UNKNOWN_STATE (-2202) +/** The timer was stuck in an unstable state until we grew impatient and returned. */ +#define VERR_TM_UNSTABLE_STATE (-2203) +/** TM requires GIP. */ +#define VERR_TM_GIP_REQUIRED (-2204) +/** TM does not support the GIP version. */ +#define VERR_TM_GIP_VERSION (-2205) +/** The GIP update interval is too large. */ +#define VERR_TM_GIP_UPDATE_INTERVAL_TOO_BIG (-2206) +/** The timer has a bad clock enum value, probably corruption. */ +#define VERR_TM_TIMER_BAD_CLOCK (-2207) +/** The timer failed to reach a stable state. */ +#define VERR_TM_TIMER_UNSTABLE_STATE (-2208) +/** Attempt to resume a running TSC. */ +#define VERR_TM_TSC_ALREADY_TICKING (-2209) +/** Attempt to pause a paused TSC. */ +#define VERR_TM_TSC_ALREADY_PAUSED (-2210) +/** Invalid value for cVirtualTicking. */ +#define VERR_TM_VIRTUAL_TICKING_IPE (-2211) +/** Max timer limit reached. */ +#define VERR_TM_TOO_MANY_TIMERS (-2212) +/** Invalid timer queue number. */ +#define VERR_TM_INVALID_TIMER_QUEUE (-2213) +/** The timer queue is not longer allowed to grow. */ +#define VERR_TM_TIMER_QUEUE_CANNOT_GROW (-2214) +/** TM internal processing error \#1. */ +#define VERR_TM_IPE_1 (-2291) +/** TM internal processing error \#2. */ +#define VERR_TM_IPE_2 (-2292) +/** TM internal processing error \#3. */ +#define VERR_TM_IPE_3 (-2293) +/** TM internal processing error \#4. */ +#define VERR_TM_IPE_4 (-2294) +/** TM internal processing error \#5. */ +#define VERR_TM_IPE_5 (-2295) +/** TM internal processing error \#6. */ +#define VERR_TM_IPE_6 (-2296) +/** TM internal processing error \#7. */ +#define VERR_TM_IPE_7 (-2297) +/** TM internal processing error \#8. */ +#define VERR_TM_IPE_8 (-2298) +/** TM internal processing error \#9. */ +#define VERR_TM_IPE_9 (-2299) +/** @} */ + + +/** @name Recompiled Execution Manager (REM) Status Codes + * @{ + */ +/** Fatal error in virtual hardware. */ +#define VERR_REM_VIRTUAL_HARDWARE_ERROR (-2300) +/** Fatal error in the recompiler cpu. */ +#define VERR_REM_VIRTUAL_CPU_ERROR (-2301) +/** Recompiler execution was interrupted by forced action. */ +#define VINF_REM_INTERRUPED_FF 2302 +/** Too many similar traps. This is a very useful debug only + * check (we don't do double/triple faults in REM). */ +#define VERR_REM_TOO_MANY_TRAPS (-2304) +/** The REM is out of breakpoint slots. */ +#define VERR_REM_NO_MORE_BP_SLOTS (-2305) +/** The REM could not find any breakpoint on the specified address. */ +#define VERR_REM_BP_NOT_FOUND (-2306) +/** @} */ + + +/** @name Trap Manager / Monitor (TRPM) Status Codes + * @{ + */ +/** No active trap. Cannot query or reset a non-existing trap. */ +#define VERR_TRPM_NO_ACTIVE_TRAP (-2400) +/** Active trap. Cannot assert a new trap when one is already active. */ +#define VERR_TRPM_ACTIVE_TRAP (-2401) +/** Reason for leaving RC: Guest tried to write to our IDT - fatal. + * The VM will be terminated assuming the worst, i.e. that the + * guest has read the idtr register. */ +#define VERR_TRPM_SHADOW_IDT_WRITE (-2402) +/** Reason for leaving RC: Fatal trap in hypervisor. */ +#define VERR_TRPM_DONT_PANIC (-2403) +/** Reason for leaving RC: Double Fault. */ +#define VERR_TRPM_PANIC (-2404) +/** Bad TRPM_TRAP_IN_OP. */ +#define VERR_TRPM_BAD_TRAP_IN_OP (-2405) +/** Internal processing error \#1 in TRPM. */ +#define VERR_TRPM_IPE_1 (-2406) +/** Internal processing error \#2 in TRPM. */ +#define VERR_TRPM_IPE_2 (-2407) +/** Internal processing error \#3 in TRPM. */ +#define VERR_TRPM_IPE_3 (-2408) +/** Got into a part of TRPM that is not used when HM (VT-x/AMD-V) is enabled. */ +#define VERR_TRPM_HM_IPE (-2409) +/** @} */ + + +/** @name Selector Manager / Monitor (SELM) Status Code + * @{ + */ +/** Reason for leaving RC: Guest tried to write to our GDT - fatal. + * The VM will be terminated assuming the worst, i.e. that the + * guest has read the gdtr register. */ +#define VERR_SELM_SHADOW_GDT_WRITE (-2500) +/** Reason for leaving RC: Guest tried to write to our LDT - fatal. + * The VM will be terminated assuming the worst, i.e. that the + * guest has read the ldtr register. */ +#define VERR_SELM_SHADOW_LDT_WRITE (-2501) +/** Reason for leaving RC: Guest tried to write to our TSS - fatal. + * The VM will be terminated assuming the worst, i.e. that the + * guest has read the ltr register. */ +#define VERR_SELM_SHADOW_TSS_WRITE (-2502) +/** Reason for leaving RC: Sync the GDT table to solve a conflict. */ +#define VINF_SELM_SYNC_GDT 2503 +/** No valid TSS present. */ +#define VERR_SELM_NO_TSS (-2504) +/** Invalid guest LDT selector. */ +#define VERR_SELM_INVALID_LDT (-2505) +/** The guest LDT selector is out of bounds. */ +#define VERR_SELM_LDT_OUT_OF_BOUNDS (-2506) +/** Unknown error while reading the guest GDT during shadow table updating. */ +#define VERR_SELM_GDT_READ_ERROR (-2507) +/** The guest GDT so full that we cannot find free space for our own + * selectors. */ +#define VERR_SELM_GDT_TOO_FULL (-2508) +/** Got into a part of SELM that is not used when HM (VT-x/AMD-V) is enabled. */ +#define VERR_SELM_HM_IPE (-2509) +/** @} */ + + +/** @name I/O Manager / Monitor (IOM) Status Code + * @{ + */ +/** The specified I/O port range was invalid. + * It was either empty or it was out of bounds. */ +#define VERR_IOM_INVALID_IOPORT_RANGE (-2600) +/** The specified R0 or RC I/O port range didn't have a corresponding R3 range. + * IOMR3IOPortRegisterR3() must be called first. */ +#define VERR_IOM_NO_R3_IOPORT_RANGE (-2601) +/** The specified I/O port range intruded on an existing range. There is + * a I/O port conflict between two device, or a device tried to register + * the same range twice. */ +#define VERR_IOM_IOPORT_RANGE_CONFLICT (-2602) +/** The I/O port range specified for removal wasn't found or it wasn't contiguous. */ +#define VERR_IOM_IOPORT_RANGE_NOT_FOUND (-2603) +/** The specified I/O port range was owned by some other device(s). Both registration + * and deregistration, but in the first case only RC and R0 ranges. */ +#define VERR_IOM_NOT_IOPORT_RANGE_OWNER (-2604) + +/** The specified MMIO range was invalid. + * It was either empty or it was out of bounds. */ +#define VERR_IOM_INVALID_MMIO_RANGE (-2605) +/** The specified R0 or RC MMIO range didn't have a corresponding R3 range. + * IOMR3MMIORegisterR3() must be called first. */ +#define VERR_IOM_NO_R3_MMIO_RANGE (-2606) +/** The specified MMIO range was owned by some other device(s). Both registration + * and deregistration, but in the first case only RC and R0 ranges. */ +#define VERR_IOM_NOT_MMIO_RANGE_OWNER (-2607) +/** The specified MMIO range intruded on an existing range. There is + * a MMIO conflict between two device, or a device tried to register + * the same range twice. */ +#define VERR_IOM_MMIO_RANGE_CONFLICT (-2608) +/** The MMIO range specified for removal was not found. */ +#define VERR_IOM_MMIO_RANGE_NOT_FOUND (-2609) +/** The MMIO range specified for removal was invalid. The range didn't match + * quite match a set of existing ranges. It's not possible to remove parts of + * a MMIO range, only one or more full ranges. */ +#define VERR_IOM_INCOMPLETE_MMIO_RANGE (-2610) +/** An invalid I/O port size was specified for a read or write operation. */ +#define VERR_IOM_INVALID_IOPORT_SIZE (-2611) +/** The MMIO handler was called for a bogus address! Internal error! */ +#define VERR_IOM_MMIO_HANDLER_BOGUS_CALL (-2612) +/** The MMIO handler experienced a problem with the disassembler. */ +#define VERR_IOM_MMIO_HANDLER_DISASM_ERROR (-2613) +/** The port being read was not present(/unused) and IOM shall return ~0 according to size. */ +#define VERR_IOM_IOPORT_UNUSED (-2614) +/** Unused MMIO register read, fill with 00. */ +#define VINF_IOM_MMIO_UNUSED_00 2615 +/** Unused MMIO register read, fill with FF. */ +#define VINF_IOM_MMIO_UNUSED_FF 2616 + +/** Reason for leaving RZ: I/O port read. */ +#define VINF_IOM_R3_IOPORT_READ 2620 +/** Reason for leaving RZ: I/O port write. */ +#define VINF_IOM_R3_IOPORT_WRITE 2621 +/** Reason for leaving RZ: Pending I/O port write. Since there is also + * VMCPU_FF_IOM for this condition, it's ok to drop this status code for + * some other VINF_EM_XXX statuses. */ +#define VINF_IOM_R3_IOPORT_COMMIT_WRITE 2622 +/** Reason for leaving RZ: MMIO read. */ +#define VINF_IOM_R3_MMIO_READ 2623 +/** Reason for leaving RZ: MMIO write. */ +#define VINF_IOM_R3_MMIO_WRITE 2624 +/** Reason for leaving RZ: MMIO read/write. */ +#define VINF_IOM_R3_MMIO_READ_WRITE 2625 +/** Reason for leaving RZ: Pending MMIO write. Since there is also + * VMCPU_FF_IOM for this condition, it's ok to drop this status code for + * some other VINF_EM_XXX statuses. */ +#define VINF_IOM_R3_MMIO_COMMIT_WRITE 2626 + +/** IOMGCIOPortHandler was given an unexpected opcode. */ +#define VERR_IOM_IOPORT_UNKNOWN_OPCODE (-2630) +/** Internal processing error \#1 in the I/O port code. */ +#define VERR_IOM_IOPORT_IPE_1 (-2631) +/** Internal processing error \#2 in the I/O port code. */ +#define VERR_IOM_IOPORT_IPE_2 (-2632) +/** Internal processing error \#3 in the I/O port code. */ +#define VERR_IOM_IOPORT_IPE_3 (-2633) +/** Internal processing error \#1 in the MMIO code. */ +#define VERR_IOM_MMIO_IPE_1 (-2634) +/** Internal processing error \#2 in the MMIO code. */ +#define VERR_IOM_MMIO_IPE_2 (-2635) +/** Internal processing error \#3 in the MMIO code. */ +#define VERR_IOM_MMIO_IPE_3 (-2636) +/** Got into a part of IOM that is not used when HM (VT-x/AMD-V) is enabled. */ +#define VERR_IOM_HM_IPE (-2637) +/** Internal processing error while merging status codes. */ +#define VERR_IOM_FF_STATUS_IPE (-2638) + +/** Too many I/O port registrations. */ +#define VERR_IOM_TOO_MANY_IOPORT_REGISTRATIONS (-2650) +/** Invalid I/O port handle. */ +#define VERR_IOM_INVALID_IOPORT_HANDLE (-2651) +/** I/O ports are already mapped. */ +#define VERR_IOM_IOPORTS_ALREADY_MAPPED (-2652) +/** I/O ports are not mapped. */ +#define VERR_IOM_IOPORTS_NOT_MAPPED (-2653) + +/** Too many MMIO registrations. */ +#define VERR_IOM_TOO_MANY_MMIO_REGISTRATIONS (-2660) +/** Invalid MMIO handle. */ +#define VERR_IOM_INVALID_MMIO_HANDLE (-2661) +/** MMIO region is already mapped. */ +#define VERR_IOM_MMIO_REGION_ALREADY_MAPPED (-2662) +/** MMIO region is not mapped. */ +#define VERR_IOM_MMIO_REGION_NOT_MAPPED (-2663) +/** @} */ + + +/** @name Virtual Machine Monitor (VMM) Status Codes + * @{ + */ +/** Reason for leaving R0: Hit a ring-0 assertion on EMT. */ +#define VERR_VMM_RING0_ASSERTION (-2701) +/** The hyper CR3 differs between PGM and CPUM. */ +#define VERR_VMM_HYPER_CR3_MISMATCH (-2702) +/** Reason for leaving RZ: Illegal call to ring-3. */ +#define VERR_VMM_RING3_CALL_DISABLED (-2703) +/** The VMMR0.r0 module version does not match VBoxVMM.dll/so/dylib. + * If you just upgraded VirtualBox, please terminate all VMs and make sure + * that neither VBoxNetDHCP nor VBoxNetNAT is running. Then try again. + * If this error persists, try re-installing VirtualBox. */ +#define VERR_VMM_R0_VERSION_MISMATCH (-2704) +/** The VMMRC.rc module version does not match VBoxVMM.dll/so/dylib. + * Re-install if you are a user. Developers should make sure the build is + * complete or try with a clean build. */ +#define VERR_VMM_RC_VERSION_MISMATCH (-2705) +/** VMM long jump error. */ +#define VERR_VMM_LONG_JMP_ERROR (-2709) +/** Reason for leaving RC: Caller the tracer in ring-0. */ +#define VINF_VMM_CALL_TRACER (2712) +/** Internal processing error \#1 in the switcher code. */ +#define VERR_VMM_SWITCHER_IPE_1 (-2713) +/** Reason for leaving RZ: Unknown call to ring-3. */ +#define VINF_VMM_UNKNOWN_RING3_CALL (2714) +/** Attempted to use stub switcher. */ +#define VERR_VMM_SWITCHER_STUB (-2715) +/** HM returned in the wrong state. */ +#define VERR_VMM_WRONG_HM_VMCPU_STATE (-2716) +/** SMAP enabled, but the AC flag was found to be clear - check the kernel + * log for details. */ +#define VERR_VMM_SMAP_BUT_AC_CLEAR (-2717) +/** NEM returned in the wrong state. */ +#define VERR_VMM_WRONG_NEM_VMCPU_STATE (-2718) +/** Got back from vmmR0CallRing3SetJmp with the context hook still enabled. */ +#define VERR_VMM_CONTEXT_HOOK_STILL_ENABLED (-2719) +/** Cannot block in ring-0. */ +#define VERR_VMM_CANNOT_BLOCK (-2720) +/** @} */ + + +/** @name Pluggable Device and Driver Manager (PDM) Status Codes + * @{ + */ +/** An invalid LUN specification was given. */ +#define VERR_PDM_NO_SUCH_LUN (-2800) +/** A device encountered an unknown configuration value. + * This means that the device is potentially misconfigured and the device + * construction or unit attachment failed because of this. */ +#define VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES (-2801) +/** The above driver doesn't export a interface required by a driver being + * attached to it. Typical misconfiguration problem. */ +#define VERR_PDM_MISSING_INTERFACE_ABOVE (-2802) +/** The below driver doesn't export a interface required by the drive + * having attached it. Typical misconfiguration problem. */ +#define VERR_PDM_MISSING_INTERFACE_BELOW (-2803) +/** A device didn't find a required interface with an attached driver. + * Typical misconfiguration problem. */ +#define VERR_PDM_MISSING_INTERFACE (-2804) +/** A driver encountered an unknown configuration value. + * This means that the driver is potentially misconfigured and the driver + * construction failed because of this. */ +#define VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES (-2805) +/** The PCI bus assigned to a device didn't have room for it. + * Either too many devices are configured on the same PCI bus, or there are + * some internal problem where PDM/PCI doesn't free up slots when unplugging devices. */ +#define VERR_PDM_TOO_PCI_MANY_DEVICES (-2806) +/** A queue is out of free items, the queueing operation failed. */ +#define VERR_PDM_NO_QUEUE_ITEMS (-2807) +/** Not possible to attach further drivers to the driver. + * A driver which doesn't support attachments (below of course) will + * return this status code if it found that further drivers were configured + * to be attached to it. */ +#define VERR_PDM_DRVINS_NO_ATTACH (-2808) +/** Not possible to attach drivers to the device. + * A device which doesn't support attachments (below of course) will + * return this status code if it found that drivers were configured + * to be attached to it. */ +#define VERR_PDM_DEVINS_NO_ATTACH (-2809) +/** No attached driver. + * The PDMDRVHLP::pfnAttach and PDMDEVHLP::pfnDriverAttach will return + * this error when no driver was configured to be attached. */ +#define VERR_PDM_NO_ATTACHED_DRIVER (-2810) +/** The media geometry hasn't been set yet, so it cannot be obtained. + * The caller should then calculate the geometry from the media size. */ +#define VERR_PDM_GEOMETRY_NOT_SET (-2811) +/** The media translation hasn't been set yet, so it cannot be obtained. + * The caller should then guess the translation. */ +#define VERR_PDM_TRANSLATION_NOT_SET (-2812) +/** The media is not mounted, operation requires a mounted media. */ +#define VERR_PDM_MEDIA_NOT_MOUNTED (-2813) +/** Mount failed because a media was already mounted. Unmount the media + * and retry the mount. */ +#define VERR_PDM_MEDIA_MOUNTED (-2814) +/** The media is locked and cannot be unmounted. */ +#define VERR_PDM_MEDIA_LOCKED (-2815) +/** No 'Type' attribute in the DrvBlock configuration. + * Misconfiguration. */ +#define VERR_PDM_BLOCK_NO_TYPE (-2816) +/** The 'Type' attribute in the DrvBlock configuration had an unknown value. + * Misconfiguration. */ +#define VERR_PDM_BLOCK_UNKNOWN_TYPE (-2817) +/** The 'Translation' attribute in the DrvBlock configuration had an unknown value. + * Misconfiguration. */ +#define VERR_PDM_BLOCK_UNKNOWN_TRANSLATION (-2818) +/** The block driver type wasn't supported. + * Misconfiguration of the kind you get when attaching a floppy to an IDE controller. */ +#define VERR_PDM_UNSUPPORTED_BLOCK_TYPE (-2819) +/** A attach or prepare mount call failed because the driver already + * had a driver attached. */ +#define VERR_PDM_DRIVER_ALREADY_ATTACHED (-2820) +/** An attempt on detaching a driver without anyone actually being attached, or + * performing any other operation on an attached driver. */ +#define VERR_PDM_NO_DRIVER_ATTACHED (-2821) +/** The attached driver configuration is missing the 'Driver' attribute. */ +#define VERR_PDM_CFG_MISSING_DRIVER_NAME (-2822) +/** The configured driver wasn't found. + * Either the necessary driver modules wasn't loaded, the name was + * misspelled, or it was a misconfiguration. */ +#define VERR_PDM_DRIVER_NOT_FOUND (-2823) +/** The Ring-3 module was already loaded. */ +#define VINF_PDM_ALREADY_LOADED (2824) +/** The name of the module clashed with an existing module. */ +#define VERR_PDM_MODULE_NAME_CLASH (-2825) +/** Couldn't find any export for registration of drivers/devices. */ +#define VERR_PDM_NO_REGISTRATION_EXPORT (-2826) +/** A module name is too long. */ +#define VERR_PDM_MODULE_NAME_TOO_LONG (-2827) +/** Driver name clash. Another driver with the same name as the + * one being registered exists. */ +#define VERR_PDM_DRIVER_NAME_CLASH (-2828) +/** The version of the driver registration structure is unknown + * to this VBox version. Either mixing incompatible versions or + * the structure isn't correctly initialized. */ +#define VERR_PDM_UNKNOWN_DRVREG_VERSION (-2829) +/** Invalid entry in the driver registration structure. */ +#define VERR_PDM_INVALID_DRIVER_REGISTRATION (-2830) +/** Invalid host bit mask. */ +#define VERR_PDM_INVALID_DRIVER_HOST_BITS (-2831) +/** Not possible to detach a driver because the above driver/device + * doesn't support it. The above entity doesn't implement the pfnDetach call. */ +#define VERR_PDM_DRIVER_DETACH_NOT_POSSIBLE (-2832) +/** No PCI Bus is available to register the device with. This is usually a + * misconfiguration or in rare cases a buggy pci device. */ +#define VERR_PDM_NO_PCI_BUS (-2833) +/** The device is not a registered PCI device and thus cannot + * perform any PCI operations. The device forgot to register it self. */ +#define VERR_PDM_NOT_PCI_DEVICE (-2834) + +/** The version of the device registration structure is unknown + * to this VBox version. Either mixing incompatible versions or + * the structure isn't correctly initialized. */ +#define VERR_PDM_UNKNOWN_DEVREG_VERSION (-2835) +/** Invalid entry in the device registration structure. */ +#define VERR_PDM_INVALID_DEVICE_REGISTRATION (-2836) +/** Invalid host bit mask. */ +#define VERR_PDM_INVALID_DEVICE_GUEST_BITS (-2837) +/** The guest bit mask didn't match the guest being loaded. */ +#define VERR_PDM_INVALID_DEVICE_HOST_BITS (-2838) +/** Device name clash. Another device with the same name as the + * one being registered exists. */ +#define VERR_PDM_DEVICE_NAME_CLASH (-2839) +/** The device wasn't found. There was no registered device + * by that name. */ +#define VERR_PDM_DEVICE_NOT_FOUND (-2840) +/** The device instance was not found. */ +#define VERR_PDM_DEVICE_INSTANCE_NOT_FOUND (-2841) +/** The device instance have no base interface. */ +#define VERR_PDM_DEVICE_INSTANCE_NO_IBASE (-2842) +/** The device instance have no such logical unit. */ +#define VERR_PDM_DEVICE_INSTANCE_LUN_NOT_FOUND (-2843) +/** The driver instance could not be found. */ +#define VERR_PDM_DRIVER_INSTANCE_NOT_FOUND (-2844) +/** Logical Unit was not found. */ +#define VERR_PDM_LUN_NOT_FOUND (-2845) +/** The Logical Unit was found, but it had no driver attached to it. */ +#define VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN (-2846) +/** The Logical Unit was found, but it had no driver attached to it. */ +#define VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN 2846 +/** No PIC device instance is registered with the current VM and thus + * the PIC operation cannot be performed. */ +#define VERR_PDM_NO_PIC_INSTANCE (-2847) +/** No APIC device instance is registered with the current VM and thus + * the APIC operation cannot be performed. */ +#define VERR_PDM_NO_APIC_INSTANCE (-2848) +/** No DMAC device instance is registered with the current VM and thus + * the DMA operation cannot be performed. */ +#define VERR_PDM_NO_DMAC_INSTANCE (-2849) +/** No RTC device instance is registered with the current VM and thus + * the RTC or CMOS operation cannot be performed. */ +#define VERR_PDM_NO_RTC_INSTANCE (-2850) +/** Unable to open the host interface due to a sharing violation . */ +#define VERR_PDM_HIF_SHARING_VIOLATION (-2851) +/** Unable to open the host interface. */ +#define VERR_PDM_HIF_OPEN_FAILED (-2852) +/** The device doesn't support runtime driver attaching. + * The PDMDEVREG::pfnAttach callback function is NULL. */ +#define VERR_PDM_DEVICE_NO_RT_ATTACH (-2853) +/** The driver doesn't support runtime driver attaching. + * The PDMDRVREG::pfnAttach callback function is NULL. */ +#define VERR_PDM_DRIVER_NO_RT_ATTACH (-2854) +/** Invalid host interface version. */ +#define VERR_PDM_HIF_INVALID_VERSION (-2855) + +/** The version of the USB device registration structure is unknown + * to this VBox version. Either mixing incompatible versions or + * the structure isn't correctly initialized. */ +#define VERR_PDM_UNKNOWN_USBREG_VERSION (-2856) +/** Invalid entry in the device registration structure. */ +#define VERR_PDM_INVALID_USB_REGISTRATION (-2857) +/** Driver name clash. Another driver with the same name as the + * one being registered exists. */ +#define VERR_PDM_USB_NAME_CLASH (-2858) +/** The USB hub is already registered. */ +#define VERR_PDM_USB_HUB_EXISTS (-2859) +/** Couldn't find any USB hubs to attach the device to. */ +#define VERR_PDM_NO_USB_HUBS (-2860) +/** Couldn't find any free USB ports to attach the device to. */ +#define VERR_PDM_NO_USB_PORTS (-2861) +/** Couldn't find the USB Proxy device. Using OSE? */ +#define VERR_PDM_NO_USBPROXY (-2862) +/** The async completion template is still used. */ +#define VERR_PDM_ASYNC_TEMPLATE_BUSY (-2863) +/** The async completion task is already suspended. */ +#define VERR_PDM_ASYNC_COMPLETION_ALREADY_SUSPENDED (-2864) +/** The async completion task is not suspended. */ +#define VERR_PDM_ASYNC_COMPLETION_NOT_SUSPENDED (-2865) +/** The driver properties were invalid, and as a consequence construction + * failed. Caused my unusable media or similar problems. */ +#define VERR_PDM_DRIVER_INVALID_PROPERTIES (-2866) +/** Too many instances of a device. */ +#define VERR_PDM_TOO_MANY_DEVICE_INSTANCES (-2867) +/** Too many instances of a driver. */ +#define VERR_PDM_TOO_MANY_DRIVER_INSTANCES (-2868) +/** Too many instances of a usb device. */ +#define VERR_PDM_TOO_MANY_USB_DEVICE_INSTANCES (-2869) +/** The device instance structure version has changed. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_DEVINS_VERSION_MISMATCH (-2870) +/** The device helper structure version has changed. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_DEVHLP_VERSION_MISMATCH (-2871) +/** The USB device instance structure version has changed. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_USBINS_VERSION_MISMATCH (-2872) +/** The USB device helper structure version has changed. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_USBHLPR3_VERSION_MISMATCH (-2873) +/** The driver instance structure version has changed. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_DRVINS_VERSION_MISMATCH (-2874) +/** The driver helper structure version has changed. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_DRVHLPR3_VERSION_MISMATCH (-2875) +/** Generic device structure version mismatch. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_DEVICE_VERSION_MISMATCH (-2876) +/** Generic USB device structure version mismatch. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_USBDEV_VERSION_MISMATCH (-2877) +/** Generic driver structure version mismatch. + * + * If you have upgraded VirtualBox recently, please make sure you have + * terminated all VMs and upgraded any extension packs. If this error + * persists, try re-installing VirtualBox. */ +#define VERR_PDM_DRIVER_VERSION_MISMATCH (-2878) +/** PDMVMMDevHeapR3ToGCPhys failure. */ +#define VERR_PDM_DEV_HEAP_R3_TO_GCPHYS (-2879) +/** A legacy device isn't implementing the HPET notification interface. */ +#define VERR_PDM_HPET_LEGACY_NOTIFY_MISSING (-2880) +/** Internal processing error in the critical section code. */ +#define VERR_PDM_CRITSECT_IPE (-2881) +/** The critical section being deleted was not found. */ +#define VERR_PDM_CRITSECT_NOT_FOUND (-2882) +/** A PDMThread API was called by the wrong thread. */ +#define VERR_PDM_THREAD_INVALID_CALLER (-2883) +/** Internal processing error \#1 in the PDM Thread code. */ +#define VERR_PDM_THREAD_IPE_1 (-2884) +/** Internal processing error \#2 in the PDM Thread code. */ +#define VERR_PDM_THREAD_IPE_2 (-2885) +/** Only one PCI function is supported per PDM device. */ +#define VERR_PDM_ONE_PCI_FUNCTION_PER_DEVICE (-2886) +/** Bad PCI configuration. */ +#define VERR_PDM_BAD_PCI_CONFIG (-2887) +/** Internal processing error # in the PDM device code. */ +#define VERR_PDM_DEV_IPE_1 (-2888) +/** Misconfigured driver chain transformation. */ +#define VERR_PDM_MISCONFIGURED_DRV_TRANSFORMATION (-2889) +/** The driver is already removed, not more transformations possible (at + * present). */ +#define VERR_PDM_CANNOT_TRANSFORM_REMOVED_DRIVER (-2890) +/** The PCI device isn't configured as a busmaster, physical memory access + * rejected. */ +#define VERR_PDM_NOT_PCI_BUS_MASTER (-2891) +/** Got into a part of PDM that is not used when HM (VT-x/AMD-V) is enabled. */ +#define VERR_PDM_HM_IPE (-2892) +/** The I/O request was canceled. */ +#define VERR_PDM_MEDIAEX_IOREQ_CANCELED (-2893) +/** There is not enough room to store the data. */ +#define VERR_PDM_MEDIAEX_IOBUF_OVERFLOW (-2894) +/** There is not enough data to satisfy the request. */ +#define VERR_PDM_MEDIAEX_IOBUF_UNDERRUN (-2895) +/** The I/O request ID is already existing. */ +#define VERR_PDM_MEDIAEX_IOREQID_CONFLICT (-2896) +/** The I/O request ID was not found. */ +#define VERR_PDM_MEDIAEX_IOREQID_NOT_FOUND (-2897) +/** The I/O request is in progress. */ +#define VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS 2898 +/** The I/O request is in an invalid state for this operation. */ +#define VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE (-2899) + +/** Returned by PCI config space callbacks to indicate taking default action. */ +#define VINF_PDM_PCI_DO_DEFAULT (7200) +/** Failed to abort entering a critical section in ring-0. */ +#define VERR_PDM_CRITSECT_ABORT_FAILED (-7201) +/** Too many readers on read/write critical section. */ +#define VERR_PDM_CRITSECTRW_TOO_MANY_READERS (-7202) +/** Too many writes on read/write critical section. */ +#define VERR_PDM_CRITSECTRW_TOO_MANY_WRITERS (-7203) +/** Too many write or write/read recursions on read/write critical section. */ +#define VERR_PDM_CRITSECTRW_TOO_MANY_RECURSIONS (-7204) +/** Internal error in read-write critical section. */ +#define VERR_PDM_CRITSECTRW_IPE (-7205) +/** Misaligned read/write critical section. */ +#define VERR_PDM_CRITSECTRW_MISALIGNED (-7206) +/** @} */ + + +/** @name Host-Guest Communication Manager (HGCM) Status Codes + * @{ + */ +/** Requested service does not exist. */ +#define VERR_HGCM_SERVICE_NOT_FOUND (-2900) +/** Service rejected client connection */ +#define VINF_HGCM_CLIENT_REJECTED 2901 +/** Command address is invalid. */ +#define VERR_HGCM_INVALID_CMD_ADDRESS (-2902) +/** Service will execute the command in background. */ +#define VINF_HGCM_ASYNC_EXECUTE 2903 +/** HGCM could not perform requested operation because of an internal error. */ +#define VERR_HGCM_INTERNAL (-2904) +/** Invalid HGCM client id. */ +#define VERR_HGCM_INVALID_CLIENT_ID (-2905) +/** The HGCM is saving state. */ +#define VINF_HGCM_SAVE_STATE (2906) +/** Requested service already exists. */ +#define VERR_HGCM_SERVICE_EXISTS (-2907) +/** Too many clients for the service. */ +#define VERR_HGCM_TOO_MANY_CLIENTS (-2908) +/** Too many calls to the service from a client. */ +#define VERR_HGCM_TOO_MANY_CLIENT_CALLS (-2909) +/** @} */ + + +/** @name Network Address Translation Driver (DrvNAT) Status Codes + * @{ + */ +/** Failed to convert the specified Guest IP to a binary IP address. + * Malformed input. */ +#define VERR_NAT_REDIR_GUEST_IP (-3001) +/** Failed while setting up a redirector rule. + * There probably is a conflict between the rule and some existing + * service on the computer. */ +#define VERR_NAT_REDIR_SETUP (-3002) +/** @} */ + + +/** @name HostIF Driver (DrvTUN) Status Codes + * @{ + */ +/** The Host Interface Networking init program failed. */ +#define VERR_HOSTIF_INIT_FAILED (-3100) +/** The Host Interface Networking device name is too long. */ +#define VERR_HOSTIF_DEVICE_NAME_TOO_LONG (-3101) +/** The Host Interface Networking name config IOCTL call failed. */ +#define VERR_HOSTIF_IOCTL (-3102) +/** Failed to make the Host Interface Networking handle non-blocking. */ +#define VERR_HOSTIF_BLOCKING (-3103) +/** If a Host Interface Networking filehandle was specified it's not allowed to + * have any init or term programs. */ +#define VERR_HOSTIF_FD_AND_INIT_TERM (-3104) +/** The Host Interface Networking terminate program failed. */ +#define VERR_HOSTIF_TERM_FAILED (-3105) +/** @} */ + + +/** @name VBox HDD Container (VD) Status Codes + * @{ + */ +/** Invalid image type. */ +#define VERR_VD_INVALID_TYPE (-3200) +/** Operation can't be done in current HDD container state. */ +#define VERR_VD_INVALID_STATE (-3201) +/** Configuration value not found. */ +#define VERR_VD_VALUE_NOT_FOUND (-3202) +/** Virtual HDD is not opened. */ +#define VERR_VD_NOT_OPENED (-3203) +/** Requested image is not opened. */ +#define VERR_VD_IMAGE_NOT_FOUND (-3204) +/** Image is read-only. */ +#define VERR_VD_IMAGE_READ_ONLY (-3205) +/** Geometry hasn't been set. */ +#define VERR_VD_GEOMETRY_NOT_SET (-3206) +/** No data for this block in image. */ +#define VERR_VD_BLOCK_FREE (-3207) +/** Differencing and parent images can't be used together due to UUID. */ +#define VERR_VD_UUID_MISMATCH (-3208) +/** Asynchronous I/O request finished. */ +#define VINF_VD_ASYNC_IO_FINISHED 3209 +/** Asynchronous I/O is not finished yet. */ +#define VERR_VD_ASYNC_IO_IN_PROGRESS (-3210) +/** The image is too small or too large for this format. */ +#define VERR_VD_INVALID_SIZE (-3211) +/** Configuration value is unknown. This indicates misconfiguration. */ +#define VERR_VD_UNKNOWN_CFG_VALUES (-3212) +/** Interface is unknown. This indicates misconfiguration. */ +#define VERR_VD_UNKNOWN_INTERFACE (-3213) +/** The DEK for disk encryption is missing. */ +#define VERR_VD_DEK_MISSING (-3214) +/** The provided password to decrypt the DEK was incorrect. */ +#define VERR_VD_PASSWORD_INCORRECT (-3215) +/** Generic: Invalid image file header. Use this for plugins. */ +#define VERR_VD_GEN_INVALID_HEADER (-3220) +/** VDI: Invalid image file header. */ +#define VERR_VD_VDI_INVALID_HEADER (-3230) +/** VDI: Invalid image file header: invalid signature. */ +#define VERR_VD_VDI_INVALID_SIGNATURE (-3231) +/** VDI: Invalid image file header: invalid version. */ +#define VERR_VD_VDI_UNSUPPORTED_VERSION (-3232) +/** Comment string is too long. */ +#define VERR_VD_VDI_COMMENT_TOO_LONG (-3233) +/** VMDK: Invalid image file header. */ +#define VERR_VD_VMDK_INVALID_HEADER (-3240) +/** VMDK: Invalid image file header: invalid version. */ +#define VERR_VD_VMDK_UNSUPPORTED_VERSION (-3241) +/** VMDK: Image property not found. */ +#define VERR_VD_VMDK_VALUE_NOT_FOUND (-3242) +/** VMDK: Operation can't be done in current image state. */ +#define VERR_VD_VMDK_INVALID_STATE (-3243) +/** VMDK: Format is invalid/inconsistent. */ +#define VERR_VD_VMDK_INVALID_FORMAT (-3244) +/** VMDK: Invalid write position. */ +#define VERR_VD_VMDK_INVALID_WRITE (-3245) +/** iSCSI: Invalid header, i.e. dummy for validity check. */ +#define VERR_VD_ISCSI_INVALID_HEADER (-3250) +/** iSCSI: Operation can't be done in current image state. */ +#define VERR_VD_ISCSI_INVALID_STATE (-3251) +/** iSCSI: Invalid device type (not a disk). */ +#define VERR_VD_ISCSI_INVALID_TYPE (-3252) +/** iSCSI: Initiator secret not decrypted */ +#define VERR_VD_ISCSI_SECRET_ENCRYPTED (-3253) +/** VHD: Invalid image file header. */ +#define VERR_VD_VHD_INVALID_HEADER (-3260) +/** Parallels HDD: Invalid image file header. */ +#define VERR_VD_PARALLELS_INVALID_HEADER (-3265) +/** DMG: Invalid image file header. */ +#define VERR_VD_DMG_INVALID_HEADER (-3267) +/** Raw: Invalid image file header. */ +#define VERR_VD_RAW_INVALID_HEADER (-3270) +/** Raw: Invalid image file type. */ +#define VERR_VD_RAW_INVALID_TYPE (-3271) +/** The backend needs more metadata before it can continue. */ +#define VERR_VD_NOT_ENOUGH_METADATA (-3272) +/** Halt the current I/O context until further notification from the backend. */ +#define VERR_VD_IOCTX_HALT (-3273) +/** The disk has a cache attached already. */ +#define VERR_VD_CACHE_ALREADY_EXISTS (-3274) +/** There is no cache attached to the disk. */ +#define VERR_VD_CACHE_NOT_FOUND (-3275) +/** The cache is not up to date with the image. */ +#define VERR_VD_CACHE_NOT_UP_TO_DATE (-3276) +/** The given range does not meet the required alignment. */ +#define VERR_VD_DISCARD_ALIGNMENT_NOT_MET (-3277) +/** The discard operation is not supported for this image. */ +#define VERR_VD_DISCARD_NOT_SUPPORTED (-3278) +/** The image is the correct format but is corrupted. */ +#define VERR_VD_IMAGE_CORRUPTED (-3279) +/** Repairing the image is not supported. */ +#define VERR_VD_IMAGE_REPAIR_NOT_SUPPORTED (-3280) +/** Repairing the image is not possible because the corruption is to severe. */ +#define VERR_VD_IMAGE_REPAIR_IMPOSSIBLE (-3281) +/** Reading from the image was not possible because the offset is out of the image range. + * This usually indicates that there is a minor corruption in the image meta data. */ +#define VERR_VD_READ_OUT_OF_RANGE (-3282) +/** Block read was marked as free in the image and returned as a zero block. */ +#define VINF_VD_NEW_ZEROED_BLOCK 3283 +/** Unable to parse the XML in DMG file. */ +#define VERR_VD_DMG_XML_PARSE_ERROR (-3284) +/** Unable to locate a usable DMG file within the XAR archive. */ +#define VERR_VD_DMG_NOT_FOUND_INSIDE_XAR (-3285) +/** The size of the raw image is not dividable by 512 */ +#define VERR_VD_RAW_SIZE_MODULO_512 (-3286) +/** The size of the raw image is not dividable by 2048 */ +#define VERR_VD_RAW_SIZE_MODULO_2048 (-3287) +/** The size of the raw optical image is too small (<= 32K) */ +#define VERR_VD_RAW_SIZE_OPTICAL_TOO_SMALL (-3288) +/** The size of the raw floppy image is too big (>2.88MB) */ +#define VERR_VD_RAW_SIZE_FLOPPY_TOO_BIG (-3289) +/** Reducing the size is not supported */ +#define VERR_VD_SHRINK_NOT_SUPPORTED (-3290) +/** @} */ + + +/** @name VBox Guest Library (VBGL) Status Codes + * @{ + */ +/** Library was not initialized. */ +#define VERR_VBGL_NOT_INITIALIZED (-3300) +/** Virtual address was not allocated by the library. */ +#define VERR_VBGL_INVALID_ADDR (-3301) +/** IOCtl to VBoxGuest driver failed. */ +#define VERR_VBGL_IOCTL_FAILED (-3302) +/** @} */ + + +/** @name VBox USB (VUSB) Status Codes + * @{ + */ +/** No available ports on the hub. + * This error is returned when a device is attempted created and/or attached + * to a hub which is out of ports. */ +#define VERR_VUSB_NO_PORTS (-3400) +/** The requested operation cannot be performed on a detached USB device. */ +#define VERR_VUSB_DEVICE_NOT_ATTACHED (-3401) +/** Failed to allocate memory for a URB. */ +#define VERR_VUSB_NO_URB_MEMORY (-3402) +/** General failure during URB queuing. + * This will go away when the queueing gets proper status code handling. */ +#define VERR_VUSB_FAILED_TO_QUEUE_URB (-3403) +/** Device creation failed because the USB device name was not found. */ +#define VERR_VUSB_DEVICE_NAME_NOT_FOUND (-3404) +/** Not permitted to open the USB device. + * The user doesn't have access to the device in the usbfs, check the mount options. */ +#define VERR_VUSB_USBFS_PERMISSION (-3405) +/** The requested operation cannot be performed because the device + * is currently being reset. */ +#define VERR_VUSB_DEVICE_IS_RESETTING (-3406) +/** The requested operation cannot be performed because the device + * is currently suspended. */ +#define VERR_VUSB_DEVICE_IS_SUSPENDED (-3407) +/** Not permitted to open the USB device. + * The user doesn't have access to the device node, check group memberships. */ +#define VERR_VUSB_USB_DEVICE_PERMISSION (-3408) +/** @} */ + + +/** @name VBox VGA Status Codes + * @{ + */ +/** One of the custom modes was incorrect. + * The format or bit count of the custom mode value is invalid. */ +#define VERR_VGA_INVALID_CUSTOM_MODE (-3500) +/** The display connector is resizing. */ +#define VINF_VGA_RESIZE_IN_PROGRESS (3501) +/** Unexpected PCI region change during VGA saved state loading. */ +#define VERR_VGA_UNEXPECTED_PCI_REGION_LOAD_CHANGE (-3502) +/** Unabled to locate or load the OpenGL library. */ +#define VERR_VGA_GL_LOAD_FAILURE (-3503) +/** Unabled to locate an OpenGL symbol. */ +#define VERR_VGA_GL_SYMBOL_NOT_FOUND (-3504) +/** @} */ + + +/** @name Internal Networking Status Codes + * @{ + */ +/** The networking interface to filter was not found. */ +#define VERR_INTNET_FLT_IF_NOT_FOUND (-3600) +/** The networking interface to filter was busy (used by someone). */ +#define VERR_INTNET_FLT_IF_BUSY (-3601) +/** Failed to create or connect to a networking interface filter. */ +#define VERR_INTNET_FLT_IF_FAILED (-3602) +/** The network already exists with a different trunk configuration. */ +#define VERR_INTNET_INCOMPATIBLE_TRUNK (-3603) +/** The network already exists with a different security profile (restricted / public). */ +#define VERR_INTNET_INCOMPATIBLE_FLAGS (-3604) +/** Failed to create a virtual network interface instance. */ +#define VERR_INTNET_FLT_VNIC_CREATE_FAILED (-3605) +/** Failed to retrieve a virtual network interface link ID. */ +#define VERR_INTNET_FLT_VNIC_LINK_ID_NOT_FOUND (-3606) +/** Failed to initialize a virtual network interface instance. */ +#define VERR_INTNET_FLT_VNIC_INIT_FAILED (-3607) +/** Failed to open a virtual network interface instance. */ +#define VERR_INTNET_FLT_VNIC_OPEN_FAILED (-3608) +/** Failed to retrieve underlying (lower mac) link. */ +#define VERR_INTNET_FLT_LOWER_LINK_INFO_NOT_FOUND (-3609) +/** Failed to open underlying link instance. */ +#define VERR_INTNET_FLT_LOWER_LINK_OPEN_FAILED (-3610) +/** Failed to get underlying link ID. */ +#define VERR_INTNET_FLT_LOWER_LINK_ID_NOT_FOUND (-3611) +/** @} */ + + +/** @name Support Driver Status Codes + * @{ + */ +/** The component factory was not found. */ +#define VERR_SUPDRV_COMPONENT_NOT_FOUND (-3700) +/** The component factories do not support the requested interface. */ +#define VERR_SUPDRV_INTERFACE_NOT_SUPPORTED (-3701) +/** The service module was not found. */ +#define VERR_SUPDRV_SERVICE_NOT_FOUND (-3702) +/** The host kernel is too old. */ +#define VERR_SUPDRV_KERNEL_TOO_OLD_FOR_VTX (-3703) +/** Bad VTG magic value. */ +#define VERR_SUPDRV_VTG_MAGIC (-3704) +/** Bad VTG bit count value. */ +#define VERR_SUPDRV_VTG_BITS (-3705) +/** Bad VTG header - misc. */ +#define VERR_SUPDRV_VTG_BAD_HDR_MISC (-3706) +/** Bad VTG header - offset. */ +#define VERR_SUPDRV_VTG_BAD_HDR_OFF (-3707) +/** Bad VTG header - offset. */ +#define VERR_SUPDRV_VTG_BAD_HDR_PTR (-3708) +/** Bad VTG header - to low value. */ +#define VERR_SUPDRV_VTG_BAD_HDR_TOO_FEW (-3709) +/** Bad VTG header - to high value. */ +#define VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH (-3710) +/** Bad VTG header - size value is not a multiple of the structure size. */ +#define VERR_SUPDRV_VTG_BAD_HDR_NOT_MULTIPLE (-3711) +/** Bad VTG string table offset. */ +#define VERR_SUPDRV_VTG_STRTAB_OFF (-3712) +/** Bad VTG string. */ +#define VERR_SUPDRV_VTG_BAD_STRING (-3713) +/** VTG string is too long. */ +#define VERR_SUPDRV_VTG_STRING_TOO_LONG (-3714) +/** Bad VTG attribute value. */ +#define VERR_SUPDRV_VTG_BAD_ATTR (-3715) +/** Bad VTG provider descriptor. */ +#define VERR_SUPDRV_VTG_BAD_PROVIDER (-3716) +/** Bad VTG probe descriptor. */ +#define VERR_SUPDRV_VTG_BAD_PROBE (-3717) +/** Bad VTG argument list descriptor. */ +#define VERR_SUPDRV_VTG_BAD_ARGLIST (-3718) +/** Bad VTG probe enabled data. */ +#define VERR_SUPDRV_VTG_BAD_PROBE_ENABLED (-3719) +/** Bad VTG probe location record. */ +#define VERR_SUPDRV_VTG_BAD_PROBE_LOC (-3720) +/** The VTG object for the session or image has already been registered. */ +#define VERR_SUPDRV_VTG_ALREADY_REGISTERED (-3721) +/** A driver may only register one VTG object per session. */ +#define VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION (-3722) +/** A tracer has already been registered. */ +#define VERR_SUPDRV_TRACER_ALREADY_REGISTERED (-3723) +/** The session has no tracer associated with it. */ +#define VERR_SUPDRV_TRACER_NOT_REGISTERED (-3724) +/** The tracer has already been opened in this sesssion. */ +#define VERR_SUPDRV_TRACER_ALREADY_OPENED (-3725) +/** The tracer has not been opened. */ +#define VERR_SUPDRV_TRACER_NOT_OPENED (-3726) +/** There is no tracer present. */ +#define VERR_SUPDRV_TRACER_NOT_PRESENT (-3727) +/** The tracer is unloading. */ +#define VERR_SUPDRV_TRACER_UNLOADING (-3728) +/** Another thread in the session is talking to the tracer. */ +#define VERR_SUPDRV_TRACER_SESSION_BUSY (-3729) +/** The tracer cannot open it self in the same session. */ +#define VERR_SUPDRV_TRACER_CANNOT_OPEN_SELF (-3730) +/** Bad argument flags. */ +#define VERR_SUPDRV_TRACER_BAD_ARG_FLAGS (-3731) +/** The session has reached the max number of (user mode) providers. */ +#define VERR_SUPDRV_TRACER_TOO_MANY_PROVIDERS (-3732) +/** The tracepoint provider object is too large. */ +#define VERR_SUPDRV_TRACER_TOO_LARGE (-3733) +/** The probe location array isn't adjacent to the probe enable array. */ +#define VERR_SUPDRV_TRACER_UMOD_NOT_ADJACENT (-3734) +/** The user mode tracepoint provider has too many probe locations and + * probes. */ +#define VERR_SUPDRV_TRACER_UMOD_TOO_MANY_PROBES (-3735) +/** The user mode tracepoint provider string table is too large. */ +#define VERR_SUPDRV_TRACER_UMOD_STRTAB_TOO_BIG (-3736) +/** The user mode tracepoint provider string table offset is bad. */ +#define VERR_SUPDRV_TRACER_UMOD_STRTAB_OFF_BAD (-3737) +/** The VM process was denied access to vboxdrv because someone have managed to + * open the process or its main thread with too broad access rights. */ +#define VERR_SUPDRV_HARDENING_EVIL_HANDLE (-3738) +/** Error opening the ApiPort LPC object. */ +#define VERR_SUPDRV_APIPORT_OPEN_ERROR (-3739) +/** Error enumerating all processes in the session. */ +#define VERR_SUPDRV_SESSION_PROCESS_ENUM_ERROR (-3740) +/** The CSRSS instance associated with the client process could not be + * located. */ +#define VERR_SUPDRV_CSRSS_NOT_FOUND (-3741) +/** Type error opening the ApiPort LPC object. */ +#define VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE (-3742) +/** Failed to measure the TSC delta between two CPUs. */ +#define VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED (-3743) +/** Failed to calculate the TSC frequency. */ +#define VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED (-3744) +/** Failed to get the delta-adjusted TSC value. */ +#define VERR_SUPDRV_TSC_READ_FAILED (-3745) +/** Failed to measure the TSC delta between two CPUs, continue without any + * TSC-delta. */ +#define VWRN_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED 3746 +/** A TSC-delta measurement request is currently being serviced. */ +#define VERR_SUPDRV_TSC_DELTA_MEASUREMENT_BUSY (-3747) +/** The process trying to open VBoxDrv is not a budding VM process (1). */ +#define VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_1 (-3748) +/** The process trying to open VBoxDrv is not a budding VM process (2). */ +#define VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_2 (-3749) + +/** Raw-mode is unavailable courtesy of Hyper-V. */ +#define VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT (-7000) +/** @} */ + + +/** @name Support Library Status Codes + * @{ + */ +/** The specified path was not absolute (hardening). */ +#define VERR_SUPLIB_PATH_NOT_ABSOLUTE (-3750) +/** The specified path was not clean (hardening). */ +#define VERR_SUPLIB_PATH_NOT_CLEAN (-3751) +/** The specified path is too long (hardening). */ +#define VERR_SUPLIB_PATH_TOO_LONG (-3752) +/** The specified path is too short (hardening). */ +#define VERR_SUPLIB_PATH_TOO_SHORT (-3753) +/** The specified path has too many components (hardening). */ +#define VERR_SUPLIB_PATH_TOO_MANY_COMPONENTS (-3754) +/** The specified path is a root path (hardening). */ +#define VERR_SUPLIB_PATH_IS_ROOT (-3755) +/** Failed to enumerate directory (hardening). */ +#define VERR_SUPLIB_DIR_ENUM_FAILED (-3756) +/** Failed to stat a file/dir during enumeration (hardening). */ +#define VERR_SUPLIB_STAT_ENUM_FAILED (-3757) +/** Failed to stat a file/dir (hardening). */ +#define VERR_SUPLIB_STAT_FAILED (-3758) +/** Failed to fstat a native handle (hardening). */ +#define VERR_SUPLIB_FSTAT_FAILED (-3759) +/** Found an illegal symbolic link (hardening). */ +#define VERR_SUPLIB_SYMLINKS_ARE_NOT_PERMITTED (-3760) +/** Found something which isn't a file nor a directory (hardening). */ +#define VERR_SUPLIB_NOT_DIR_NOT_FILE (-3761) +/** The specified path is a directory and not a file (hardening). */ +#define VERR_SUPLIB_IS_DIRECTORY (-3762) +/** The specified path is a file and not a directory (hardening). */ +#define VERR_SUPLIB_IS_FILE (-3763) +/** The path is not the same object as the native handle (hardening). */ +#define VERR_SUPLIB_NOT_SAME_OBJECT (-3764) +/** The owner is not root (hardening). */ +#define VERR_SUPLIB_OWNER_NOT_ROOT (-3765) +/** The group is a non-system group and it has write access (hardening). */ +#define VERR_SUPLIB_WRITE_NON_SYS_GROUP (-3766) +/** The file or directory is world writable (hardening). */ +#define VERR_SUPLIB_WORLD_WRITABLE (-3767) +/** The argv[0] of an internal application does not match the executable image + * path (hardening). */ +#define VERR_SUPLIB_INVALID_ARGV0_INTERNAL (-3768) +/** The internal application does not reside in the correct place (hardening). */ +#define VERR_SUPLIB_INVALID_INTERNAL_APP_DIR (-3769) +/** Unable to establish trusted of VM process (0). */ +#define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0 (-3770) +/** Unable to establish trusted of VM process (1). */ +#define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1 (-3771) +/** Unable to establish trusted of VM process (2). */ +#define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2 (-3772) +/** Unable to establish trusted of VM process (3). */ +#define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_3 (-3773) +/** Unable to establish trusted of VM process (4). */ +#define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_4 (-3774) +/** Unable to establish trusted of VM process (5). */ +#define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_5 (-3775) +/** Unable to make text memory writeable (hardening). */ +#define VERR_SUPLIB_TEXT_NOT_WRITEABLE (-3776) +/** Unable to seal text memory again to protect against write access (hardening). */ +#define VERR_SUPLIB_TEXT_NOT_SEALED (-3777) +/** Unexpected instruction encountered for which there is no patch strategy + * implemented (hardening). */ +#define VERR_SUPLIB_UNEXPECTED_INSTRUCTION (-3778) +/** @} */ + + +/** @name VBox GMM Status Codes + * @{ + */ +/** Unable to allocate more pages from the host system. */ +#define VERR_GMM_OUT_OF_MEMORY (-3801) +/** Hit the global allocation limit. + * If you know there is still sufficient memory available, try raising the limit. */ +#define VERR_GMM_HIT_GLOBAL_LIMIT (-3802) +/** Hit the a VM account limit. */ +#define VERR_GMM_HIT_VM_ACCOUNT_LIMIT (-3803) +/** Attempt to free more memory than what was previously allocated. */ +#define VERR_GMM_ATTEMPT_TO_FREE_TOO_MUCH (-3804) +/** Attempted to report too many pages as deflated. */ +#define VERR_GMM_ATTEMPT_TO_DEFLATE_TOO_MUCH (-3805) +/** The page to be freed or updated was not found. */ +#define VERR_GMM_PAGE_NOT_FOUND (-3806) +/** The specified shared page was not actually private. */ +#define VERR_GMM_PAGE_NOT_PRIVATE (-3807) +/** The specified shared page was not actually shared. */ +#define VERR_GMM_PAGE_NOT_SHARED (-3808) +/** The page to be freed was already freed. */ +#define VERR_GMM_PAGE_ALREADY_FREE (-3809) +/** The page to be updated or freed was noted owned by the caller. */ +#define VERR_GMM_NOT_PAGE_OWNER (-3810) +/** The specified chunk was not found. */ +#define VERR_GMM_CHUNK_NOT_FOUND (-3811) +/** The chunk has already been mapped into the process. */ +#define VERR_GMM_CHUNK_ALREADY_MAPPED (-3812) +/** The chunk to be unmapped isn't actually mapped into the process. */ +#define VERR_GMM_CHUNK_NOT_MAPPED (-3813) +/** The chunk has been mapped too many times already (impossible). */ +#define VERR_GMM_TOO_MANY_CHUNK_MAPPINGS (-3814) +/** The reservation or reservation update was declined - too many VMs, too + * little memory, and/or too low GMM configuration. */ +#define VERR_GMM_MEMORY_RESERVATION_DECLINED (-3815) +/** A GMM sanity check failed. */ +#define VERR_GMM_IS_NOT_SANE (-3816) +/** Inserting a new chunk failed. */ +#define VERR_GMM_CHUNK_INSERT (-3817) +/** Failed to obtain the GMM instance. */ +#define VERR_GMM_INSTANCE (-3818) +/** Bad mutex semaphore flags. */ +#define VERR_GMM_MTX_FLAGS (-3819) +/** Internal processing error in the page allocator. */ +#define VERR_GMM_ALLOC_PAGES_IPE (-3820) +/** Invalid page count given to GMMR3FreePagesPerform. */ +#define VERR_GMM_ACTUAL_PAGES_IPE (-3821) +/** The shared module name is too long. */ +#define VERR_GMM_MODULE_NAME_TOO_LONG (-3822) +/** The shared module version string is too long. */ +#define VERR_GMM_MODULE_VERSION_TOO_LONG (-3823) +/** The shared module has too many regions. */ +#define VERR_GMM_TOO_MANY_REGIONS (-3824) +/** The guest has reported too many modules. */ +#define VERR_GMM_TOO_MANY_PER_VM_MODULES (-3825) +/** The guest has reported too many modules. */ +#define VERR_GMM_TOO_MANY_GLOBAL_MODULES (-3826) +/** The shared module is already registered. */ +#define VINF_GMM_SHARED_MODULE_ALREADY_REGISTERED (3827) +/** The shared module clashed address wise with a previously registered + * module. */ +#define VERR_GMM_SHARED_MODULE_ADDRESS_CLASH (-3828) +/** The shared module was not found. */ +#define VERR_GMM_SHARED_MODULE_NOT_FOUND (-3829) +/** The size of the shared module was out of range. */ +#define VERR_GMM_BAD_SHARED_MODULE_SIZE (-3830) +/** The size of the one or more regions in the shared module was out of + * range. */ +#define VERR_GMM_SHARED_MODULE_BAD_REGIONS_SIZE (-3831) +/** @} */ + + +/** @name VBox GVM Status Codes + * @{ + */ +/** The GVM is out of VM handle space. */ +#define VERR_GVM_TOO_MANY_VMS (-3900) +/** The EMT was not blocked at the time of the call. */ +#define VINF_GVM_NOT_BLOCKED 3901 +/** The EMT was not busy running guest code at the time of the call. */ +#define VINF_GVM_NOT_BUSY_IN_GC 3902 +/** RTThreadYield was called during a GVMMR0SchedPoll call. */ +#define VINF_GVM_YIELDED 3903 +/** @} */ + + +/** @name VBox VMX Status Codes + * @{ + */ +/** VMXON failed; possibly because it was already run before. */ +#define VERR_VMX_VMXON_FAILED (-4000) +/** Invalid VMCS pointer. + * (Can be OR'ed with VERR_VMX_INVALID_VMCS_FIELD.) */ +#define VERR_VMX_INVALID_VMCS_PTR (-4001) +/** Invalid VMCS index or write to read-only element. */ +#define VERR_VMX_INVALID_VMCS_FIELD (-4002) +/** Reserved for future status code that we wish to OR with + * VERR_VMX_INVALID_VMCS_PTR and VERR_VMX_INVALID_VMCS_FIELD. */ +#define VERR_VMX_RESERVED (-4003) +/** Invalid VMXON pointer. */ +#define VERR_VMX_INVALID_VMXON_PTR (-4004) +/** Unable to start VM execution. */ +#define VERR_VMX_UNABLE_TO_START_VM (-4005) +/** Unable to switch due to invalid host state. */ +#define VERR_VMX_INVALID_HOST_STATE (-4006) +/** VMX CPU extension not available in hardware. */ +#define VERR_VMX_NO_VMX (-4009) +/** CPU was incorrectly left in VMX root mode; incompatible with VirtualBox */ +#define VERR_VMX_IN_VMX_ROOT_MODE (-4011) +/** Somebody cleared X86_CR4_VMXE in the CR4 register. */ +#define VERR_VMX_X86_CR4_VMXE_CLEARED (-4012) +/** Failed to enable and lock VT-x features. */ +#define VERR_VMX_MSR_LOCKING_FAILED (-4013) +/** Unable to switch due to invalid guest state. */ +#define VERR_VMX_INVALID_GUEST_STATE (-4014) +/** Unexpected VM exit. */ +#define VERR_VMX_UNEXPECTED_EXIT (-4015) +/** Unexpected VM exception. */ +#define VERR_VMX_UNEXPECTED_EXCEPTION (-4016) +/** Unexpected interruption exit type. */ +#define VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE (-4017) +/** CPU is not in VMX root mode; unexpected when leaving VMX root mode. */ +#define VERR_VMX_NOT_IN_VMX_ROOT_MODE (-4018) +/** Undefined VM exit code. */ +#define VERR_VMX_UNDEFINED_EXIT_CODE (-4019) +/** VMPTRLD failed; possibly because of invalid VMCS launch-state. */ +#define VERR_VMX_VMPTRLD_FAILED (-4021) +/** Invalid VMCS pointer passed to VMLAUNCH/VMRESUME. */ +#define VERR_VMX_INVALID_VMCS_PTR_TO_START_VM (-4022) +/** Internal VMX processing error no 1. */ +#define VERR_VMX_IPE_1 (-4023) +/** Internal VMX processing error no 2. */ +#define VERR_VMX_IPE_2 (-4024) +/** Internal VMX processing error no 3. */ +#define VERR_VMX_IPE_3 (-4025) +/** Internal VMX processing error no 4. */ +#define VERR_VMX_IPE_4 (-4026) +/** Internal VMX processing error no 5. */ +#define VERR_VMX_IPE_5 (-4027) +/** VT-x features for all modes (SMX and non-SMX) disabled by the BIOS. */ +#define VERR_VMX_MSR_ALL_VMX_DISABLED (-4028) +/** VT-x features disabled by the BIOS. */ +#define VERR_VMX_MSR_VMX_DISABLED (-4029) +/** VT-x VMCS field cache invalid. */ +#define VERR_VMX_VMCS_FIELD_CACHE_INVALID (-4030) +/** Failed to set VMXON enable bit while enabling VT-x through the MSR. */ +#define VERR_VMX_MSR_VMX_ENABLE_FAILED (-4031) +/** Failed to enable VMXON-in-SMX bit while enabling VT-x through the MSR. */ +#define VERR_VMX_MSR_SMX_VMX_ENABLE_FAILED (-4032) +/** An operation caused a nested-guest VM-exit. */ +#define VINF_VMX_VMEXIT 4033 +/** Generic VM-entry failure. */ +#define VERR_VMX_VMENTRY_FAILED (-4033) +/** Generic VM-exit failure. */ +#define VERR_VMX_VMEXIT_FAILED (-4034) +/** The requested nested-guest VMX intercept is not active or not in + * nested-guest execution mode. */ +#define VINF_VMX_INTERCEPT_NOT_ACTIVE 4035 +/** The behavior of the instruction/operation is modified/needs modification + * in VMX non-root mode. */ +#define VINF_VMX_MODIFIES_BEHAVIOR 4036 +/** VMLAUNCH/VMRESUME succeeded, can enter nested-guest execution. */ +#define VINF_VMX_VMLAUNCH_VMRESUME 4037 +/** VT-x VMCS launch state invalid. */ +#define VERR_VMX_INVALID_VMCS_LAUNCH_STATE (-4038) +/** Precodition no 0 in hmR0VMXStartVm failed. */ +#define VERR_VMX_STARTVM_PRECOND_0 (-4039) +/** Precodition no 1 in hmR0VMXStartVm failed. */ +#define VERR_VMX_STARTVM_PRECOND_1 (-4040) +/** Precodition no 2 in hmR0VMXStartVm failed. */ +#define VERR_VMX_STARTVM_PRECOND_2 (-4041) +/** Precodition no 3 in hmR0VMXStartVm failed. */ +#define VERR_VMX_STARTVM_PRECOND_3 (-4042) +/** @} */ + + +/** @name VBox SVM Status Codes + * @{ + */ +/** Unable to start VM execution. */ +#define VERR_SVM_UNABLE_TO_START_VM (-4050) +/** AMD-V bit not set in K6_EFER MSR */ +#define VERR_SVM_ILLEGAL_EFER_MSR (-4051) +/** AMD-V CPU extension not available. */ +#define VERR_SVM_NO_SVM (-4052) +/** AMD-V CPU extension disabled (by BIOS). */ +#define VERR_SVM_DISABLED (-4053) +/** AMD-V CPU extension in-use. */ +#define VERR_SVM_IN_USE (-4054) +/** Invalid pVMCB. */ +#define VERR_SVM_INVALID_PVMCB (-4055) +/** Unexpected SVM exit. */ +#define VERR_SVM_UNEXPECTED_EXIT (-4056) +/** Unexpected SVM exception exit. */ +#define VERR_SVM_UNEXPECTED_XCPT_EXIT (-4057) +/** Unexpected SVM patch type. */ +#define VERR_SVM_UNEXPECTED_PATCH_TYPE (-4058) +/** Unable to start VM execution due to an invalid guest state. */ +#define VERR_SVM_INVALID_GUEST_STATE (-4059) +/** Unknown or unrecognized SVM exit. */ +#define VERR_SVM_UNKNOWN_EXIT (-4060) +/** Internal SVM processing error no 1. */ +#define VERR_SVM_IPE_1 (-4061) +/** Internal SVM processing error no 2. */ +#define VERR_SVM_IPE_2 (-4062) +/** Internal SVM processing error no 3. */ +#define VERR_SVM_IPE_3 (-4063) +/** Internal SVM processing error no 4. */ +#define VERR_SVM_IPE_4 (-4064) +/** Internal SVM processing error no 5. */ +#define VERR_SVM_IPE_5 (-4065) +/** The nested-guest \#VMEXIT processing failed, initiate shutdown. */ +#define VERR_SVM_VMEXIT_FAILED (-4066) +/** An operation caused a nested-guest SVM \#VMEXIT. */ +#define VINF_SVM_VMEXIT 4067 +/** VMRUN emulation succeeded, ready to immediately enter the nested-guest. */ +#define VINF_SVM_VMRUN 4068 +/** The requested nested-guest SVM intercept is not active or not in + * nested-guest execution mode. */ +#define VINF_SVM_INTERCEPT_NOT_ACTIVE 4069 +/** Precodition no 0 in hmR0SvmVmRun failed. */ +#define VERR_SVM_VMRUN_PRECOND_0 (-4070) +/** Precodition no 1 in hmR0SvmVmRun failed. */ +#define VERR_SVM_VMRUN_PRECOND_1 (-4071) +/** Precodition no 2 in hmR0SvmVmRun failed. */ +#define VERR_SVM_VMRUN_PRECOND_2 (-4072) +/** Precodition no 3 in hmR0SvmVmRun failed. */ +#define VERR_SVM_VMRUN_PRECOND_3 (-4073) +/** @} */ + + +/** @name VBox HM Status Codes + * @{ + */ +/** Host is about to go into suspend mode. */ +#define VERR_HM_SUSPEND_PENDING (-4100) +/** Conflicting CFGM values. */ +#define VERR_HM_CONFIG_MISMATCH (-4103) +/** Internal processing error in the HM init code. */ +#define VERR_HM_ALREADY_ENABLED_IPE (-4104) +/** Unexpected MSR in the auto-load/store area. */ +#define VERR_HM_UNEXPECTED_LD_ST_MSR (-4105) +/** No 32-bit to 64-bit switcher in place. */ +#define VERR_HM_NO_32_TO_64_SWITCHER (-4106) +/** HMR0Leave was called on the wrong CPU. */ +#define VERR_HM_WRONG_CPU (-4107) +/** Internal processing error \#1 in the HM code. */ +#define VERR_HM_IPE_1 (-4108) +/** Internal processing error \#2 in the HM code. */ +#define VERR_HM_IPE_2 (-4109) +/** Wrong 32/64-bit switcher. */ +#define VERR_HM_WRONG_SWITCHER (-4110) +/** Unknown I/O instruction. */ +#define VERR_HM_UNKNOWN_IO_INSTRUCTION (-4111) +/** Unsupported CPU feature combination. */ +#define VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO (-4112) +/** Internal processing error \#3 in the HM code. */ +#define VERR_HM_IPE_3 (-4113) +/** Internal processing error \#4 in the HM code. */ +#define VERR_HM_IPE_4 (-4114) +/** Internal processing error \#5 in the HM code. */ +#define VERR_HM_IPE_5 (-4115) +/** Invalid HM64ON32OP value. */ +#define VERR_HM_INVALID_HM64ON32OP (-4116) +/** Resume guest execution after injecting a double-fault. */ +#define VINF_HM_DOUBLE_FAULT 4117 +/** Pending exception; continue guest execution. */ +#define VINF_HM_PENDING_XCPT 4118 +/** @} */ + + +/** @name VBox Disassembler Status Codes + * @{ + */ +/** Invalid opcode byte(s) */ +#define VERR_DIS_INVALID_OPCODE (-4200) +/** Generic failure during disassembly. */ +#define VERR_DIS_GEN_FAILURE (-4201) +/** No read callback. */ +#define VERR_DIS_NO_READ_CALLBACK (-4202) +/** Invalid Mod/RM. */ +#define VERR_DIS_INVALID_MODRM (-4203) +/** Invalid parameter index. */ +#define VERR_DIS_INVALID_PARAMETER (-4204) +/** The instruction is too long. */ +#define VERR_DIS_TOO_LONG_INSTR (-4206) +/** @} */ + + +/** @name VBox Webservice Status Codes + * @{ + */ +/** Authentication failed (ISessionManager::logon()) */ +#define VERR_WEB_NOT_AUTHENTICATED (-4300) +/** Invalid format of managed object reference */ +#define VERR_WEB_INVALID_MANAGED_OBJECT_REFERENCE (-4301) +/** Invalid session ID in managed object reference */ +#define VERR_WEB_INVALID_SESSION_ID (-4302) +/** Invalid object ID in managed object reference */ +#define VERR_WEB_INVALID_OBJECT_ID (-4303) +/** Unsupported interface for managed object reference */ +#define VERR_WEB_UNSUPPORTED_INTERFACE (-4304) +/** @} */ + + +/** @name VBox PARAV Status Codes + * @{ + */ +/** Switch back to host */ +#define VINF_PARAV_SWITCH_TO_HOST 4400 + +/** @} */ + +/** @name VBox Video HW Acceleration command status + * @{ + */ +/** command processing is pending, a completion handler will be called */ +#define VINF_VHWA_CMD_PENDING 4500 + +/** @} */ + + +/** @name VBox COM error codes + * + * @remarks Global::vboxStatusCodeToCOM and Global::vboxStatusCodeFromCOM uses + * these for conversion that is lossless with respect to important COM + * status codes. These methods should be moved to the glue library. + * @{ */ +/** Unexpected turn of events. */ +#define VERR_COM_UNEXPECTED (-4600) +/** The base of the VirtualBox COM status codes (the lower value) + * corresponding 1:1 to VBOX_E_XXX. This is the lowest value. */ +#define VERR_COM_VBOX_LOWEST (-4699) +/** Object corresponding to the supplied arguments does not exist. */ +#define VERR_COM_OBJECT_NOT_FOUND (VERR_COM_VBOX_LOWEST + 1) +/** Current virtual machine state prevents the operation. */ +#define VERR_COM_INVALID_VM_STATE (VERR_COM_VBOX_LOWEST + 2) +/** Virtual machine error occurred attempting the operation. */ +#define VERR_COM_VM_ERROR (VERR_COM_VBOX_LOWEST + 3) +/** File not accessible or erroneous file contents. */ +#define VERR_COM_FILE_ERROR (VERR_COM_VBOX_LOWEST + 4) +/** IPRT error. */ +#define VERR_COM_IPRT_ERROR (VERR_COM_VBOX_LOWEST + 5) +/** Pluggable Device Manager error. */ +#define VERR_COM_PDM_ERROR (VERR_COM_VBOX_LOWEST + 6) +/** Current object state prohibits operation. */ +#define VERR_COM_INVALID_OBJECT_STATE (VERR_COM_VBOX_LOWEST + 7) +/** Host operating system related error. */ +#define VERR_COM_HOST_ERROR (VERR_COM_VBOX_LOWEST + 8) +/** Requested operation is not supported. */ +#define VERR_COM_NOT_SUPPORTED (VERR_COM_VBOX_LOWEST + 9) +/** Invalid XML found. */ +#define VERR_COM_XML_ERROR (VERR_COM_VBOX_LOWEST + 10) +/** Current session state prohibits operation. */ +#define VERR_COM_INVALID_SESSION_STATE (VERR_COM_VBOX_LOWEST + 11) +/** Object being in use prohibits operation. */ +#define VERR_COM_OBJECT_IN_USE (VERR_COM_VBOX_LOWEST + 12) +/** Returned by callback methods which does not need to be called + * again because the client does not actually make use of them. */ +#define VERR_COM_DONT_CALL_AGAIN (VERR_COM_VBOX_LOWEST + 13) +/** @} */ + +/** @name VBox VMMDev Status codes + * @{ + */ +/** CPU hotplug events from VMMDev are not monitored by the guest. */ +#define VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST (-4700) +/** @} */ + +/** @name VBox async I/O manager Status Codes + * @{ + */ +/** Async I/O task is pending, a completion handler will be called. */ +#define VINF_AIO_TASK_PENDING 4800 +/** @} */ + +/** @name VBox Virtual SCSI Status Codes + * @{ + */ +/** LUN type is not supported. */ +#define VERR_VSCSI_LUN_TYPE_NOT_SUPPORTED (-4900) +/** LUN is already/still attached to a device. */ +#define VERR_VSCSI_LUN_ATTACHED_TO_DEVICE (-4901) +/** The specified LUN is invalid. */ +#define VERR_VSCSI_LUN_INVALID (-4902) +/** The LUN is not attached to the device. */ +#define VERR_VSCSI_LUN_NOT_ATTACHED (-4903) +/** The LUN is still busy. */ +#define VERR_VSCSI_LUN_BUSY (-4904) +/** @} */ + +/** @name VBox FAM Status Codes + * @{ + */ +/** FAM failed to open a connection. */ +#define VERR_FAM_OPEN_FAILED (-5000) +/** FAM failed to add a file to the list to be monitored. */ +#define VERR_FAM_MONITOR_FILE_FAILED (-5001) +/** FAM failed to add a directory to the list to be monitored. */ +#define VERR_FAM_MONITOR_DIRECTORY_FAILED (-5002) +/** The connection to the FAM daemon was lost. */ +#define VERR_FAM_CONNECTION_LOST (-5003) +/** @} */ + + +/** @name PCI Bus & Passthrough Status Codes + * @{ + */ +/** RamPreAlloc not set. + * RAM pre-allocation is currently a requirement for PCI passthrough. */ +#define VERR_PCI_PASSTHROUGH_NO_RAM_PREALLOC (-5100) +/** VT-x/AMD-V not active. + * PCI passthrough currently works only if VT-x/AMD-V is active. */ +#define VERR_PCI_PASSTHROUGH_NO_HM (-5101) +/** Nested paging not active. + * PCI passthrough currently works only if nested paging is active. */ +#define VERR_PCI_PASSTHROUGH_NO_NESTED_PAGING (-5102) + +/** Special return code from a PCI I/O region mapping handler that tells the BUS + * that it has done the mapping already. */ +#define VINF_PCI_MAPPING_DONE 5150 +/** @} */ + + +/** @name GVMM Status Codes + * @{ + */ +/** Internal error obtaining the GVMM instance. */ +#define VERR_GVMM_INSTANCE (-5200) +/** GVMM does not support the range of CPUs present/possible on the host. */ +#define VERR_GVMM_HOST_CPU_RANGE (-5201) +/** GVMM ran into some broken IPRT code. */ +#define VERR_GVMM_BROKEN_IPRT (-5202) +/** Internal processing error \#1 in the GVMM code. */ +#define VERR_GVMM_IPE_1 (-5203) +/** Internal processing error \#2 in the GVMM code. */ +#define VERR_GVMM_IPE_2 (-5204) +/** Cannot destroy VM because not all other EMTs have deregistered. */ +#define VERR_GVMM_NOT_ALL_EMTS_DEREGISTERED (-5205) +/** @} */ + + +/** @name IEM Status Codes + * @{ */ +/** The instruction is not yet implemented by IEM. */ +#define VERR_IEM_INSTR_NOT_IMPLEMENTED (-5300) +/** Invalid operand size passed to an IEM function. */ +#define VERR_IEM_INVALID_OPERAND_SIZE (-5301) +/** Invalid address mode passed to an IEM function. */ +#define VERR_IEM_INVALID_ADDRESS_MODE (-5302) +/** Invalid effective segment register number passed to an IEM function. */ +#define VERR_IEM_INVALID_EFF_SEG (-5303) +/** Invalid instruction length passed to an IEM function. */ +#define VERR_IEM_INVALID_INSTR_LENGTH (-5304) +/** Internal status code for indicating that a selector isn't valid (LAR, LSL, + * VERR, VERW). This is not used outside the instruction implementations. */ +#define VINF_IEM_SELECTOR_NOT_OK (5305) +/** Restart the current instruction. For testing only. */ +#define VERR_IEM_RESTART_INSTRUCTION (-5389) +/** This particular aspect of the instruction is not yet implemented by IEM. */ +#define VERR_IEM_ASPECT_NOT_IMPLEMENTED (-5390) +/** Internal processing error \#1 in the IEM code. */ +#define VERR_IEM_IPE_1 (-5391) +/** Internal processing error \#2 in the IEM code. */ +#define VERR_IEM_IPE_2 (-5392) +/** Internal processing error \#3 in the IEM code. */ +#define VERR_IEM_IPE_3 (-5393) +/** Internal processing error \#4 in the IEM code. */ +#define VERR_IEM_IPE_4 (-5394) +/** Internal processing error \#5 in the IEM code. */ +#define VERR_IEM_IPE_5 (-5395) +/** Internal processing error \#6 in the IEM code. */ +#define VERR_IEM_IPE_6 (-5396) +/** Internal processing error \#7 in the IEM code. */ +#define VERR_IEM_IPE_7 (-5397) +/** Internal processing error \#8 in the IEM code. */ +#define VERR_IEM_IPE_8 (-5398) +/** Internal processing error \#9 in the IEM code. */ +#define VERR_IEM_IPE_9 (-5399) +/** @} */ + + +/** @name DBGC Status Codes + * @{ */ +/** Status that causes DBGC to quit. */ +#define VERR_DBGC_QUIT (-5400) +/** Async command pending. */ +#define VWRN_DBGC_CMD_PENDING 5401 +/** The command has already been registered. */ +#define VWRN_DBGC_ALREADY_REGISTERED 5402 +/** The command cannot be deregistered because has not been registered. */ +#define VERR_DBGC_COMMANDS_NOT_REGISTERED (-5403) +/** Unknown breakpoint. */ +#define VERR_DBGC_BP_NOT_FOUND (-5404) +/** The breakpoint already exists. */ +#define VERR_DBGC_BP_EXISTS (-5405) +/** The breakpoint has no command. */ +#define VINF_DBGC_BP_NO_COMMAND 5406 +/** Generic debugger command failure. */ +#define VERR_DBGC_COMMAND_FAILED (-5407) +/** Logic bug in the DBGC code. */ +#define VERR_DBGC_IPE (-5408) + +/** The lowest parse status code. */ +#define VERR_DBGC_PARSE_LOWEST (-5499) +/** Syntax error - too few arguments. */ +#define VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS (VERR_DBGC_PARSE_LOWEST + 0) +/** Syntax error - too many arguments. */ +#define VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS (VERR_DBGC_PARSE_LOWEST + 1) +/** Syntax error - too many arguments for static storage. */ +#define VERR_DBGC_PARSE_ARGUMENT_OVERFLOW (VERR_DBGC_PARSE_LOWEST + 2) +/** Syntax error - expected binary operator. */ +#define VERR_DBGC_PARSE_EXPECTED_BINARY_OP (VERR_DBGC_PARSE_LOWEST + 3) + +/** Syntax error - the argument does not allow a range to be specified. */ +#define VERR_DBGC_PARSE_NO_RANGE_ALLOWED (VERR_DBGC_PARSE_LOWEST + 5) +/** Syntax error - unbalanced quotes. */ +#define VERR_DBGC_PARSE_UNBALANCED_QUOTE (VERR_DBGC_PARSE_LOWEST + 6) +/** Syntax error - unbalanced parenthesis. */ +#define VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS (VERR_DBGC_PARSE_LOWEST + 7) +/** Syntax error - an argument or subargument contains nothing useful. */ +#define VERR_DBGC_PARSE_EMPTY_ARGUMENT (VERR_DBGC_PARSE_LOWEST + 8) +/** Syntax error - invalid operator usage. */ +#define VERR_DBGC_PARSE_UNEXPECTED_OPERATOR (VERR_DBGC_PARSE_LOWEST + 9) +/** Syntax error - invalid numeric value. */ +#define VERR_DBGC_PARSE_INVALID_NUMBER (VERR_DBGC_PARSE_LOWEST + 10) +/** Syntax error - numeric overflow. */ +#define VERR_DBGC_PARSE_NUMBER_TOO_BIG (VERR_DBGC_PARSE_LOWEST + 11) +/** Syntax error - invalid operation attempted. */ +#define VERR_DBGC_PARSE_INVALID_OPERATION (VERR_DBGC_PARSE_LOWEST + 12) +/** Syntax error - function not found. */ +#define VERR_DBGC_PARSE_FUNCTION_NOT_FOUND (VERR_DBGC_PARSE_LOWEST + 13) +/** Syntax error - the specified function is not a function. */ +#define VERR_DBGC_PARSE_NOT_A_FUNCTION (VERR_DBGC_PARSE_LOWEST + 14) +/** Syntax error - out of scratch memory. */ +#define VERR_DBGC_PARSE_NO_SCRATCH (VERR_DBGC_PARSE_LOWEST + 15) +/** Syntax error - out of regular heap memory. */ +#define VERR_DBGC_PARSE_NO_MEMORY (VERR_DBGC_PARSE_LOWEST + 16) +/** Syntax error - incorrect argument type. */ +#define VERR_DBGC_PARSE_INCORRECT_ARG_TYPE (VERR_DBGC_PARSE_LOWEST + 17) +/** Syntax error - an undefined variable was referenced. */ +#define VERR_DBGC_PARSE_VARIABLE_NOT_FOUND (VERR_DBGC_PARSE_LOWEST + 18) +/** Syntax error - a type conversion failed. */ +#define VERR_DBGC_PARSE_CONVERSION_FAILED (VERR_DBGC_PARSE_LOWEST + 19) +/** Syntax error - you hit a debugger feature which isn't implemented yet. + * (Feel free to help implement it.) */ +#define VERR_DBGC_PARSE_NOT_IMPLEMENTED (VERR_DBGC_PARSE_LOWEST + 20) +/** Syntax error - Couldn't satisfy a request for a specific result type. */ +#define VERR_DBGC_PARSE_BAD_RESULT_TYPE (VERR_DBGC_PARSE_LOWEST + 21) +/** Syntax error - Cannot read symbol value, it is a set-only symbol. */ +#define VERR_DBGC_PARSE_WRITEONLY_SYMBOL (VERR_DBGC_PARSE_LOWEST + 22) +/** Syntax error - Invalid command name. */ +#define VERR_DBGC_PARSE_INVALD_COMMAND_NAME (VERR_DBGC_PARSE_LOWEST + 23) +/** Syntax error - Command not found. */ +#define VERR_DBGC_PARSE_COMMAND_NOT_FOUND (VERR_DBGC_PARSE_LOWEST + 24) +/** Syntax error - buggy parser. */ +#define VERR_DBGC_PARSE_BUG (VERR_DBGC_PARSE_LOWEST + 25) +/** @} */ + + +/** @name Support driver/library shared verification status codes. + * @{ */ +/** Process Verification Failure: The memory content does not match the image + * file. */ +#define VERR_SUP_VP_MEMORY_VS_FILE_MISMATCH (-5600) +/** Process Verification Failure: The memory protection of a image file section + * does not match what the section header prescribes. */ +#define VERR_SUP_VP_SECTION_PROTECTION_MISMATCH (-5601) +/** Process Verification Failure: One of the section in the image file is not + * mapped into memory. */ +#define VERR_SUP_VP_SECTION_NOT_MAPPED (-5602) +/** Process Verification Failure: One of the section in the image file is not + * fully mapped into memory. */ +#define VERR_SUP_VP_SECTION_NOT_FULLY_MAPPED (-5603) +/** Process Verification Failure: Bad file alignment value in image header. */ +#define VERR_SUP_VP_BAD_FILE_ALIGNMENT_VALUE (-5604) +/** Process Verification Failure: Bad image base in header. */ +#define VERR_SUP_VP_BAD_IMAGE_BASE (-5605) +/** Process Verification Failure: Bad image signature. */ +#define VERR_SUP_VP_BAD_IMAGE_SIGNATURE (-5606) +/** Process Verification Failure: Bad image size. */ +#define VERR_SUP_VP_BAD_IMAGE_SIZE (-5607) +/** Process Verification Failure: Bad new-header offset in the MZ header. */ +#define VERR_SUP_VP_BAD_MZ_OFFSET (-5608) +/** Process Verification Failure: Bad optional header field. */ +#define VERR_SUP_VP_BAD_OPTIONAL_HEADER (-5609) +/** Process Verification Failure: Bad section alignment value in image + * header. */ +#define VERR_SUP_VP_BAD_SECTION_ALIGNMENT_VALUE (-5610) +/** Process Verification Failure: Bad section raw data size. */ +#define VERR_SUP_VP_BAD_SECTION_FILE_SIZE (-5611) +/** Process Verification Failure: Bad virtual section address. */ +#define VERR_SUP_VP_BAD_SECTION_RVA (-5612) +/** Process Verification Failure: Bad virtual section size. */ +#define VERR_SUP_VP_BAD_SECTION_VIRTUAL_SIZE (-5613) +/** Process Verification Failure: Bad size of image header. */ +#define VERR_SUP_VP_BAD_SIZE_OF_HEADERS (-5614) +/** Process Verification Failure: The process is being debugged. */ +#define VERR_SUP_VP_DEBUGGED (-5615) +/** Process Verification Failure: A DLL was found more than once. */ +#define VERR_SUP_VP_DUPLICATE_DLL_MAPPING (-5616) +/** Process Verification Failure: Image section region is too large. */ +#define VERR_SUP_VP_EMPTY_REGION_TOO_LARGE (-5617) +/** Process Verification Failure: Executable file name and process image name + * does not match up. */ +#define VERR_SUP_VP_EXE_VS_PROC_NAME_MISMATCH (-5618) +/** Process Verification Failure: Found executable memory allocated in the + * process. There is only supposed be executable memory associated with + * image file mappings (DLLs & EXE). */ +#define VERR_SUP_VP_FOUND_EXEC_MEMORY (-5619) +/** Process Verification Failure: There is more than one known executable mapped + * into the process. */ +#define VERR_SUP_VP_FOUND_MORE_THAN_ONE_EXE_MAPPING (-5620) +/** Process Verification Failure: Error closing image file handle. */ +#define VERR_SUP_VP_IMAGE_FILE_CLOSE_ERROR (-5621) +/** Process Verification Failure: Error opening image file. */ +#define VERR_SUP_VP_IMAGE_FILE_OPEN_ERROR (-5622) +/** Process Verification Failure: Error reading image file header. */ +#define VERR_SUP_VP_IMAGE_HDR_READ_ERROR (-5623) +/** Process Verification Failure: Image mapping is bogus as the first region + * has different AllocationBase and BaseAddress values, indicating that a + * section was unmapped or otherwise tampered with. */ +#define VERR_SUP_VP_IMAGE_MAPPING_BASE_ERROR (-5624) +/** Process Verification Failure: Error reading process memory for comparing + * with disk data. */ +#define VERR_SUP_VP_MEMORY_READ_ERROR (-5625) +/** Process Verification Failure: Found no executable mapped into the process + * address space. */ +#define VERR_SUP_VP_NO_FOUND_NO_EXE_MAPPING (-5626) +/** Process Verification Failure: An image mapping failed to report a name. */ +#define VERR_SUP_VP_NO_IMAGE_MAPPING_NAME (-5627) +/** Process Verification Failure: No KERNE32.DLL mapping found. This is + * impossible. */ +#define VERR_SUP_VP_NO_KERNEL32_MAPPING (-5628) +/** Process Verification Failure: Error allocating memory. */ +#define VERR_SUP_VP_NO_MEMORY (-5629) +/** Process Verification Failure: Error allocating state memory or querying + * the system32 path. */ +#define VERR_SUP_VP_NO_MEMORY_STATE (-5630) +/** Process Verification Failure: No NTDLL.DLL mapping found. This is + * impossible. */ +#define VERR_SUP_VP_NO_NTDLL_MAPPING (-5631) +/** Process Verification Failure: A DLL residing outside System32 was found + * in the process. */ +#define VERR_SUP_VP_NON_SYSTEM32_DLL (-5632) +/** Process Verification Failure: An unknown and unwanted DLL was found loaded + * into the process. */ +#define VERR_SUP_VP_NOT_KNOWN_DLL_OR_EXE (-5633) +/** Process Verification Failure: The name of an image file changes between + * mapping regions. */ +#define VERR_SUP_VP_NT_MAPPING_NAME_CHANGED (-5634) +/** Process Verification Failure: Error querying process name. */ +#define VERR_SUP_VP_NT_QI_PROCESS_NM_ERROR (-5635) +/** Process Verification Failure: Error querying thread information. */ +#define VERR_SUP_VP_NT_QI_THREAD_ERROR (-5636) +/** Process Verification Failure: Error query virtual memory information. */ +#define VERR_SUP_VP_NT_QI_VIRTUAL_MEMORY_ERROR (-5637) +/** Process Verification Failure: Error query virtual memory mapping name. */ +#define VERR_SUP_VP_NT_QI_VIRTUAL_MEMORY_NM_ERROR (-5638) +/** Process Verification Failure: Error determining the full path of + * System32. */ +#define VERR_SUP_VP_SYSTEM32_PATH (-5639) +/** Process Verification Failure: The process has more than one thread. */ +#define VERR_SUP_VP_THREAD_NOT_ALONE (-5640) +/** Process Verification Failure: The image mapping is too large (>= 2GB). */ +#define VERR_SUP_VP_TOO_HIGH_REGION_RVA (-5641) +/** Process Verification Failure: The memory region is too large (>= 2GB). */ +#define VERR_SUP_VP_TOO_LARGE_REGION (-5642) +/** Process Verification Failure: There are too many DLLs loaded. */ +#define VERR_SUP_VP_TOO_MANY_DLLS_LOADED (-5643) +/** Process Verification Failure: An image has too many regions. */ +#define VERR_SUP_VP_TOO_MANY_IMAGE_REGIONS (-5644) +/** Process Verification Failure: The process has too many virtual memory + * regions. */ +#define VERR_SUP_VP_TOO_MANY_MEMORY_REGIONS (-5645) +/** Process Verification Failure: An image has too many sections. */ +#define VERR_SUP_VP_TOO_MANY_SECTIONS (-5646) +/** Process Verification Failure: An image is targeting an unexpected + * machine/CPU. */ +#define VERR_SUP_VP_UNEXPECTED_IMAGE_MACHINE (-5647) +/** Process Verification Failure: Unexpected section protection flag + * combination. */ +#define VERR_SUP_VP_UNEXPECTED_SECTION_FLAGS (-5648) +/** Process Verification Failure: Expected the process and exe to have forced + * integrity checking enabled (verifying signatures). */ +#define VERR_SUP_VP_EXE_MISSING_FORCE_INTEGRITY (-5649) +/** Process Verification Failure: Expected the process and exe to have dynamic + * base enabled. */ +#define VERR_SUP_VP_EXE_MISSING_DYNAMIC_BASE (-5650) +/** Process Verification Failure: Expected the process and exe to advertise + * NX compatibility. */ +#define VERR_SUP_VP_EXE_MISSING_NX_COMPAT (-5651) +/** Process Verification Failure: The DllCharacteristics of the process + * does not match the value in the optional header in the exe file. */ +#define VERR_SUP_VP_DLL_CHARECTERISTICS_MISMATCH (-5652) +/** Process Verification Failure: The ImageCharacteristics of the process + * does not match the value in the file header in the exe file. */ +#define VERR_SUP_VP_IMAGE_CHARECTERISTICS_MISMATCH (-5653) +/** Process Verification Failure: Error querying image information. */ +#define VERR_SUP_VP_NT_QI_PROCESS_IMG_INFO_ERROR (-5654) +/** Process Verification Failure: Error querying debug port. */ +#define VERR_SUP_VP_NT_QI_PROCESS_DBG_PORT_ERROR (-5655) +/** WinVerifyTrust failed with an unexpected status code when using the + * catalog-file approach. */ +#define VERR_SUP_VP_WINTRUST_CAT_FAILURE (-5656) +/** The image is required to be signed with the same certificate as the rest + * of VirtualBox. */ +#define VERR_SUP_VP_NOT_SIGNED_WITH_BUILD_CERT (-5657) +/** Internal processing error: Not build certificate. */ +#define VERR_SUP_VP_NOT_BUILD_CERT_IPE (-5658) +/** The image requires to be signed using the kernel-code signing process. */ +#define VERR_SUP_VP_NOT_VALID_KERNEL_CODE_SIGNATURE (-5659) +/** Unexpected number of valid paths. */ +#define VERR_SUP_VP_UNEXPECTED_VALID_PATH_COUNT (-5660) +/** The image is required to force integrity checks. */ +#define VERR_SUP_VP_SIGNATURE_CHECKS_NOT_ENFORCED (-5661) +/** Process Verification Failure: Symantec Endpoint Protection must be + * disabled for the VirtualBox VM processes. + * http://www.symantec.com/connect/articles/creating-application-control-exclusions-symantec-endpoint-protection-121 */ +#define VERR_SUP_VP_SYSFER_DLL (-5662) +/** Process Purification Failure: KERNE32.DLL already mapped into the initial + * process (suspended). */ +#define VERR_SUP_VP_KERNEL32_ALREADY_MAPPED (-5663) +/** Process Purification Failure: NtFreeVirtualMemory failed on a chunk of + * executable memory which shouldn't be present in the process. */ +#define VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED (-5664) +/** Process Purification Failure: Both NtUnmapViewOfSetion and + * NtProtectVirtualMemory failed to get rid of or passify an non-image + * executable mapping. */ +#define VERR_SUP_VP_UNMAP_AND_PROTECT_FAILED (-5665) +/** Process Purification Failure: Unknown memory type of executable memory. */ +#define VERR_SUP_VP_UNKOWN_MEM_TYPE (-5666) +/** The image file is not owned by TrustedInstaller is it should be. */ +#define VERR_SUP_VP_NOT_OWNED_BY_TRUSTED_INSTALLER (-5667) +/** The image is outside the expected range. */ +#define VERR_SUP_VP_IMAGE_TOO_BIG (-5668) +/** Stub process not found so it cannot be revalidated when vboxdrv is opened + * by the VM process. */ +#define VERR_SUP_VP_STUB_NOT_FOUND (-5669) +/** Error opening the stub process for revalidation when vboxdrv is opened by + * the VM process. */ +#define VERR_SUP_VP_STUB_OPEN_ERROR (-5670) +/** Stub process thread not found during revalidation upon vboxdrv opening by + * the VM process. */ +#define VERR_SUP_VP_STUB_THREAD_NOT_FOUND (-5671) +/** Error opening the stub process thread for revalidation when vboxdrv is + * opened by the VM process. */ +#define VERR_SUP_VP_STUB_THREAD_OPEN_ERROR (-5672) +/** Process Purification Failure: NtAllocateVirtualMemory failed to get us + * suitable replacement memory for a chunk of executable memory that + * shouldn't be present in our process. (You will only see this message if you + * got potentially fatally buggy anti-virus software installed.) */ +#define VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED (-5673) +/** Error getting the file mode. */ +#define VERR_SUP_VP_FILE_MODE_ERROR (-5674) +/** Error creating an event semaphore for used with asynchronous reads. */ +#define VERR_SUP_VP_CREATE_READ_EVT_SEM_FAILED (-5675) +/** Undesirable module. */ +#define VERR_SUP_VP_UNDESIRABLE_MODULE (-5676) +/** NtQueryObject/Type failed. */ +#define VERR_SUP_VP_QUERY_HANDLE_TYPE (-5677) +/** NtSetInformationObject/NoInherit failed. */ +#define VERR_SUP_VP_SET_HANDLE_NOINHERIT (-5678) + +/** We are in driverless mode. */ +#define VERR_SUP_DRIVERLESS (-5699) +/** We are in driverless mode. */ +#define VINF_SUP_DRIVERLESS 5699 +/** @} */ + +/** @name VBox Extension Pack Status Codes + * @{ + */ +/** The host is not supported. Uninstall the extension pack. + * Returned by the VBOXEXTPACKREG::pfnInstalled. */ +#define VERR_EXTPACK_UNSUPPORTED_HOST_UNINSTALL (-6000) +/** The VirtualBox version is not supported by one of the extension packs. + * + * You have probably upgraded VirtualBox recently. Please upgrade the + * extension packs to versions compatible with this VirtualBox release. + */ +#define VERR_EXTPACK_VBOX_VERSION_MISMATCH (-6001) +/** @} */ + + +/** @name VBox Guest Control Status Codes + * @{ + */ +/** Guest side reported an error. */ +#define VERR_GSTCTL_GUEST_ERROR (-6200) +/** A guest control object has changed its overall status. */ +#define VWRN_GSTCTL_OBJECTSTATE_CHANGED 6220 +/** Guest process is in a wrong state. */ +#define VERR_GSTCTL_PROCESS_WRONG_STATE (-6221) +/** Maximum (context ID) sessions have been reached. */ +#define VERR_GSTCTL_MAX_CID_SESSIONS_REACHED (-6222) +/** Maximum (context ID) objects have been reached. */ +#define VERR_GSTCTL_MAX_CID_OBJECTS_REACHED (-6223) +/** Maximum (context ID object) count has been reached. */ +#define VERR_GSTCTL_MAX_CID_COUNT_REACHED (-6224) +/** Started guest process terminated with an exit code <> 0. */ +#define VERR_GSTCTL_PROCESS_EXIT_CODE (-6225) +/** @} */ + + +/** @name GIM Status Codes + * @{ + */ +/** No GIM provider is configured for this VM. */ +#define VERR_GIM_NOT_ENABLED (-6300) +/** GIM internal processing error \#1. */ +#define VERR_GIM_IPE_1 (-6301) +/** GIM internal processing error \#2. */ +#define VERR_GIM_IPE_2 (-6302) +/** GIM internal processing error \#3. */ +#define VERR_GIM_IPE_3 (-6303) +/** The GIM provider does not support any paravirtualized TSC. */ +#define VERR_GIM_PVTSC_NOT_AVAILABLE (-6304) +/** The guest has not setup use of the paravirtualized TSC. */ +#define VERR_GIM_PVTSC_NOT_ENABLED (-6305) +/** Unknown or invalid GIM provider. */ +#define VERR_GIM_INVALID_PROVIDER (-6306) +/** GIM generic operation failed. */ +#define VERR_GIM_OPERATION_FAILED (-6307) +/** The GIM provider does not support any hypercalls. */ +#define VERR_GIM_HYPERCALLS_NOT_AVAILABLE (-6308) +/** The guest has not setup use of the hypercalls. */ +#define VERR_GIM_HYPERCALLS_NOT_ENABLED (-6309) +/** The GIM device is not registered with GIM when it ought to be. */ +#define VERR_GIM_DEVICE_NOT_REGISTERED (-6310) +/** Hypercall cannot be enabled/performed due to access/permissions/CPL. */ +#define VERR_GIM_HYPERCALL_ACCESS_DENIED (-6311) +/** Failed to read to a memory region while performing a hypercall. */ +#define VERR_GIM_HYPERCALL_MEMORY_READ_FAILED (-6312) +/** Failed to write to a memory region while performing a hypercall. */ +#define VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED (-6313) +/** Generic hypercall operation failure. */ +#define VERR_GIM_HYPERCALL_FAILED (-6314) +/** No debug connection configured. */ +#define VERR_GIM_NO_DEBUG_CONNECTION (-6315) +/** Return to ring-3 to perform the hypercall there. */ +#define VINF_GIM_R3_HYPERCALL 6316 +/** Continuing hypercall at the same RIP, continue guest execution. */ +#define VINF_GIM_HYPERCALL_CONTINUING 6317 +/** Instruction that triggers the hypercall is invalid/unrecognized. */ +#define VERR_GIM_INVALID_HYPERCALL_INSTR (-6318) +/** @} */ + + +/** @name Main API Status Codes + * @{ + */ +/** The configuration constructor in main failed due to a COM error. Check + * the release log of the VM for further details. */ +#define VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR (-6400) +/** The configuration constructor in main failed due to an internal consistency + * error. Consult the release log of the VM for further details. */ +#define VERR_MAIN_CONFIG_CONSTRUCTOR_IPE (-6401) +/** @} */ + + +/** @name VBox Drag and Drop Status Codes + * @{ + */ +/** Guest side reported an error. */ +#define VERR_DND_GUEST_ERROR (-6500) +/** @} */ + + +/** @name Audio Status Codes + * @{ + */ +/** Host backend couldn't be initialized. Happen if the audio server is not + * reachable, audio hardware is not available or similar. We should use the + * NULL audio driver. */ +#define VERR_AUDIO_BACKEND_INIT_FAILED (-6600) +/** No host backend attached / available. */ +#define VERR_AUDIO_BACKEND_NOT_ATTACHED (-6601) +/** No free input streams. */ +#define VERR_AUDIO_NO_FREE_INPUT_STREAMS (-6602) +/** No free output streams. */ +#define VERR_AUDIO_NO_FREE_OUTPUT_STREAMS (-6603) +/** Pending stream disable operation in progress. */ +#define VERR_AUDIO_STREAM_PENDING_DISABLE (-6604) +/** There is more data available. + * This can happen due to a buffer wraparound of a buffer read/write operation. */ +#define VINF_AUDIO_MORE_DATA_AVAILABLE (6605) +/** Stream is not ready for requested operation. */ +#define VERR_AUDIO_STREAM_NOT_READY (-6605) +/** Stream could not be created. + * This might due to missing host (backend) drivers or a host not having the + * required hardware, or that the requested stream configuration + * is not supported by the host backend. */ +#define VERR_AUDIO_STREAM_COULD_NOT_CREATE (-6606) +/** Generic audio device enumeration error. */ +#define VERR_AUDIO_ENUMERATION_FAILED (-6607) +/** Asynchronous stream initialization still on-going. */ +#define VERR_AUDIO_STREAM_INIT_IN_PROGRESS (-6608) +/** Special PDMIHOSTAUDIO::pfnStreamCreate return value for triggering + * calling of PDMIHOSTAUDIO::pfnStreamInitAsync on a worker thread. */ +#define VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED (6609) +/** @} */ + + +/** @name APIC Status Codes + * @{ + */ +/** No pending interrupt. */ +#define VERR_APIC_INTR_NOT_PENDING (-6700) +/** Pending interrupt is masked by TPR. */ +#define VERR_APIC_INTR_MASKED_BY_TPR (-6701) +/** APIC did not accept the interrupt. */ +#define VERR_APIC_INTR_DISCARDED (-6702) +/** @} */ + +/** @name NEM Status Codes + * @{ + */ +/** NEM is not enabled. */ +#define VERR_NEM_NOT_ENABLED (-6800) +/** NEM is not available. */ +#define VERR_NEM_NOT_AVAILABLE (-6801) +/** NEM init failed. */ +#define VERR_NEM_INIT_FAILED (-6802) +/** NEM init failed because of missing kernel API (\#1). */ +#define VERR_NEM_MISSING_KERNEL_API_1 (-6803) +/** NEM can only operate from ring-3. */ +#define VERR_NEM_RING3_ONLY (-6804) +/** NEM failed to create a native VM instance. */ +#define VERR_NEM_VM_CREATE_FAILED (-6805) +/** NEM failed to map page(s) into the VM. */ +#define VERR_NEM_MAP_PAGES_FAILED (-6806) +/** NEM failed to unmap page(s) into the VM. */ +#define VERR_NEM_UNMAP_PAGES_FAILED (-6807) +/** NEM failed to get registers. */ +#define VERR_NEM_GET_REGISTERS_FAILED (-6808) +/** NEM failed to set registers. */ +#define VERR_NEM_SET_REGISTERS_FAILED (-6809) +/** Get register caller must flush the TLB (not an error). */ +#define VERR_NEM_FLUSH_TLB (-6810) +/** Get register caller must flush the TLB. */ +#define VINF_NEM_FLUSH_TLB (6810) +/** NEM failed to set TSC. */ +#define VERR_NEM_SET_TSC (-6811) +/** NEM init failed because of missing kernel API (\#2). */ +#define VERR_NEM_MISSING_KERNEL_API_2 (-6812) +/** NEM init failed because of missing kernel API (\#3). */ +#define VERR_NEM_MISSING_KERNEL_API_3 (-6813) +/** NEM init failed because of missing kernel API (\#4). */ +#define VERR_NEM_MISSING_KERNEL_API_4 (-6814) +/** NEM init failed because of missing kernel API (\#5). */ +#define VERR_NEM_MISSING_KERNEL_API_5 (-6815) +/** NEM failed to query dirty page bitmap. */ +#define VERR_NEM_QUERY_DIRTY_BITMAP_FAILED (-6816) +/** NEM is missing a require feature in the host API. */ +#define VERR_NEM_MISSING_FEATURE (-6817) + +/** NEM internal processing error \#0. */ +#define VERR_NEM_IPE_0 (-6890) +/** NEM internal processing error \#1. */ +#define VERR_NEM_IPE_1 (-6891) +/** NEM internal processing error \#2. */ +#define VERR_NEM_IPE_2 (-6892) +/** NEM internal processing error \#3. */ +#define VERR_NEM_IPE_3 (-6893) +/** NEM internal processing error \#4. */ +#define VERR_NEM_IPE_4 (-6894) +/** NEM internal processing error \#5. */ +#define VERR_NEM_IPE_5 (-6895) +/** NEM internal processing error \#6. */ +#define VERR_NEM_IPE_6 (-6896) +/** NEM internal processing error \#7. */ +#define VERR_NEM_IPE_7 (-6897) +/** NEM internal processing error \#8. */ +#define VERR_NEM_IPE_8 (-6898) +/** NEM internal processing error \#9. */ +#define VERR_NEM_IPE_9 (-6899) +/** @} */ + +/** @name Recording Status Codes + * @{ + */ +/** Codec was not found. */ +#define VERR_RECORDING_CODEC_NOT_FOUND (-6900) +/** Codec initialization failed. */ +#define VERR_RECORDING_CODEC_INIT_FAILED (-6902) +/** Codec is not supported. */ +#define VERR_RECORDING_CODEC_NOT_SUPPORTED (-6903) +/** Format not supported by the codec. */ +#define VERR_RECORDING_FORMAT_NOT_SUPPORTED (-6904) +/** Recording is not possible due to a set restriction. */ +#define VERR_RECORDING_RESTRICTED (-6905) +/** Recording limit (time, size, ...) has been reached. */ +#define VINF_RECORDING_LIMIT_REACHED (6906) +/** Recording limit (time, size, ...) has been reached. */ +#define VERR_RECORDING_LIMIT_REACHED (-6906) +/** Recording has been throttled due to current settings. + * This e.g. can happen when submitting more video frames than + * the current FPS setting allows. */ +#define VINF_RECORDING_THROTTLED (6907) +/** Recording has been throttled due to current settings. + * This e.g. can happen when submitting more video frames than + * the current FPS setting allows. */ +#define VERR_RECORDING_THROTTLED (-6907) +/** Encoding data failed. */ +#define VERR_RECORDING_ENCODING_FAILED (-6908) +/** @} */ + +/** @name Shared Clipboard Status Codes + * @{ + */ +/** Maximum of concurrent clipboard transfers has been reached. */ +#define VERR_SHCLPB_MAX_TRANSFERS_REACHED (-7100) +/** Maximum number of Shared Clipboard objects has been reached. */ +#define VERR_SHCLPB_MAX_OBJECTS_REACHED (-7101) +/** Maximum number of Shared Clipboard lists has been reached. */ +#define VERR_SHCLPB_MAX_LISTS_REACHED (-7102) +/** A Shared Clipboard list handle is invalid. */ +#define VERR_SHCLPB_LIST_HANDLE_INVALID (-7103) +/** A Shared Clipboard objects handle is invalid. */ +#define VERR_SHCLPB_OBJ_HANDLE_INVALID (-7104) +/** Shared Clipboard event ID not found. */ +#define VERR_SHCLPB_EVENT_ID_NOT_FOUND (-7105) +/** Maximum number of Shared Clipboard events for an event source has been reached. */ +#define VERR_SHCLPB_MAX_EVENTS_REACHED (-7106) +/** Shared Clipboard transfer ID not found. */ +#define VERR_SHCLPB_TRANSFER_ID_NOT_FOUND (-7150) +/** @} */ + +/** @name Virtual IOMMU Status Codes + * @{ + */ +/** Failed to read the device table entry from guest memory. */ +#define VERR_IOMMU_DTE_READ_FAILED (-7300) +/** Failed to read the device table entry due to an invalid offset. */ +#define VERR_IOMMU_DTE_BAD_OFFSET (-7301) +/** Address translation failed. */ +#define VERR_IOMMU_ADDR_TRANSLATION_FAILED (-7302) +/** Access denied for the address. */ +#define VERR_IOMMU_ADDR_ACCESS_DENIED (-7303) +/** Remapping failed for the interrupt. */ +#define VERR_IOMMU_INTR_REMAP_FAILED (-7304) +/** Remapping denied for the interrupt (might have caused a PCI target abort). */ +#define VERR_IOMMU_INTR_REMAP_DENIED (-7305) +/** Command not supported. */ +#define VERR_IOMMU_CMD_NOT_SUPPORTED (-7306) +/** Command format (or reserved bits) invalid. */ +#define VERR_IOMMU_CMD_INVALID_FORMAT (-7307) +/** Command hardware failure. */ +#define VERR_IOMMU_CMD_HW_ERROR (-7308) +/** IOMMU device is not present. */ +#define VERR_IOMMU_NOT_PRESENT (-7309) +/** IOMMU instance cannot call itself (for remapping interrupts or translating + * addresses). */ +#define VERR_IOMMU_CANNOT_CALL_SELF (-7310) +/** Address translation disabled (but permission bits apply). */ +#define VINF_IOMMU_ADDR_TRANSLATION_DISABLED 7311 + +/** IOMMU Internal processing error \#0. */ +#define VERR_IOMMU_IPE_0 (-7390) +/** IOMMU Internal processing error \#1. */ +#define VERR_IOMMU_IPE_1 (-7391) +/** IOMMU Internal processing error \#2. */ +#define VERR_IOMMU_IPE_2 (-7392) +/** IOMMU Internal processing error \#3. */ +#define VERR_IOMMU_IPE_3 (-7393) +/** IOMMU Internal processing error \#4. */ +#define VERR_IOMMU_IPE_4 (-7394) +/** IOMMU Internal processing error \#5. */ +#define VERR_IOMMU_IPE_5 (-7395) +/** IOMMU Internal processing error \#6. */ +#define VERR_IOMMU_IPE_6 (-7396) +/** IOMMU Internal processing error \#7. */ +#define VERR_IOMMU_IPE_7 (-7397) +/** IOMMU Internal processing error \#8. */ +#define VERR_IOMMU_IPE_8 (-7398) +/** IOMMU Internal processing error \#9. */ +#define VERR_IOMMU_IPE_9 (-7399) +/** @} */ + +/* SED-END */ + +/** @} */ + + +#endif /* !VBOX_INCLUDED_err_h */ + diff --git a/include/VBox/err.mac b/include/VBox/err.mac new file mode 100644 index 00000000..14f39cb1 --- /dev/null +++ b/include/VBox/err.mac @@ -0,0 +1,1230 @@ +;; @file +; VirtualBox Status Codes. +; +; Automatically generated by err.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%define VERR_NO_VM_MEMORY (-1000) +%define VERR_DONT_PANIC (-1001) +%define VERR_UNSUPPORTED_CPU (-1002) +%define VERR_UNSUPPORTED_CPU_MODE (-1003) +%define VERR_PAGE_NOT_PRESENT (-1004) +%define VERR_CFG_INVALID_FORMAT (-1005) +%define VERR_CFG_NO_VALUE (-1006) +%define VERR_SELECTOR_NOT_PRESENT (-1007) +%define VERR_NOT_CODE_SELECTOR (-1008) +%define VERR_NOT_DATA_SELECTOR (-1009) +%define VERR_OUT_OF_SELECTOR_BOUNDS (-1010) +%define VERR_INVALID_SELECTOR (-1011) +%define VERR_INVALID_RPL (-1012) +%define VERR_PAGE_MAP_LEVEL4_NOT_PRESENT (-1013) +%define VERR_PAGE_DIRECTORY_PTR_NOT_PRESENT (-1014) +%define VERR_RAW_MODE_INVALID_SMP (-1015) +%define VERR_INVALID_VM_HANDLE (-1016) +%define VERR_INVALID_VMCPU_HANDLE (-1017) +%define VERR_INVALID_CPU_ID (-1018) +%define VERR_TOO_MANY_CPUS (-1019) +%define VERR_SERVICE_DISABLED (-1020) +%define VERR_NOT_SUP_IN_RAW_MODE (-1021) +%define VERR_INVALID_CPU_INDEX (-1022) +%define VERR_RAW_MODE_NOT_SUPPORTED (-1023) +%define VERR_INCONSISTENT_VM_HANDLE (-1024) +%define VERR_VM_RESTORED (-1025) +%define VERR_NOT_SUP_BY_NEM (-1026) +%define VINF_EM_FIRST 1100 +%define VINF_EM_TERMINATE 1100 +%define VINF_EM_DBG_HYPER_STEPPED 1101 +%define VINF_EM_DBG_HYPER_BREAKPOINT 1102 +%define VINF_EM_DBG_HYPER_ASSERTION 1103 +%define VINF_EM_DBG_EVENT 1104 +%define VINF_EM_DBG_STOP 1105 +%define VINF_EM_DBG_STEPPED 1106 +%define VINF_EM_DBG_BREAKPOINT 1107 +%define VINF_EM_DBG_STEP 1108 +%define VINF_EM_OFF 1109 +%define VINF_EM_SUSPEND 1110 +%define VINF_EM_RESET 1111 +%define VINF_EM_HALT 1112 +%define VINF_EM_RESUME 1113 +%define VINF_EM_NO_MEMORY 1114 +%define VERR_EM_NO_MEMORY (-1114) +%define VINF_EM_RESCHEDULE_REM 1115 +%define VINF_EM_RESCHEDULE_HM 1116 +%define VINF_EM_RESCHEDULE_RAW 1117 +%define VINF_EM_RESCHEDULE 1118 +%define VINF_EM_RESCHEDULE_PARAV 1119 +%define VINF_EM_WAIT_SIPI 1120 +%define VINF_EM_LAST 1120 +%define VINF_EM_RAW_GUEST_TRAP 1121 +%define VINF_EM_RAW_INTERRUPT 1122 +%define VINF_EM_RAW_INTERRUPT_HYPER 1123 +%define VINF_EM_RAW_RING_SWITCH 1124 +%define VINF_EM_RAW_RING_SWITCH_INT 1125 +%define VINF_EM_RAW_EXCEPTION_PRIVILEGED 1126 +%define VINF_EM_RAW_EMULATE_INSTR 1127 +%define VINF_EM_RAW_EMULATE_INSTR_TSS_FAULT 1128 +%define VINF_EM_RAW_EMULATE_INSTR_LDT_FAULT 1129 +%define VINF_EM_RAW_EMULATE_INSTR_IDT_FAULT 1130 +%define VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT 1131 +%define VERR_EM_RAW_PATCH_CONFLICT (-1133) +%define VINF_EM_RAW_TO_R3 1135 +%define VINF_EM_RAW_TIMER_PENDING 1136 +%define VINF_EM_RAW_INTERRUPT_PENDING 1137 +%define VINF_EM_RAW_STALE_SELECTOR 1138 +%define VINF_EM_RAW_IRET_TRAP 1139 +%define VERR_EM_INTERPRETER (-1148) +%define VERR_EM_INTERNAL_ERROR (-1149) +%define VINF_EM_PENDING_REQUEST 1150 +%define VINF_EM_RAW_EMULATE_DBG_STEP 1151 +%define VINF_EM_HM_PATCH_TPR_INSTR 1152 +%define VERR_EM_UNEXPECTED_MAPPING_CONFLICT (-1154) +%define VINF_EM_TRIPLE_FAULT 1155 +%define VERR_EM_CANNOT_EXEC_GUEST (-1156) +%define VINF_EM_RAW_INJECT_TRPM_EVENT 1157 +%define VERR_EM_GUEST_CPU_HANG (-1158) +%define VINF_EM_PENDING_R3_IOPORT_READ 1159 +%define VINF_EM_PENDING_R3_IOPORT_WRITE 1160 +%define VINF_EM_RESUME_R3_HISTORY_EXEC 1161 +%define VINF_EM_EMULATE_SPLIT_LOCK 1162 +%define VERR_DBGF_NOT_ATTACHED (-1200) +%define VERR_DBGF_ALREADY_ATTACHED (-1201) +%define VWRN_DBGF_ALREADY_HALTED 1202 +%define VERR_DBGF_NO_MORE_BP_SLOTS (-1203) +%define VERR_DBGF_BP_NOT_FOUND (-1204) +%define VINF_DBGF_BP_ALREADY_ENABLED 1205 +%define VINF_DBGF_BP_ALREADY_DISABLED 1206 +%define VINF_DBGF_BP_ALREADY_EXIST 1207 +%define VERR_DBGF_MEM_NOT_FOUND (-1208) +%define VERR_DBGF_OS_NOT_DETCTED (-1209) +%define VINF_DBGF_OS_NOT_DETCTED 1209 +%define VERR_DBGF_REGISTER_NOT_FOUND (-1210) +%define VINF_DBGF_TRUNCATED_REGISTER 1211 +%define VINF_DBGF_ZERO_EXTENDED_REGISTER 1212 +%define VERR_DBGF_UNSUPPORTED_CAST (-1213) +%define VERR_DBGF_READ_ONLY_REGISTER (-1214) +%define VERR_DBGF_REG_IPE_1 (-1215) +%define VERR_DBGF_REG_IPE_2 (-1216) +%define VERR_DBGF_HYPER_DB_XCPT (-1217) +%define VERR_DBGF_STACK_IPE_1 (-1218) +%define VERR_DBGF_STACK_IPE_2 (-1219) +%define VERR_DBGF_NO_TRACE_BUFFER (-1220) +%define VERR_DBGF_TRACER_IPE_1 (-1221) +%define VWRN_DBGF_ALREADY_RUNNING (-1222) +%define VERR_DBGF_IPE_1 (-1223) +%define VINF_DBGF_BP_HALT (1224) +%define VERR_DBGF_OWNER_BUSY (-1225) +%define VERR_DBGF_BP_INT3_ADD_TRIES_REACHED (-1226) +%define VERR_DBGF_BP_IPE_1 (-1227) +%define VERR_DBGF_BP_IPE_2 (-1228) +%define VERR_DBGF_BP_IPE_3 (-1229) +%define VERR_DBGF_BP_IPE_4 (-1230) +%define VERR_DBGF_BP_IPE_5 (-1231) +%define VERR_DBGF_BP_IPE_6 (-1232) +%define VERR_DBGF_BP_IPE_7 (-1233) +%define VERR_DBGF_BP_IPE_8 (-1234) +%define VERR_DBGF_BP_IPE_9 (-1235) +%define VERR_DBGF_BP_L1_LOOKUP_FAILED (-1236) +%define VERR_DBGF_BP_L2_LOOKUP_FAILED (-1237) +%define VERR_DBGF_BP_OWNER_NO_MORE_HANDLES (-1238) +%define VINF_DBGF_R3_BP_OWNER_DEFER 1239 +%define VERR_DBGF_BP_OWNER_CALLBACK_WRONG_STATUS (-1240) +%define VERR_DBGF_CANCELLED (-1241) +%define VWRN_CONTINUE_ANALYSIS 1400 +%define VWRN_CONTINUE_RECOMPILE VWRN_CONTINUE_ANALYSIS +%define VWRN_PATM_CONTINUE_SEARCH VWRN_CONTINUE_ANALYSIS +%define VERR_PATCHING_REFUSED (-1401) +%define VERR_PATCH_NOT_FOUND (-1402) +%define VERR_PATCH_DISABLED (-1403) +%define VWRN_PATCH_ENABLED 1404 +%define VERR_PATCH_ALREADY_DISABLED (-1405) +%define VERR_PATCH_ALREADY_ENABLED (-1406) +%define VWRN_PATCH_REMOVED 1407 +%define VINF_PATM_PATCH_TRAP_GP 1408 +%define VINF_PATM_LEAVE_RC_FIRST VINF_PATM_PATCH_TRAP_GP +%define VINF_PATM_PATCH_TRAP_PF 1409 +%define VINF_PATM_PATCH_INT3 1410 +%define VINF_PATM_CHECK_PATCH_PAGE 1411 +%define VINF_PATM_DUPLICATE_FUNCTION 1412 +%define VINF_PATCH_EMULATE_INSTR 1413 +%define VINF_PATM_HC_MMIO_PATCH_WRITE 1414 +%define VINF_PATM_HC_MMIO_PATCH_READ 1415 +%define VINF_PATM_PENDING_IRQ_AFTER_IRET 1416 +%define VINF_PATM_LEAVE_RC_LAST VINF_PATM_PENDING_IRQ_AFTER_IRET +%define VERR_PATCH_NO_CONFLICT (-1425) +%define VERR_PATM_UNSAFE_CODE (-1426) +%define VWRN_PATCH_END_BRANCH 1427 +%define VERR_PATM_ALREADY_PATCHED (-1428) +%define VINF_PATM_SPINLOCK_FAILED (1429) +%define VINF_PATCH_CONTINUE (1430) +%define VERR_PATM_HM_IPE (-1431) +%define VERR_PATM_IPE_TRAP_IN_PATCH_CODE (-1432) +%define VWRN_CSAM_TRAP_NOT_HANDLED 1500 +%define VWRN_CSAM_INSTRUCTION_PATCHED 1501 +%define VWRN_CSAM_PAGE_NOT_FOUND 1502 +%define VINF_CSAM_PENDING_ACTION 1503 +%define VERR_CSAM_HM_IPE (-1504) +%define VERR_PGM_MAPPING_CONFLICT (-1600) +%define VERR_PGM_HANDLER_PHYSICAL_NO_RAM_RANGE (-1601) +%define VERR_PGM_HANDLER_VIRTUAL_CONFLICT (-1602) +%define VERR_PGM_HANDLER_PHYSICAL_CONFLICT (-1603) +%define VERR_PGM_INVALID_PAGE_DIRECTORY (-1604) +%define VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS (-1605) +%define VERR_PGM_INVALID_GC_PHYSICAL_RANGE (-1606) +%define VERR_PGM_HANDLER_NOT_FOUND (-1607) +%define VERR_PGM_RAM_CONFLICT (-1608) +%define VERR_PGM_MAPPINGS_FIXED (-1609) +%define VERR_PGM_MAPPINGS_FIX_CONFLICT (-1610) +%define VERR_PGM_MAPPINGS_FIX_REJECTED (-1611) +%define VERR_PGM_MAPPINGS_FIX_TOO_SMALL (-1612) +%define VINF_PGM_SYNC_CR3 1613 +%define VINF_PGM_NO_DIRTY_BIT_TRACKING 1614 +%define VINF_PGM_HANDLED_DIRTY_BIT_FAULT 1615 +%define VINF_PGM_HANDLER_DO_DEFAULT 1616 +%define VERR_PGM_UNSUPPORTED_HOST_PAGING_MODE (-1617) +%define VERR_PGM_PHYS_PAGE_RESERVED (-1618) +%define VERR_PGM_NO_HYPERVISOR_ADDRESS (-1619) +%define VINF_PGM_CACHED_PAGE 1622 +%define VINF_PGM_GCPHYS_ALIASED 1623 +%define VINF_PGM_SYNCPAGE_MODIFIED_PDE 1625 +%define VERR_PGM_GCPHYS_RANGE_CROSSES_BOUNDARY (-1626) +%define VERR_PGM_INTERMEDIATE_PAGING_CONFLICT (-1627) +%define VERR_PGM_UNSUPPORTED_SHADOW_PAGING_MODE (-1628) +%define VERR_PGM_DYNMAP_FAILED (-1629) +%define VERR_PGM_DYNMAP_FULL_SET (-1630) +%define VERR_PGM_DYNMAP_SETUP_ERROR (-1631) +%define VERR_PGM_DYNMAP_EXPAND_ERROR (-1632) +%define VERR_PGM_PHYS_TLB_UNASSIGNED (-1633) +%define VERR_PGM_PHYS_TLB_CATCH_ALL (-1634) +%define VINF_PGM_PHYS_TLB_CATCH_WRITE 1635 +%define VERR_PGM_PHYS_TLB_CATCH_WRITE (-1635) +%define VERR_PGM_NO_CR3_SHADOW_ROOT (-1636) +%define VERR_PGM_PHYS_INVALID_PAGE_ID (-1637) +%define VERR_PGM_PHYS_WR_HIT_HANDLER (-1638) +%define VERR_PGM_PHYS_NOT_RAM (-1639) +%define VERR_PGM_PHYS_NOT_ROM (-1640) +%define VERR_PGM_PHYS_NOT_MMIO (-1641) +%define VERR_PGM_PHYS_NOT_MMIO2 (-1642) +%define VERR_PGM_HANDLER_ALREADY_ALIASED (-1643) +%define VINF_PGM_HANDLER_ALREADY_ALIASED (1643) +%define VINF_PGM_POOL_FLUSH_PENDING (1644) +%define VERR_PGM_INVALID_LARGE_PAGE_RANGE (-1645) +%define VERR_PGM_PHYS_PAGE_BALLOONED (-1646) +%define VERR_PGM_HANDLER_IPE_1 (-1647) +%define VERR_PGM_MAP_MMIO2_ALIAS_MMIO (-1651) +%define VERR_PGM_MAPPINGS_DISABLED (-1652) +%define VERR_PGM_MAPPINGS_SMP (-1653) +%define VERR_PGM_INVALID_SAVED_PAGE_STATE (-1654) +%define VERR_PGM_LOAD_UNEXPECTED_PAGE_TYPE (-1655) +%define VERR_PGM_UNEXPECTED_PAGE_STATE (-1656) +%define VERR_PGM_SAVED_MMIO2_RANGE_NOT_FOUND (-1657) +%define VERR_PGM_SAVED_MMIO2_PAGE_NOT_FOUND (-1658) +%define VERR_PGM_SAVED_ROM_RANGE_NOT_FOUND (-1659) +%define VERR_PGM_SAVED_ROM_PAGE_NOT_FOUND (-1660) +%define VERR_PGM_SAVED_ROM_PAGE_PROT (-1661) +%define VERR_PGM_SAVED_REC_TYPE (-1662) +%define VERR_PGM_DYNMAP_IPE (-1663) +%define VERR_PGM_HANDY_PAGE_IPE (-1664) +%define VERR_PGM_PML4_MAPPING (-1665) +%define VERR_PGM_POOL_GET_PAGE_FAILED (-1666) +%define VERR_PGM_NOT_USED_IN_MODE (-1667) +%define VERR_PGM_INVALID_CR3_ADDR (-1668) +%define VERR_PGM_INVALID_PDPE_ADDR (-1669) +%define VERR_PGM_PHYS_HANDLER_IPE (-1670) +%define VERR_PGM_PHYS_PAGE_MAP_IPE_1 (-1671) +%define VERR_PGM_PHYS_PAGE_MAP_IPE_2 (-1672) +%define VERR_PGM_PHYS_PAGE_MAP_IPE_3 (-1673) +%define VERR_PGM_PHYS_PAGE_MAP_IPE_4 (-1674) +%define VERR_PGM_POOL_TOO_MANY_LOOPS (-1675) +%define VERR_PGM_MAPPING_IPE (-1676) +%define VERR_PGM_POOL_MAXED_OUT_ALREADY (-1677) +%define VERR_PGM_POOL_IPE (-1678) +%define VERR_PGM_WRITE_MONITOR_ENGAGED (-1679) +%define VERR_PGM_PHYS_PAGE_GET_IPE (-1680) +%define VERR_PGM_PHYS_NULL_PAGE_PARAM (-1681) +%define VERR_PGM_PCI_PASSTHRU_MISCONFIG (-1682) +%define VERR_PGM_TOO_MANY_MMIO2_RANGES (-1683) +%define VERR_PGM_PHYS_PAGE_MAP_MMIO2_IPE (-1684) +%define VERR_PGM_PHYS_MMIO_EX_IPE (-1685) +%define VERR_PGM_MODE_IPE (-1686) +%define VERR_PGM_SHW_NONE_IPE (-1687) +%define VERR_PGM_PAE_PDPE_RSVD (-1688) +%define VERR_PGM_NOT_SUPPORTED_FOR_NEM_MODE (-1689) +%define VERR_MM_RAM_CONFLICT (-1700) +%define VERR_MM_HYPER_NO_MEMORY (-1701) +%define VERR_MM_BAD_TRAP_TYPE_IPE (-1702) +%define VERR_CPUM_RAISE_GP_0 (-1750) +%define VERR_CPUM_INCOMPATIBLE_CONFIG (-1751) +%define VERR_CPUM_HIDDEN_CS_LOAD_ERROR (-1752) +%define VERR_CPUM_TOO_MANY_CPUID_SUBLEAVES (-1753) +%define VERR_CPUM_IPE_1 (-1754) +%define VERR_CPUM_IPE_2 (-1755) +%define VERR_CPUM_DB_CPU_NOT_FOUND (-1756) +%define VERR_CPUM_MSR_BAD_CPUMCPU_OFFSET (-1757) +%define VINF_CPUM_R3_MSR_READ (1758) +%define VINF_CPUM_R3_MSR_WRITE (1759) +%define VERR_TOO_MANY_CPUID_LEAVES (-1760) +%define VERR_CPUM_INVALID_CONFIG_VALUE (-1761) +%define VERR_CPUM_INCOMPATIBLE_XSAVE_COMP_MASK (-1762) +%define VERR_CPUM_INVALID_XSAVE_COMP_MASK (-1763) +%define VERR_CPUM_INVALID_XSAVE_HDR (-1764) +%define VERR_CPUM_INVALID_XCR0 (-1765) +%define VINF_CPUM_HOST_CR0_MODIFIED (1766) +%define VERR_CPUM_INVALID_HWVIRT_CONFIG (-1767) +%define VERR_CPUM_INVALID_HWVIRT_FEAT_COMBO (-1768) +%define VERR_SSM_UNIT_EXISTS (-1800) +%define VERR_SSM_UNIT_NOT_FOUND (-1801) +%define VERR_SSM_UNIT_NOT_OWNER (-1802) +%define VERR_SSM_INTEGRITY (-1810) +%define VERR_SSM_INTEGRITY_MAGIC (-1811) +%define VERR_SSM_INTEGRITY_VERSION (-1812) +%define VERR_SSM_INTEGRITY_SIZE (-1813) +%define VERR_SSM_INTEGRITY_CRC (-1814) +%define VERR_SMM_INTEGRITY_MACHINE (-1815) +%define VERR_SSM_INTEGRITY_HEADER (-1816) +%define VERR_SSM_INTEGRITY_UNIT (-1817) +%define VERR_SSM_INTEGRITY_UNIT_MAGIC (-1818) +%define VERR_SSM_INTEGRITY_UNIT_NOT_FOUND (-1819) +%define VERR_SSM_INTEGRITY_VBOX_VERSION (-1820) +%define VERR_SSM_INTEGRITY_FOOTER (-1821) +%define VERR_SSM_INTEGRITY_REC_HDR (-1822) +%define VERR_SSM_INTEGRITY_REC_TERM (-1823) +%define VERR_SSM_INTEGRITY_REC_TERM_CRC (-1824) +%define VERR_SSM_INTEGRITY_DECOMPRESSION (-1825) +%define VERR_SSM_INTEGRITY_DIR (-1826) +%define VERR_SSM_INTEGRITY_DIR_MAGIC (-1827) +%define VERR_SSM_NO_LOAD_EXEC (-1830) +%define VERR_SSM_LOADED_TOO_MUCH (-1831) +%define VERR_SSM_INVALID_STATE (-1832) +%define VERR_SSM_LOADED_TOO_LITTLE (-1833) +%define VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION (-1840) +%define VERR_SSM_DATA_UNIT_FORMAT_CHANGED (-1841) +%define VERR_SSM_LOAD_CPUID_MISMATCH (-1842) +%define VERR_SSM_LOAD_MEMORY_SIZE_MISMATCH (-1843) +%define VERR_SSM_LOAD_CONFIG_MISMATCH (-1844) +%define VERR_SSM_VIRTUAL_CLOCK_HZ (-1845) +%define VERR_SSM_IDE_ASYNC_TIMEOUT (-1846) +%define VERR_SSM_STRUCTURE_MAGIC (-1847) +%define VERR_SSM_UNEXPECTED_DATA (-1848) +%define VERR_SSM_GCPHYS_OVERFLOW (-1849) +%define VERR_SSM_GCPTR_OVERFLOW (-1850) +%define VINF_SSM_VOTE_FOR_ANOTHER_PASS 1851 +%define VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN 1852 +%define VERR_SSM_VOTE_FOR_GIVING_UP (-1853) +%define VINF_SSM_DONT_CALL_AGAIN 1854 +%define VERR_SSM_TOO_MANY_PASSES (-1855) +%define VERR_SSM_STATE_GREW_TOO_BIG (-1856) +%define VERR_SSM_LOW_ON_DISK_SPACE (-1857) +%define VERR_SSM_CANCELLED (-1858) +%define VERR_SSM_NO_PENDING_OPERATION (-1859) +%define VERR_SSM_ALREADY_CANCELLED (-1860) +%define VERR_SSM_LIVE_POWERED_OFF (-1861) +%define VERR_SSM_LIVE_GURU_MEDITATION (-1862) +%define VERR_SSM_LIVE_FATAL_ERROR (-1863) +%define VINF_SSM_LIVE_SUSPENDED 1864 +%define VERR_SSM_FIELD_COMPLEX (-1864) +%define VERR_SSM_FIELD_INVALID_SIZE (-1865) +%define VERR_SSM_FIELD_OUT_OF_BOUNDS (-1866) +%define VERR_SSM_FIELD_NOT_CONSECUTIVE (-1867) +%define VERR_SSM_FIELD_INVALID_CALLBACK (-1868) +%define VERR_SSM_FIELD_INVALID_PADDING_SIZE (-1869) +%define VERR_SSM_FIELD_INVALID_VALUE (-1870) +%define VERR_SSM_STREAM_ERROR (-1871) +%define VERR_SSM_UNEXPECTED_PASS (-1872) +%define VERR_SSM_SKIP_BACKWARDS (-1873) +%define VERR_SSM_MEM_TOO_BIG (-1874) +%define VERR_SSM_BAD_REC_TYPE (-1875) +%define VERR_SSM_IPE_1 (-1876) +%define VERR_SSM_IPE_2 (-1877) +%define VERR_SSM_IPE_3 (-1878) +%define VERR_SSM_FIELD_LOAD_ONLY_TRANSFORMATION (-1879) +%define VERR_VM_ATRESET_NOT_FOUND (-1900) +%define VERR_VM_REQUEST_INVALID_TYPE (-1901) +%define VERR_VM_REQUEST_STATE (-1902) +%define VERR_VM_REQUEST_INVALID_PACKAGE (-1903) +%define VERR_VM_REQUEST_STATUS_STILL_PENDING (-1904) +%define VERR_VM_REQUEST_STATUS_FREED (-1905) +%define VERR_VM_THREAD_NOT_EMT (-1906) +%define VERR_VM_INVALID_VM_STATE (-1907) +%define VERR_VM_DRIVER_NOT_INSTALLED (-1908) +%define VERR_VM_DRIVER_NOT_ACCESSIBLE (-1909) +%define VERR_VM_DRIVER_LOAD_ERROR (-1910) +%define VERR_VM_DRIVER_OPEN_ERROR (-1911) +%define VERR_VM_DRIVER_VERSION_MISMATCH (-1912) +%define VERR_VM_SAVE_STATE_NOT_ALLOWED (-1913) +%define VERR_VM_THREAD_IS_EMT (-1914) +%define VERR_VM_UNEXPECTED_VM_STATE (-1915) +%define VERR_VM_UNEXPECTED_UNSTABLE_STATE (-1916) +%define VERR_VM_REQUEST_TOO_MANY_ARGS_IPE (-1917) +%define VERR_VM_FATAL_WAIT_ERROR (-1918) +%define VERR_VM_REQUEST_KILLED (-1919) +%define VINF_VRDP_SUCCESS VINF_SUCCESS +%define VERR_VRDP_TIMEOUT VERR_TIMEOUT +%define VERR_VRDP_ISO_UNSUPPORTED (-2000) +%define VERR_VRDP_SEC_ENGINE_FAIL (-2001) +%define VERR_VRDP_PROTOCOL_ERROR (-2002) +%define VERR_VRDP_NOT_SUPPORTED (-2003) +%define VERR_VRDP_INSUFFICIENT_DATA (-2004) +%define VERR_VRDP_INVALID_MODE (-2005) +%define VERR_VRDP_NO_MEMORY (-2006) +%define VERR_VRDP_ACCESS_DENIED (-2007) +%define VWRN_VRDP_PDU_NOT_SUPPORTED 2008 +%define VINF_VRDP_PROCESS_PDU 2009 +%define VINF_VRDP_OPERATION_COMPLETED 2010 +%define VINF_VRDP_THREAD_STARTED 2011 +%define VINF_VRDP_RESIZE_REQUESTED 2012 +%define VINF_VRDP_OUTPUT_ENABLE 2013 +%define VERR_CFGM_INTEGER_TOO_BIG (-2100) +%define VERR_CFGM_CHILD_NOT_FOUND (-2101) +%define VERR_CFGM_INVALID_CHILD_PATH (-2102) +%define VERR_CFGM_VALUE_NOT_FOUND (-2103) +%define VERR_CFGM_NO_PARENT (-2104) +%define VERR_CFGM_NO_NODE (-2105) +%define VERR_CFGM_NOT_INTEGER (-2106) +%define VERR_CFGM_NOT_STRING (-2107) +%define VERR_CFGM_NOT_BYTES (-2108) +%define VERR_CFGM_NOT_ENOUGH_SPACE (-2109) +%define VERR_CFGM_NOT_PASSWORD (-2110) +%define VERR_CFGM_INVALID_NODE_PATH (-2160) +%define VERR_CFGM_NODE_EXISTS (-2161) +%define VERR_CFGM_LEAF_EXISTS (-2162) +%define VERR_CFGM_CONFIG_UNKNOWN_VALUE (-2163) +%define VERR_CFGM_CONFIG_UNKNOWN_NODE (-2164) +%define VERR_CFGM_IPE_1 (-2165) +%define VERR_TM_LOAD_STATE (-2200) +%define VERR_TM_INVALID_STATE (-2201) +%define VERR_TM_UNKNOWN_STATE (-2202) +%define VERR_TM_UNSTABLE_STATE (-2203) +%define VERR_TM_GIP_REQUIRED (-2204) +%define VERR_TM_GIP_VERSION (-2205) +%define VERR_TM_GIP_UPDATE_INTERVAL_TOO_BIG (-2206) +%define VERR_TM_TIMER_BAD_CLOCK (-2207) +%define VERR_TM_TIMER_UNSTABLE_STATE (-2208) +%define VERR_TM_TSC_ALREADY_TICKING (-2209) +%define VERR_TM_TSC_ALREADY_PAUSED (-2210) +%define VERR_TM_VIRTUAL_TICKING_IPE (-2211) +%define VERR_TM_TOO_MANY_TIMERS (-2212) +%define VERR_TM_INVALID_TIMER_QUEUE (-2213) +%define VERR_TM_TIMER_QUEUE_CANNOT_GROW (-2214) +%define VERR_TM_IPE_1 (-2291) +%define VERR_TM_IPE_2 (-2292) +%define VERR_TM_IPE_3 (-2293) +%define VERR_TM_IPE_4 (-2294) +%define VERR_TM_IPE_5 (-2295) +%define VERR_TM_IPE_6 (-2296) +%define VERR_TM_IPE_7 (-2297) +%define VERR_TM_IPE_8 (-2298) +%define VERR_TM_IPE_9 (-2299) +%define VERR_REM_VIRTUAL_HARDWARE_ERROR (-2300) +%define VERR_REM_VIRTUAL_CPU_ERROR (-2301) +%define VINF_REM_INTERRUPED_FF 2302 +%define VERR_REM_TOO_MANY_TRAPS (-2304) +%define VERR_REM_NO_MORE_BP_SLOTS (-2305) +%define VERR_REM_BP_NOT_FOUND (-2306) +%define VERR_TRPM_NO_ACTIVE_TRAP (-2400) +%define VERR_TRPM_ACTIVE_TRAP (-2401) +%define VERR_TRPM_SHADOW_IDT_WRITE (-2402) +%define VERR_TRPM_DONT_PANIC (-2403) +%define VERR_TRPM_PANIC (-2404) +%define VERR_TRPM_BAD_TRAP_IN_OP (-2405) +%define VERR_TRPM_IPE_1 (-2406) +%define VERR_TRPM_IPE_2 (-2407) +%define VERR_TRPM_IPE_3 (-2408) +%define VERR_TRPM_HM_IPE (-2409) +%define VERR_SELM_SHADOW_GDT_WRITE (-2500) +%define VERR_SELM_SHADOW_LDT_WRITE (-2501) +%define VERR_SELM_SHADOW_TSS_WRITE (-2502) +%define VINF_SELM_SYNC_GDT 2503 +%define VERR_SELM_NO_TSS (-2504) +%define VERR_SELM_INVALID_LDT (-2505) +%define VERR_SELM_LDT_OUT_OF_BOUNDS (-2506) +%define VERR_SELM_GDT_READ_ERROR (-2507) +%define VERR_SELM_GDT_TOO_FULL (-2508) +%define VERR_SELM_HM_IPE (-2509) +%define VERR_IOM_INVALID_IOPORT_RANGE (-2600) +%define VERR_IOM_NO_R3_IOPORT_RANGE (-2601) +%define VERR_IOM_IOPORT_RANGE_CONFLICT (-2602) +%define VERR_IOM_IOPORT_RANGE_NOT_FOUND (-2603) +%define VERR_IOM_NOT_IOPORT_RANGE_OWNER (-2604) +%define VERR_IOM_INVALID_MMIO_RANGE (-2605) +%define VERR_IOM_NO_R3_MMIO_RANGE (-2606) +%define VERR_IOM_NOT_MMIO_RANGE_OWNER (-2607) +%define VERR_IOM_MMIO_RANGE_CONFLICT (-2608) +%define VERR_IOM_MMIO_RANGE_NOT_FOUND (-2609) +%define VERR_IOM_INCOMPLETE_MMIO_RANGE (-2610) +%define VERR_IOM_INVALID_IOPORT_SIZE (-2611) +%define VERR_IOM_MMIO_HANDLER_BOGUS_CALL (-2612) +%define VERR_IOM_MMIO_HANDLER_DISASM_ERROR (-2613) +%define VERR_IOM_IOPORT_UNUSED (-2614) +%define VINF_IOM_MMIO_UNUSED_00 2615 +%define VINF_IOM_MMIO_UNUSED_FF 2616 +%define VINF_IOM_R3_IOPORT_READ 2620 +%define VINF_IOM_R3_IOPORT_WRITE 2621 +%define VINF_IOM_R3_IOPORT_COMMIT_WRITE 2622 +%define VINF_IOM_R3_MMIO_READ 2623 +%define VINF_IOM_R3_MMIO_WRITE 2624 +%define VINF_IOM_R3_MMIO_READ_WRITE 2625 +%define VINF_IOM_R3_MMIO_COMMIT_WRITE 2626 +%define VERR_IOM_IOPORT_UNKNOWN_OPCODE (-2630) +%define VERR_IOM_IOPORT_IPE_1 (-2631) +%define VERR_IOM_IOPORT_IPE_2 (-2632) +%define VERR_IOM_IOPORT_IPE_3 (-2633) +%define VERR_IOM_MMIO_IPE_1 (-2634) +%define VERR_IOM_MMIO_IPE_2 (-2635) +%define VERR_IOM_MMIO_IPE_3 (-2636) +%define VERR_IOM_HM_IPE (-2637) +%define VERR_IOM_FF_STATUS_IPE (-2638) +%define VERR_IOM_TOO_MANY_IOPORT_REGISTRATIONS (-2650) +%define VERR_IOM_INVALID_IOPORT_HANDLE (-2651) +%define VERR_IOM_IOPORTS_ALREADY_MAPPED (-2652) +%define VERR_IOM_IOPORTS_NOT_MAPPED (-2653) +%define VERR_IOM_TOO_MANY_MMIO_REGISTRATIONS (-2660) +%define VERR_IOM_INVALID_MMIO_HANDLE (-2661) +%define VERR_IOM_MMIO_REGION_ALREADY_MAPPED (-2662) +%define VERR_IOM_MMIO_REGION_NOT_MAPPED (-2663) +%define VERR_VMM_RING0_ASSERTION (-2701) +%define VERR_VMM_HYPER_CR3_MISMATCH (-2702) +%define VERR_VMM_RING3_CALL_DISABLED (-2703) +%define VERR_VMM_R0_VERSION_MISMATCH (-2704) +%define VERR_VMM_RC_VERSION_MISMATCH (-2705) +%define VERR_VMM_LONG_JMP_ERROR (-2709) +%define VINF_VMM_CALL_TRACER (2712) +%define VERR_VMM_SWITCHER_IPE_1 (-2713) +%define VINF_VMM_UNKNOWN_RING3_CALL (2714) +%define VERR_VMM_SWITCHER_STUB (-2715) +%define VERR_VMM_WRONG_HM_VMCPU_STATE (-2716) +%define VERR_VMM_SMAP_BUT_AC_CLEAR (-2717) +%define VERR_VMM_WRONG_NEM_VMCPU_STATE (-2718) +%define VERR_VMM_CONTEXT_HOOK_STILL_ENABLED (-2719) +%define VERR_VMM_CANNOT_BLOCK (-2720) +%define VERR_PDM_NO_SUCH_LUN (-2800) +%define VERR_PDM_DEVINS_UNKNOWN_CFG_VALUES (-2801) +%define VERR_PDM_MISSING_INTERFACE_ABOVE (-2802) +%define VERR_PDM_MISSING_INTERFACE_BELOW (-2803) +%define VERR_PDM_MISSING_INTERFACE (-2804) +%define VERR_PDM_DRVINS_UNKNOWN_CFG_VALUES (-2805) +%define VERR_PDM_TOO_PCI_MANY_DEVICES (-2806) +%define VERR_PDM_NO_QUEUE_ITEMS (-2807) +%define VERR_PDM_DRVINS_NO_ATTACH (-2808) +%define VERR_PDM_DEVINS_NO_ATTACH (-2809) +%define VERR_PDM_NO_ATTACHED_DRIVER (-2810) +%define VERR_PDM_GEOMETRY_NOT_SET (-2811) +%define VERR_PDM_TRANSLATION_NOT_SET (-2812) +%define VERR_PDM_MEDIA_NOT_MOUNTED (-2813) +%define VERR_PDM_MEDIA_MOUNTED (-2814) +%define VERR_PDM_MEDIA_LOCKED (-2815) +%define VERR_PDM_BLOCK_NO_TYPE (-2816) +%define VERR_PDM_BLOCK_UNKNOWN_TYPE (-2817) +%define VERR_PDM_BLOCK_UNKNOWN_TRANSLATION (-2818) +%define VERR_PDM_UNSUPPORTED_BLOCK_TYPE (-2819) +%define VERR_PDM_DRIVER_ALREADY_ATTACHED (-2820) +%define VERR_PDM_NO_DRIVER_ATTACHED (-2821) +%define VERR_PDM_CFG_MISSING_DRIVER_NAME (-2822) +%define VERR_PDM_DRIVER_NOT_FOUND (-2823) +%define VINF_PDM_ALREADY_LOADED (2824) +%define VERR_PDM_MODULE_NAME_CLASH (-2825) +%define VERR_PDM_NO_REGISTRATION_EXPORT (-2826) +%define VERR_PDM_MODULE_NAME_TOO_LONG (-2827) +%define VERR_PDM_DRIVER_NAME_CLASH (-2828) +%define VERR_PDM_UNKNOWN_DRVREG_VERSION (-2829) +%define VERR_PDM_INVALID_DRIVER_REGISTRATION (-2830) +%define VERR_PDM_INVALID_DRIVER_HOST_BITS (-2831) +%define VERR_PDM_DRIVER_DETACH_NOT_POSSIBLE (-2832) +%define VERR_PDM_NO_PCI_BUS (-2833) +%define VERR_PDM_NOT_PCI_DEVICE (-2834) +%define VERR_PDM_UNKNOWN_DEVREG_VERSION (-2835) +%define VERR_PDM_INVALID_DEVICE_REGISTRATION (-2836) +%define VERR_PDM_INVALID_DEVICE_GUEST_BITS (-2837) +%define VERR_PDM_INVALID_DEVICE_HOST_BITS (-2838) +%define VERR_PDM_DEVICE_NAME_CLASH (-2839) +%define VERR_PDM_DEVICE_NOT_FOUND (-2840) +%define VERR_PDM_DEVICE_INSTANCE_NOT_FOUND (-2841) +%define VERR_PDM_DEVICE_INSTANCE_NO_IBASE (-2842) +%define VERR_PDM_DEVICE_INSTANCE_LUN_NOT_FOUND (-2843) +%define VERR_PDM_DRIVER_INSTANCE_NOT_FOUND (-2844) +%define VERR_PDM_LUN_NOT_FOUND (-2845) +%define VERR_PDM_NO_DRIVER_ATTACHED_TO_LUN (-2846) +%define VINF_PDM_NO_DRIVER_ATTACHED_TO_LUN 2846 +%define VERR_PDM_NO_PIC_INSTANCE (-2847) +%define VERR_PDM_NO_APIC_INSTANCE (-2848) +%define VERR_PDM_NO_DMAC_INSTANCE (-2849) +%define VERR_PDM_NO_RTC_INSTANCE (-2850) +%define VERR_PDM_HIF_SHARING_VIOLATION (-2851) +%define VERR_PDM_HIF_OPEN_FAILED (-2852) +%define VERR_PDM_DEVICE_NO_RT_ATTACH (-2853) +%define VERR_PDM_DRIVER_NO_RT_ATTACH (-2854) +%define VERR_PDM_HIF_INVALID_VERSION (-2855) +%define VERR_PDM_UNKNOWN_USBREG_VERSION (-2856) +%define VERR_PDM_INVALID_USB_REGISTRATION (-2857) +%define VERR_PDM_USB_NAME_CLASH (-2858) +%define VERR_PDM_USB_HUB_EXISTS (-2859) +%define VERR_PDM_NO_USB_HUBS (-2860) +%define VERR_PDM_NO_USB_PORTS (-2861) +%define VERR_PDM_NO_USBPROXY (-2862) +%define VERR_PDM_ASYNC_TEMPLATE_BUSY (-2863) +%define VERR_PDM_ASYNC_COMPLETION_ALREADY_SUSPENDED (-2864) +%define VERR_PDM_ASYNC_COMPLETION_NOT_SUSPENDED (-2865) +%define VERR_PDM_DRIVER_INVALID_PROPERTIES (-2866) +%define VERR_PDM_TOO_MANY_DEVICE_INSTANCES (-2867) +%define VERR_PDM_TOO_MANY_DRIVER_INSTANCES (-2868) +%define VERR_PDM_TOO_MANY_USB_DEVICE_INSTANCES (-2869) +%define VERR_PDM_DEVINS_VERSION_MISMATCH (-2870) +%define VERR_PDM_DEVHLP_VERSION_MISMATCH (-2871) +%define VERR_PDM_USBINS_VERSION_MISMATCH (-2872) +%define VERR_PDM_USBHLPR3_VERSION_MISMATCH (-2873) +%define VERR_PDM_DRVINS_VERSION_MISMATCH (-2874) +%define VERR_PDM_DRVHLPR3_VERSION_MISMATCH (-2875) +%define VERR_PDM_DEVICE_VERSION_MISMATCH (-2876) +%define VERR_PDM_USBDEV_VERSION_MISMATCH (-2877) +%define VERR_PDM_DRIVER_VERSION_MISMATCH (-2878) +%define VERR_PDM_DEV_HEAP_R3_TO_GCPHYS (-2879) +%define VERR_PDM_HPET_LEGACY_NOTIFY_MISSING (-2880) +%define VERR_PDM_CRITSECT_IPE (-2881) +%define VERR_PDM_CRITSECT_NOT_FOUND (-2882) +%define VERR_PDM_THREAD_INVALID_CALLER (-2883) +%define VERR_PDM_THREAD_IPE_1 (-2884) +%define VERR_PDM_THREAD_IPE_2 (-2885) +%define VERR_PDM_ONE_PCI_FUNCTION_PER_DEVICE (-2886) +%define VERR_PDM_BAD_PCI_CONFIG (-2887) +%define VERR_PDM_DEV_IPE_1 (-2888) +%define VERR_PDM_MISCONFIGURED_DRV_TRANSFORMATION (-2889) +%define VERR_PDM_CANNOT_TRANSFORM_REMOVED_DRIVER (-2890) +%define VERR_PDM_NOT_PCI_BUS_MASTER (-2891) +%define VERR_PDM_HM_IPE (-2892) +%define VERR_PDM_MEDIAEX_IOREQ_CANCELED (-2893) +%define VERR_PDM_MEDIAEX_IOBUF_OVERFLOW (-2894) +%define VERR_PDM_MEDIAEX_IOBUF_UNDERRUN (-2895) +%define VERR_PDM_MEDIAEX_IOREQID_CONFLICT (-2896) +%define VERR_PDM_MEDIAEX_IOREQID_NOT_FOUND (-2897) +%define VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS 2898 +%define VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE (-2899) +%define VINF_PDM_PCI_DO_DEFAULT (7200) +%define VERR_PDM_CRITSECT_ABORT_FAILED (-7201) +%define VERR_PDM_CRITSECTRW_TOO_MANY_READERS (-7202) +%define VERR_PDM_CRITSECTRW_TOO_MANY_WRITERS (-7203) +%define VERR_PDM_CRITSECTRW_TOO_MANY_RECURSIONS (-7204) +%define VERR_PDM_CRITSECTRW_IPE (-7205) +%define VERR_PDM_CRITSECTRW_MISALIGNED (-7206) +%define VERR_HGCM_SERVICE_NOT_FOUND (-2900) +%define VINF_HGCM_CLIENT_REJECTED 2901 +%define VERR_HGCM_INVALID_CMD_ADDRESS (-2902) +%define VINF_HGCM_ASYNC_EXECUTE 2903 +%define VERR_HGCM_INTERNAL (-2904) +%define VERR_HGCM_INVALID_CLIENT_ID (-2905) +%define VINF_HGCM_SAVE_STATE (2906) +%define VERR_HGCM_SERVICE_EXISTS (-2907) +%define VERR_HGCM_TOO_MANY_CLIENTS (-2908) +%define VERR_HGCM_TOO_MANY_CLIENT_CALLS (-2909) +%define VERR_NAT_REDIR_GUEST_IP (-3001) +%define VERR_NAT_REDIR_SETUP (-3002) +%define VERR_HOSTIF_INIT_FAILED (-3100) +%define VERR_HOSTIF_DEVICE_NAME_TOO_LONG (-3101) +%define VERR_HOSTIF_IOCTL (-3102) +%define VERR_HOSTIF_BLOCKING (-3103) +%define VERR_HOSTIF_FD_AND_INIT_TERM (-3104) +%define VERR_HOSTIF_TERM_FAILED (-3105) +%define VERR_VD_INVALID_TYPE (-3200) +%define VERR_VD_INVALID_STATE (-3201) +%define VERR_VD_VALUE_NOT_FOUND (-3202) +%define VERR_VD_NOT_OPENED (-3203) +%define VERR_VD_IMAGE_NOT_FOUND (-3204) +%define VERR_VD_IMAGE_READ_ONLY (-3205) +%define VERR_VD_GEOMETRY_NOT_SET (-3206) +%define VERR_VD_BLOCK_FREE (-3207) +%define VERR_VD_UUID_MISMATCH (-3208) +%define VINF_VD_ASYNC_IO_FINISHED 3209 +%define VERR_VD_ASYNC_IO_IN_PROGRESS (-3210) +%define VERR_VD_INVALID_SIZE (-3211) +%define VERR_VD_UNKNOWN_CFG_VALUES (-3212) +%define VERR_VD_UNKNOWN_INTERFACE (-3213) +%define VERR_VD_DEK_MISSING (-3214) +%define VERR_VD_PASSWORD_INCORRECT (-3215) +%define VERR_VD_GEN_INVALID_HEADER (-3220) +%define VERR_VD_VDI_INVALID_HEADER (-3230) +%define VERR_VD_VDI_INVALID_SIGNATURE (-3231) +%define VERR_VD_VDI_UNSUPPORTED_VERSION (-3232) +%define VERR_VD_VDI_COMMENT_TOO_LONG (-3233) +%define VERR_VD_VMDK_INVALID_HEADER (-3240) +%define VERR_VD_VMDK_UNSUPPORTED_VERSION (-3241) +%define VERR_VD_VMDK_VALUE_NOT_FOUND (-3242) +%define VERR_VD_VMDK_INVALID_STATE (-3243) +%define VERR_VD_VMDK_INVALID_FORMAT (-3244) +%define VERR_VD_VMDK_INVALID_WRITE (-3245) +%define VERR_VD_ISCSI_INVALID_HEADER (-3250) +%define VERR_VD_ISCSI_INVALID_STATE (-3251) +%define VERR_VD_ISCSI_INVALID_TYPE (-3252) +%define VERR_VD_ISCSI_SECRET_ENCRYPTED (-3253) +%define VERR_VD_VHD_INVALID_HEADER (-3260) +%define VERR_VD_PARALLELS_INVALID_HEADER (-3265) +%define VERR_VD_DMG_INVALID_HEADER (-3267) +%define VERR_VD_RAW_INVALID_HEADER (-3270) +%define VERR_VD_RAW_INVALID_TYPE (-3271) +%define VERR_VD_NOT_ENOUGH_METADATA (-3272) +%define VERR_VD_IOCTX_HALT (-3273) +%define VERR_VD_CACHE_ALREADY_EXISTS (-3274) +%define VERR_VD_CACHE_NOT_FOUND (-3275) +%define VERR_VD_CACHE_NOT_UP_TO_DATE (-3276) +%define VERR_VD_DISCARD_ALIGNMENT_NOT_MET (-3277) +%define VERR_VD_DISCARD_NOT_SUPPORTED (-3278) +%define VERR_VD_IMAGE_CORRUPTED (-3279) +%define VERR_VD_IMAGE_REPAIR_NOT_SUPPORTED (-3280) +%define VERR_VD_IMAGE_REPAIR_IMPOSSIBLE (-3281) +%define VERR_VD_READ_OUT_OF_RANGE (-3282) +%define VINF_VD_NEW_ZEROED_BLOCK 3283 +%define VERR_VD_DMG_XML_PARSE_ERROR (-3284) +%define VERR_VD_DMG_NOT_FOUND_INSIDE_XAR (-3285) +%define VERR_VD_RAW_SIZE_MODULO_512 (-3286) +%define VERR_VD_RAW_SIZE_MODULO_2048 (-3287) +%define VERR_VD_RAW_SIZE_OPTICAL_TOO_SMALL (-3288) +%define VERR_VD_RAW_SIZE_FLOPPY_TOO_BIG (-3289) +%define VERR_VD_SHRINK_NOT_SUPPORTED (-3290) +%define VERR_VBGL_NOT_INITIALIZED (-3300) +%define VERR_VBGL_INVALID_ADDR (-3301) +%define VERR_VBGL_IOCTL_FAILED (-3302) +%define VERR_VUSB_NO_PORTS (-3400) +%define VERR_VUSB_DEVICE_NOT_ATTACHED (-3401) +%define VERR_VUSB_NO_URB_MEMORY (-3402) +%define VERR_VUSB_FAILED_TO_QUEUE_URB (-3403) +%define VERR_VUSB_DEVICE_NAME_NOT_FOUND (-3404) +%define VERR_VUSB_USBFS_PERMISSION (-3405) +%define VERR_VUSB_DEVICE_IS_RESETTING (-3406) +%define VERR_VUSB_DEVICE_IS_SUSPENDED (-3407) +%define VERR_VUSB_USB_DEVICE_PERMISSION (-3408) +%define VERR_VGA_INVALID_CUSTOM_MODE (-3500) +%define VINF_VGA_RESIZE_IN_PROGRESS (3501) +%define VERR_VGA_UNEXPECTED_PCI_REGION_LOAD_CHANGE (-3502) +%define VERR_VGA_GL_LOAD_FAILURE (-3503) +%define VERR_VGA_GL_SYMBOL_NOT_FOUND (-3504) +%define VERR_INTNET_FLT_IF_NOT_FOUND (-3600) +%define VERR_INTNET_FLT_IF_BUSY (-3601) +%define VERR_INTNET_FLT_IF_FAILED (-3602) +%define VERR_INTNET_INCOMPATIBLE_TRUNK (-3603) +%define VERR_INTNET_INCOMPATIBLE_FLAGS (-3604) +%define VERR_INTNET_FLT_VNIC_CREATE_FAILED (-3605) +%define VERR_INTNET_FLT_VNIC_LINK_ID_NOT_FOUND (-3606) +%define VERR_INTNET_FLT_VNIC_INIT_FAILED (-3607) +%define VERR_INTNET_FLT_VNIC_OPEN_FAILED (-3608) +%define VERR_INTNET_FLT_LOWER_LINK_INFO_NOT_FOUND (-3609) +%define VERR_INTNET_FLT_LOWER_LINK_OPEN_FAILED (-3610) +%define VERR_INTNET_FLT_LOWER_LINK_ID_NOT_FOUND (-3611) +%define VERR_SUPDRV_COMPONENT_NOT_FOUND (-3700) +%define VERR_SUPDRV_INTERFACE_NOT_SUPPORTED (-3701) +%define VERR_SUPDRV_SERVICE_NOT_FOUND (-3702) +%define VERR_SUPDRV_KERNEL_TOO_OLD_FOR_VTX (-3703) +%define VERR_SUPDRV_VTG_MAGIC (-3704) +%define VERR_SUPDRV_VTG_BITS (-3705) +%define VERR_SUPDRV_VTG_BAD_HDR_MISC (-3706) +%define VERR_SUPDRV_VTG_BAD_HDR_OFF (-3707) +%define VERR_SUPDRV_VTG_BAD_HDR_PTR (-3708) +%define VERR_SUPDRV_VTG_BAD_HDR_TOO_FEW (-3709) +%define VERR_SUPDRV_VTG_BAD_HDR_TOO_MUCH (-3710) +%define VERR_SUPDRV_VTG_BAD_HDR_NOT_MULTIPLE (-3711) +%define VERR_SUPDRV_VTG_STRTAB_OFF (-3712) +%define VERR_SUPDRV_VTG_BAD_STRING (-3713) +%define VERR_SUPDRV_VTG_STRING_TOO_LONG (-3714) +%define VERR_SUPDRV_VTG_BAD_ATTR (-3715) +%define VERR_SUPDRV_VTG_BAD_PROVIDER (-3716) +%define VERR_SUPDRV_VTG_BAD_PROBE (-3717) +%define VERR_SUPDRV_VTG_BAD_ARGLIST (-3718) +%define VERR_SUPDRV_VTG_BAD_PROBE_ENABLED (-3719) +%define VERR_SUPDRV_VTG_BAD_PROBE_LOC (-3720) +%define VERR_SUPDRV_VTG_ALREADY_REGISTERED (-3721) +%define VERR_SUPDRV_VTG_ONLY_ONCE_PER_SESSION (-3722) +%define VERR_SUPDRV_TRACER_ALREADY_REGISTERED (-3723) +%define VERR_SUPDRV_TRACER_NOT_REGISTERED (-3724) +%define VERR_SUPDRV_TRACER_ALREADY_OPENED (-3725) +%define VERR_SUPDRV_TRACER_NOT_OPENED (-3726) +%define VERR_SUPDRV_TRACER_NOT_PRESENT (-3727) +%define VERR_SUPDRV_TRACER_UNLOADING (-3728) +%define VERR_SUPDRV_TRACER_SESSION_BUSY (-3729) +%define VERR_SUPDRV_TRACER_CANNOT_OPEN_SELF (-3730) +%define VERR_SUPDRV_TRACER_BAD_ARG_FLAGS (-3731) +%define VERR_SUPDRV_TRACER_TOO_MANY_PROVIDERS (-3732) +%define VERR_SUPDRV_TRACER_TOO_LARGE (-3733) +%define VERR_SUPDRV_TRACER_UMOD_NOT_ADJACENT (-3734) +%define VERR_SUPDRV_TRACER_UMOD_TOO_MANY_PROBES (-3735) +%define VERR_SUPDRV_TRACER_UMOD_STRTAB_TOO_BIG (-3736) +%define VERR_SUPDRV_TRACER_UMOD_STRTAB_OFF_BAD (-3737) +%define VERR_SUPDRV_HARDENING_EVIL_HANDLE (-3738) +%define VERR_SUPDRV_APIPORT_OPEN_ERROR (-3739) +%define VERR_SUPDRV_SESSION_PROCESS_ENUM_ERROR (-3740) +%define VERR_SUPDRV_CSRSS_NOT_FOUND (-3741) +%define VERR_SUPDRV_APIPORT_OPEN_ERROR_TYPE (-3742) +%define VERR_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED (-3743) +%define VERR_SUPDRV_TSC_FREQ_MEASUREMENT_FAILED (-3744) +%define VERR_SUPDRV_TSC_READ_FAILED (-3745) +%define VWRN_SUPDRV_TSC_DELTA_MEASUREMENT_FAILED 3746 +%define VERR_SUPDRV_TSC_DELTA_MEASUREMENT_BUSY (-3747) +%define VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_1 (-3748) +%define VERR_SUPDRV_NOT_BUDDING_VM_PROCESS_2 (-3749) +%define VERR_SUPDRV_NO_RAW_MODE_HYPER_V_ROOT (-7000) +%define VERR_SUPLIB_PATH_NOT_ABSOLUTE (-3750) +%define VERR_SUPLIB_PATH_NOT_CLEAN (-3751) +%define VERR_SUPLIB_PATH_TOO_LONG (-3752) +%define VERR_SUPLIB_PATH_TOO_SHORT (-3753) +%define VERR_SUPLIB_PATH_TOO_MANY_COMPONENTS (-3754) +%define VERR_SUPLIB_PATH_IS_ROOT (-3755) +%define VERR_SUPLIB_DIR_ENUM_FAILED (-3756) +%define VERR_SUPLIB_STAT_ENUM_FAILED (-3757) +%define VERR_SUPLIB_STAT_FAILED (-3758) +%define VERR_SUPLIB_FSTAT_FAILED (-3759) +%define VERR_SUPLIB_SYMLINKS_ARE_NOT_PERMITTED (-3760) +%define VERR_SUPLIB_NOT_DIR_NOT_FILE (-3761) +%define VERR_SUPLIB_IS_DIRECTORY (-3762) +%define VERR_SUPLIB_IS_FILE (-3763) +%define VERR_SUPLIB_NOT_SAME_OBJECT (-3764) +%define VERR_SUPLIB_OWNER_NOT_ROOT (-3765) +%define VERR_SUPLIB_WRITE_NON_SYS_GROUP (-3766) +%define VERR_SUPLIB_WORLD_WRITABLE (-3767) +%define VERR_SUPLIB_INVALID_ARGV0_INTERNAL (-3768) +%define VERR_SUPLIB_INVALID_INTERNAL_APP_DIR (-3769) +%define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_0 (-3770) +%define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_1 (-3771) +%define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_2 (-3772) +%define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_3 (-3773) +%define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_4 (-3774) +%define VERR_SUPLIB_NT_PROCESS_UNTRUSTED_5 (-3775) +%define VERR_SUPLIB_TEXT_NOT_WRITEABLE (-3776) +%define VERR_SUPLIB_TEXT_NOT_SEALED (-3777) +%define VERR_SUPLIB_UNEXPECTED_INSTRUCTION (-3778) +%define VERR_GMM_OUT_OF_MEMORY (-3801) +%define VERR_GMM_HIT_GLOBAL_LIMIT (-3802) +%define VERR_GMM_HIT_VM_ACCOUNT_LIMIT (-3803) +%define VERR_GMM_ATTEMPT_TO_FREE_TOO_MUCH (-3804) +%define VERR_GMM_ATTEMPT_TO_DEFLATE_TOO_MUCH (-3805) +%define VERR_GMM_PAGE_NOT_FOUND (-3806) +%define VERR_GMM_PAGE_NOT_PRIVATE (-3807) +%define VERR_GMM_PAGE_NOT_SHARED (-3808) +%define VERR_GMM_PAGE_ALREADY_FREE (-3809) +%define VERR_GMM_NOT_PAGE_OWNER (-3810) +%define VERR_GMM_CHUNK_NOT_FOUND (-3811) +%define VERR_GMM_CHUNK_ALREADY_MAPPED (-3812) +%define VERR_GMM_CHUNK_NOT_MAPPED (-3813) +%define VERR_GMM_TOO_MANY_CHUNK_MAPPINGS (-3814) +%define VERR_GMM_MEMORY_RESERVATION_DECLINED (-3815) +%define VERR_GMM_IS_NOT_SANE (-3816) +%define VERR_GMM_CHUNK_INSERT (-3817) +%define VERR_GMM_INSTANCE (-3818) +%define VERR_GMM_MTX_FLAGS (-3819) +%define VERR_GMM_ALLOC_PAGES_IPE (-3820) +%define VERR_GMM_ACTUAL_PAGES_IPE (-3821) +%define VERR_GMM_MODULE_NAME_TOO_LONG (-3822) +%define VERR_GMM_MODULE_VERSION_TOO_LONG (-3823) +%define VERR_GMM_TOO_MANY_REGIONS (-3824) +%define VERR_GMM_TOO_MANY_PER_VM_MODULES (-3825) +%define VERR_GMM_TOO_MANY_GLOBAL_MODULES (-3826) +%define VINF_GMM_SHARED_MODULE_ALREADY_REGISTERED (3827) +%define VERR_GMM_SHARED_MODULE_ADDRESS_CLASH (-3828) +%define VERR_GMM_SHARED_MODULE_NOT_FOUND (-3829) +%define VERR_GMM_BAD_SHARED_MODULE_SIZE (-3830) +%define VERR_GMM_SHARED_MODULE_BAD_REGIONS_SIZE (-3831) +%define VERR_GVM_TOO_MANY_VMS (-3900) +%define VINF_GVM_NOT_BLOCKED 3901 +%define VINF_GVM_NOT_BUSY_IN_GC 3902 +%define VINF_GVM_YIELDED 3903 +%define VERR_VMX_VMXON_FAILED (-4000) +%define VERR_VMX_INVALID_VMCS_PTR (-4001) +%define VERR_VMX_INVALID_VMCS_FIELD (-4002) +%define VERR_VMX_RESERVED (-4003) +%define VERR_VMX_INVALID_VMXON_PTR (-4004) +%define VERR_VMX_UNABLE_TO_START_VM (-4005) +%define VERR_VMX_INVALID_HOST_STATE (-4006) +%define VERR_VMX_NO_VMX (-4009) +%define VERR_VMX_IN_VMX_ROOT_MODE (-4011) +%define VERR_VMX_X86_CR4_VMXE_CLEARED (-4012) +%define VERR_VMX_MSR_LOCKING_FAILED (-4013) +%define VERR_VMX_INVALID_GUEST_STATE (-4014) +%define VERR_VMX_UNEXPECTED_EXIT (-4015) +%define VERR_VMX_UNEXPECTED_EXCEPTION (-4016) +%define VERR_VMX_UNEXPECTED_INTERRUPTION_EXIT_TYPE (-4017) +%define VERR_VMX_NOT_IN_VMX_ROOT_MODE (-4018) +%define VERR_VMX_UNDEFINED_EXIT_CODE (-4019) +%define VERR_VMX_VMPTRLD_FAILED (-4021) +%define VERR_VMX_INVALID_VMCS_PTR_TO_START_VM (-4022) +%define VERR_VMX_IPE_1 (-4023) +%define VERR_VMX_IPE_2 (-4024) +%define VERR_VMX_IPE_3 (-4025) +%define VERR_VMX_IPE_4 (-4026) +%define VERR_VMX_IPE_5 (-4027) +%define VERR_VMX_MSR_ALL_VMX_DISABLED (-4028) +%define VERR_VMX_MSR_VMX_DISABLED (-4029) +%define VERR_VMX_VMCS_FIELD_CACHE_INVALID (-4030) +%define VERR_VMX_MSR_VMX_ENABLE_FAILED (-4031) +%define VERR_VMX_MSR_SMX_VMX_ENABLE_FAILED (-4032) +%define VINF_VMX_VMEXIT 4033 +%define VERR_VMX_VMENTRY_FAILED (-4033) +%define VERR_VMX_VMEXIT_FAILED (-4034) +%define VINF_VMX_INTERCEPT_NOT_ACTIVE 4035 +%define VINF_VMX_MODIFIES_BEHAVIOR 4036 +%define VINF_VMX_VMLAUNCH_VMRESUME 4037 +%define VERR_VMX_INVALID_VMCS_LAUNCH_STATE (-4038) +%define VERR_VMX_STARTVM_PRECOND_0 (-4039) +%define VERR_VMX_STARTVM_PRECOND_1 (-4040) +%define VERR_VMX_STARTVM_PRECOND_2 (-4041) +%define VERR_VMX_STARTVM_PRECOND_3 (-4042) +%define VERR_SVM_UNABLE_TO_START_VM (-4050) +%define VERR_SVM_ILLEGAL_EFER_MSR (-4051) +%define VERR_SVM_NO_SVM (-4052) +%define VERR_SVM_DISABLED (-4053) +%define VERR_SVM_IN_USE (-4054) +%define VERR_SVM_INVALID_PVMCB (-4055) +%define VERR_SVM_UNEXPECTED_EXIT (-4056) +%define VERR_SVM_UNEXPECTED_XCPT_EXIT (-4057) +%define VERR_SVM_UNEXPECTED_PATCH_TYPE (-4058) +%define VERR_SVM_INVALID_GUEST_STATE (-4059) +%define VERR_SVM_UNKNOWN_EXIT (-4060) +%define VERR_SVM_IPE_1 (-4061) +%define VERR_SVM_IPE_2 (-4062) +%define VERR_SVM_IPE_3 (-4063) +%define VERR_SVM_IPE_4 (-4064) +%define VERR_SVM_IPE_5 (-4065) +%define VERR_SVM_VMEXIT_FAILED (-4066) +%define VINF_SVM_VMEXIT 4067 +%define VINF_SVM_VMRUN 4068 +%define VINF_SVM_INTERCEPT_NOT_ACTIVE 4069 +%define VERR_SVM_VMRUN_PRECOND_0 (-4070) +%define VERR_SVM_VMRUN_PRECOND_1 (-4071) +%define VERR_SVM_VMRUN_PRECOND_2 (-4072) +%define VERR_SVM_VMRUN_PRECOND_3 (-4073) +%define VERR_HM_SUSPEND_PENDING (-4100) +%define VERR_HM_CONFIG_MISMATCH (-4103) +%define VERR_HM_ALREADY_ENABLED_IPE (-4104) +%define VERR_HM_UNEXPECTED_LD_ST_MSR (-4105) +%define VERR_HM_NO_32_TO_64_SWITCHER (-4106) +%define VERR_HM_WRONG_CPU (-4107) +%define VERR_HM_IPE_1 (-4108) +%define VERR_HM_IPE_2 (-4109) +%define VERR_HM_WRONG_SWITCHER (-4110) +%define VERR_HM_UNKNOWN_IO_INSTRUCTION (-4111) +%define VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO (-4112) +%define VERR_HM_IPE_3 (-4113) +%define VERR_HM_IPE_4 (-4114) +%define VERR_HM_IPE_5 (-4115) +%define VERR_HM_INVALID_HM64ON32OP (-4116) +%define VINF_HM_DOUBLE_FAULT 4117 +%define VINF_HM_PENDING_XCPT 4118 +%define VERR_DIS_INVALID_OPCODE (-4200) +%define VERR_DIS_GEN_FAILURE (-4201) +%define VERR_DIS_NO_READ_CALLBACK (-4202) +%define VERR_DIS_INVALID_MODRM (-4203) +%define VERR_DIS_INVALID_PARAMETER (-4204) +%define VERR_DIS_TOO_LONG_INSTR (-4206) +%define VERR_WEB_NOT_AUTHENTICATED (-4300) +%define VERR_WEB_INVALID_MANAGED_OBJECT_REFERENCE (-4301) +%define VERR_WEB_INVALID_SESSION_ID (-4302) +%define VERR_WEB_INVALID_OBJECT_ID (-4303) +%define VERR_WEB_UNSUPPORTED_INTERFACE (-4304) +%define VINF_PARAV_SWITCH_TO_HOST 4400 +%define VINF_VHWA_CMD_PENDING 4500 +%define VERR_COM_UNEXPECTED (-4600) +%define VERR_COM_VBOX_LOWEST (-4699) +%define VERR_COM_OBJECT_NOT_FOUND (VERR_COM_VBOX_LOWEST + 1) +%define VERR_COM_INVALID_VM_STATE (VERR_COM_VBOX_LOWEST + 2) +%define VERR_COM_VM_ERROR (VERR_COM_VBOX_LOWEST + 3) +%define VERR_COM_FILE_ERROR (VERR_COM_VBOX_LOWEST + 4) +%define VERR_COM_IPRT_ERROR (VERR_COM_VBOX_LOWEST + 5) +%define VERR_COM_PDM_ERROR (VERR_COM_VBOX_LOWEST + 6) +%define VERR_COM_INVALID_OBJECT_STATE (VERR_COM_VBOX_LOWEST + 7) +%define VERR_COM_HOST_ERROR (VERR_COM_VBOX_LOWEST + 8) +%define VERR_COM_NOT_SUPPORTED (VERR_COM_VBOX_LOWEST + 9) +%define VERR_COM_XML_ERROR (VERR_COM_VBOX_LOWEST + 10) +%define VERR_COM_INVALID_SESSION_STATE (VERR_COM_VBOX_LOWEST + 11) +%define VERR_COM_OBJECT_IN_USE (VERR_COM_VBOX_LOWEST + 12) +%define VERR_COM_DONT_CALL_AGAIN (VERR_COM_VBOX_LOWEST + 13) +%define VERR_VMMDEV_CPU_HOTPLUG_NOT_MONITORED_BY_GUEST (-4700) +%define VINF_AIO_TASK_PENDING 4800 +%define VERR_VSCSI_LUN_TYPE_NOT_SUPPORTED (-4900) +%define VERR_VSCSI_LUN_ATTACHED_TO_DEVICE (-4901) +%define VERR_VSCSI_LUN_INVALID (-4902) +%define VERR_VSCSI_LUN_NOT_ATTACHED (-4903) +%define VERR_VSCSI_LUN_BUSY (-4904) +%define VERR_FAM_OPEN_FAILED (-5000) +%define VERR_FAM_MONITOR_FILE_FAILED (-5001) +%define VERR_FAM_MONITOR_DIRECTORY_FAILED (-5002) +%define VERR_FAM_CONNECTION_LOST (-5003) +%define VERR_PCI_PASSTHROUGH_NO_RAM_PREALLOC (-5100) +%define VERR_PCI_PASSTHROUGH_NO_HM (-5101) +%define VERR_PCI_PASSTHROUGH_NO_NESTED_PAGING (-5102) +%define VINF_PCI_MAPPING_DONE 5150 +%define VERR_GVMM_INSTANCE (-5200) +%define VERR_GVMM_HOST_CPU_RANGE (-5201) +%define VERR_GVMM_BROKEN_IPRT (-5202) +%define VERR_GVMM_IPE_1 (-5203) +%define VERR_GVMM_IPE_2 (-5204) +%define VERR_GVMM_NOT_ALL_EMTS_DEREGISTERED (-5205) +%define VERR_IEM_INSTR_NOT_IMPLEMENTED (-5300) +%define VERR_IEM_INVALID_OPERAND_SIZE (-5301) +%define VERR_IEM_INVALID_ADDRESS_MODE (-5302) +%define VERR_IEM_INVALID_EFF_SEG (-5303) +%define VERR_IEM_INVALID_INSTR_LENGTH (-5304) +%define VINF_IEM_SELECTOR_NOT_OK (5305) +%define VERR_IEM_RESTART_INSTRUCTION (-5389) +%define VERR_IEM_ASPECT_NOT_IMPLEMENTED (-5390) +%define VERR_IEM_IPE_1 (-5391) +%define VERR_IEM_IPE_2 (-5392) +%define VERR_IEM_IPE_3 (-5393) +%define VERR_IEM_IPE_4 (-5394) +%define VERR_IEM_IPE_5 (-5395) +%define VERR_IEM_IPE_6 (-5396) +%define VERR_IEM_IPE_7 (-5397) +%define VERR_IEM_IPE_8 (-5398) +%define VERR_IEM_IPE_9 (-5399) +%define VERR_DBGC_QUIT (-5400) +%define VWRN_DBGC_CMD_PENDING 5401 +%define VWRN_DBGC_ALREADY_REGISTERED 5402 +%define VERR_DBGC_COMMANDS_NOT_REGISTERED (-5403) +%define VERR_DBGC_BP_NOT_FOUND (-5404) +%define VERR_DBGC_BP_EXISTS (-5405) +%define VINF_DBGC_BP_NO_COMMAND 5406 +%define VERR_DBGC_COMMAND_FAILED (-5407) +%define VERR_DBGC_IPE (-5408) +%define VERR_DBGC_PARSE_LOWEST (-5499) +%define VERR_DBGC_PARSE_TOO_FEW_ARGUMENTS (VERR_DBGC_PARSE_LOWEST + 0) +%define VERR_DBGC_PARSE_TOO_MANY_ARGUMENTS (VERR_DBGC_PARSE_LOWEST + 1) +%define VERR_DBGC_PARSE_ARGUMENT_OVERFLOW (VERR_DBGC_PARSE_LOWEST + 2) +%define VERR_DBGC_PARSE_EXPECTED_BINARY_OP (VERR_DBGC_PARSE_LOWEST + 3) +%define VERR_DBGC_PARSE_NO_RANGE_ALLOWED (VERR_DBGC_PARSE_LOWEST + 5) +%define VERR_DBGC_PARSE_UNBALANCED_QUOTE (VERR_DBGC_PARSE_LOWEST + 6) +%define VERR_DBGC_PARSE_UNBALANCED_PARENTHESIS (VERR_DBGC_PARSE_LOWEST + 7) +%define VERR_DBGC_PARSE_EMPTY_ARGUMENT (VERR_DBGC_PARSE_LOWEST + 8) +%define VERR_DBGC_PARSE_UNEXPECTED_OPERATOR (VERR_DBGC_PARSE_LOWEST + 9) +%define VERR_DBGC_PARSE_INVALID_NUMBER (VERR_DBGC_PARSE_LOWEST + 10) +%define VERR_DBGC_PARSE_NUMBER_TOO_BIG (VERR_DBGC_PARSE_LOWEST + 11) +%define VERR_DBGC_PARSE_INVALID_OPERATION (VERR_DBGC_PARSE_LOWEST + 12) +%define VERR_DBGC_PARSE_FUNCTION_NOT_FOUND (VERR_DBGC_PARSE_LOWEST + 13) +%define VERR_DBGC_PARSE_NOT_A_FUNCTION (VERR_DBGC_PARSE_LOWEST + 14) +%define VERR_DBGC_PARSE_NO_SCRATCH (VERR_DBGC_PARSE_LOWEST + 15) +%define VERR_DBGC_PARSE_NO_MEMORY (VERR_DBGC_PARSE_LOWEST + 16) +%define VERR_DBGC_PARSE_INCORRECT_ARG_TYPE (VERR_DBGC_PARSE_LOWEST + 17) +%define VERR_DBGC_PARSE_VARIABLE_NOT_FOUND (VERR_DBGC_PARSE_LOWEST + 18) +%define VERR_DBGC_PARSE_CONVERSION_FAILED (VERR_DBGC_PARSE_LOWEST + 19) +%define VERR_DBGC_PARSE_NOT_IMPLEMENTED (VERR_DBGC_PARSE_LOWEST + 20) +%define VERR_DBGC_PARSE_BAD_RESULT_TYPE (VERR_DBGC_PARSE_LOWEST + 21) +%define VERR_DBGC_PARSE_WRITEONLY_SYMBOL (VERR_DBGC_PARSE_LOWEST + 22) +%define VERR_DBGC_PARSE_INVALD_COMMAND_NAME (VERR_DBGC_PARSE_LOWEST + 23) +%define VERR_DBGC_PARSE_COMMAND_NOT_FOUND (VERR_DBGC_PARSE_LOWEST + 24) +%define VERR_DBGC_PARSE_BUG (VERR_DBGC_PARSE_LOWEST + 25) +%define VERR_SUP_VP_MEMORY_VS_FILE_MISMATCH (-5600) +%define VERR_SUP_VP_SECTION_PROTECTION_MISMATCH (-5601) +%define VERR_SUP_VP_SECTION_NOT_MAPPED (-5602) +%define VERR_SUP_VP_SECTION_NOT_FULLY_MAPPED (-5603) +%define VERR_SUP_VP_BAD_FILE_ALIGNMENT_VALUE (-5604) +%define VERR_SUP_VP_BAD_IMAGE_BASE (-5605) +%define VERR_SUP_VP_BAD_IMAGE_SIGNATURE (-5606) +%define VERR_SUP_VP_BAD_IMAGE_SIZE (-5607) +%define VERR_SUP_VP_BAD_MZ_OFFSET (-5608) +%define VERR_SUP_VP_BAD_OPTIONAL_HEADER (-5609) +%define VERR_SUP_VP_BAD_SECTION_ALIGNMENT_VALUE (-5610) +%define VERR_SUP_VP_BAD_SECTION_FILE_SIZE (-5611) +%define VERR_SUP_VP_BAD_SECTION_RVA (-5612) +%define VERR_SUP_VP_BAD_SECTION_VIRTUAL_SIZE (-5613) +%define VERR_SUP_VP_BAD_SIZE_OF_HEADERS (-5614) +%define VERR_SUP_VP_DEBUGGED (-5615) +%define VERR_SUP_VP_DUPLICATE_DLL_MAPPING (-5616) +%define VERR_SUP_VP_EMPTY_REGION_TOO_LARGE (-5617) +%define VERR_SUP_VP_EXE_VS_PROC_NAME_MISMATCH (-5618) +%define VERR_SUP_VP_FOUND_EXEC_MEMORY (-5619) +%define VERR_SUP_VP_FOUND_MORE_THAN_ONE_EXE_MAPPING (-5620) +%define VERR_SUP_VP_IMAGE_FILE_CLOSE_ERROR (-5621) +%define VERR_SUP_VP_IMAGE_FILE_OPEN_ERROR (-5622) +%define VERR_SUP_VP_IMAGE_HDR_READ_ERROR (-5623) +%define VERR_SUP_VP_IMAGE_MAPPING_BASE_ERROR (-5624) +%define VERR_SUP_VP_MEMORY_READ_ERROR (-5625) +%define VERR_SUP_VP_NO_FOUND_NO_EXE_MAPPING (-5626) +%define VERR_SUP_VP_NO_IMAGE_MAPPING_NAME (-5627) +%define VERR_SUP_VP_NO_KERNEL32_MAPPING (-5628) +%define VERR_SUP_VP_NO_MEMORY (-5629) +%define VERR_SUP_VP_NO_MEMORY_STATE (-5630) +%define VERR_SUP_VP_NO_NTDLL_MAPPING (-5631) +%define VERR_SUP_VP_NON_SYSTEM32_DLL (-5632) +%define VERR_SUP_VP_NOT_KNOWN_DLL_OR_EXE (-5633) +%define VERR_SUP_VP_NT_MAPPING_NAME_CHANGED (-5634) +%define VERR_SUP_VP_NT_QI_PROCESS_NM_ERROR (-5635) +%define VERR_SUP_VP_NT_QI_THREAD_ERROR (-5636) +%define VERR_SUP_VP_NT_QI_VIRTUAL_MEMORY_ERROR (-5637) +%define VERR_SUP_VP_NT_QI_VIRTUAL_MEMORY_NM_ERROR (-5638) +%define VERR_SUP_VP_SYSTEM32_PATH (-5639) +%define VERR_SUP_VP_THREAD_NOT_ALONE (-5640) +%define VERR_SUP_VP_TOO_HIGH_REGION_RVA (-5641) +%define VERR_SUP_VP_TOO_LARGE_REGION (-5642) +%define VERR_SUP_VP_TOO_MANY_DLLS_LOADED (-5643) +%define VERR_SUP_VP_TOO_MANY_IMAGE_REGIONS (-5644) +%define VERR_SUP_VP_TOO_MANY_MEMORY_REGIONS (-5645) +%define VERR_SUP_VP_TOO_MANY_SECTIONS (-5646) +%define VERR_SUP_VP_UNEXPECTED_IMAGE_MACHINE (-5647) +%define VERR_SUP_VP_UNEXPECTED_SECTION_FLAGS (-5648) +%define VERR_SUP_VP_EXE_MISSING_FORCE_INTEGRITY (-5649) +%define VERR_SUP_VP_EXE_MISSING_DYNAMIC_BASE (-5650) +%define VERR_SUP_VP_EXE_MISSING_NX_COMPAT (-5651) +%define VERR_SUP_VP_DLL_CHARECTERISTICS_MISMATCH (-5652) +%define VERR_SUP_VP_IMAGE_CHARECTERISTICS_MISMATCH (-5653) +%define VERR_SUP_VP_NT_QI_PROCESS_IMG_INFO_ERROR (-5654) +%define VERR_SUP_VP_NT_QI_PROCESS_DBG_PORT_ERROR (-5655) +%define VERR_SUP_VP_WINTRUST_CAT_FAILURE (-5656) +%define VERR_SUP_VP_NOT_SIGNED_WITH_BUILD_CERT (-5657) +%define VERR_SUP_VP_NOT_BUILD_CERT_IPE (-5658) +%define VERR_SUP_VP_NOT_VALID_KERNEL_CODE_SIGNATURE (-5659) +%define VERR_SUP_VP_UNEXPECTED_VALID_PATH_COUNT (-5660) +%define VERR_SUP_VP_SIGNATURE_CHECKS_NOT_ENFORCED (-5661) +%define VERR_SUP_VP_SYSFER_DLL (-5662) +%define VERR_SUP_VP_KERNEL32_ALREADY_MAPPED (-5663) +%define VERR_SUP_VP_FREE_VIRTUAL_MEMORY_FAILED (-5664) +%define VERR_SUP_VP_UNMAP_AND_PROTECT_FAILED (-5665) +%define VERR_SUP_VP_UNKOWN_MEM_TYPE (-5666) +%define VERR_SUP_VP_NOT_OWNED_BY_TRUSTED_INSTALLER (-5667) +%define VERR_SUP_VP_IMAGE_TOO_BIG (-5668) +%define VERR_SUP_VP_STUB_NOT_FOUND (-5669) +%define VERR_SUP_VP_STUB_OPEN_ERROR (-5670) +%define VERR_SUP_VP_STUB_THREAD_NOT_FOUND (-5671) +%define VERR_SUP_VP_STUB_THREAD_OPEN_ERROR (-5672) +%define VERR_SUP_VP_REPLACE_VIRTUAL_MEMORY_FAILED (-5673) +%define VERR_SUP_VP_FILE_MODE_ERROR (-5674) +%define VERR_SUP_VP_CREATE_READ_EVT_SEM_FAILED (-5675) +%define VERR_SUP_VP_UNDESIRABLE_MODULE (-5676) +%define VERR_SUP_DRIVERLESS (-5699) +%define VINF_SUP_DRIVERLESS 5699 +%define VERR_EXTPACK_UNSUPPORTED_HOST_UNINSTALL (-6000) +%define VERR_EXTPACK_VBOX_VERSION_MISMATCH (-6001) +%define VERR_GSTCTL_GUEST_ERROR (-6200) +%define VWRN_GSTCTL_OBJECTSTATE_CHANGED 6220 +%define VERR_GSTCTL_PROCESS_WRONG_STATE (-6221) +%define VERR_GSTCTL_MAX_CID_SESSIONS_REACHED (-6222) +%define VERR_GSTCTL_MAX_CID_OBJECTS_REACHED (-6223) +%define VERR_GSTCTL_MAX_CID_COUNT_REACHED (-6224) +%define VERR_GSTCTL_PROCESS_EXIT_CODE (-6225) +%define VERR_GIM_NOT_ENABLED (-6300) +%define VERR_GIM_IPE_1 (-6301) +%define VERR_GIM_IPE_2 (-6302) +%define VERR_GIM_IPE_3 (-6303) +%define VERR_GIM_PVTSC_NOT_AVAILABLE (-6304) +%define VERR_GIM_PVTSC_NOT_ENABLED (-6305) +%define VERR_GIM_INVALID_PROVIDER (-6306) +%define VERR_GIM_OPERATION_FAILED (-6307) +%define VERR_GIM_HYPERCALLS_NOT_AVAILABLE (-6308) +%define VERR_GIM_HYPERCALLS_NOT_ENABLED (-6309) +%define VERR_GIM_DEVICE_NOT_REGISTERED (-6310) +%define VERR_GIM_HYPERCALL_ACCESS_DENIED (-6311) +%define VERR_GIM_HYPERCALL_MEMORY_READ_FAILED (-6312) +%define VERR_GIM_HYPERCALL_MEMORY_WRITE_FAILED (-6313) +%define VERR_GIM_HYPERCALL_FAILED (-6314) +%define VERR_GIM_NO_DEBUG_CONNECTION (-6315) +%define VINF_GIM_R3_HYPERCALL 6316 +%define VINF_GIM_HYPERCALL_CONTINUING 6317 +%define VERR_GIM_INVALID_HYPERCALL_INSTR (-6318) +%define VERR_MAIN_CONFIG_CONSTRUCTOR_COM_ERROR (-6400) +%define VERR_MAIN_CONFIG_CONSTRUCTOR_IPE (-6401) +%define VERR_GSTDND_GUEST_ERROR (-6500) +%define VERR_AUDIO_BACKEND_INIT_FAILED (-6600) +%define VERR_AUDIO_BACKEND_NOT_ATTACHED (-6601) +%define VERR_AUDIO_NO_FREE_INPUT_STREAMS (-6602) +%define VERR_AUDIO_NO_FREE_OUTPUT_STREAMS (-6603) +%define VERR_AUDIO_STREAM_PENDING_DISABLE (-6604) +%define VINF_AUDIO_MORE_DATA_AVAILABLE (6605) +%define VERR_AUDIO_STREAM_NOT_READY (-6605) +%define VERR_AUDIO_STREAM_COULD_NOT_CREATE (-6606) +%define VERR_AUDIO_ENUMERATION_FAILED (-6607) +%define VERR_AUDIO_STREAM_INIT_IN_PROGRESS (-6608) +%define VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED (6609) +%define VERR_APIC_INTR_NOT_PENDING (-6700) +%define VERR_APIC_INTR_MASKED_BY_TPR (-6701) +%define VERR_APIC_INTR_DISCARDED (-6702) +%define VERR_NEM_NOT_ENABLED (-6800) +%define VERR_NEM_NOT_AVAILABLE (-6801) +%define VERR_NEM_INIT_FAILED (-6802) +%define VERR_NEM_MISSING_KERNEL_API_1 (-6803) +%define VERR_NEM_RING3_ONLY (-6804) +%define VERR_NEM_VM_CREATE_FAILED (-6805) +%define VERR_NEM_MAP_PAGES_FAILED (-6806) +%define VERR_NEM_UNMAP_PAGES_FAILED (-6807) +%define VERR_NEM_GET_REGISTERS_FAILED (-6808) +%define VERR_NEM_SET_REGISTERS_FAILED (-6809) +%define VERR_NEM_FLUSH_TLB (-6810) +%define VINF_NEM_FLUSH_TLB (6810) +%define VERR_NEM_SET_TSC (-6811) +%define VERR_NEM_MISSING_KERNEL_API_2 (-6812) +%define VERR_NEM_MISSING_KERNEL_API_3 (-6813) +%define VERR_NEM_MISSING_KERNEL_API_4 (-6814) +%define VERR_NEM_MISSING_KERNEL_API_5 (-6815) +%define VERR_NEM_QUERY_DIRTY_BITMAP_FAILED (-6816) +%define VERR_NEM_MISSING_FEATURE (-6817) +%define VERR_NEM_IPE_0 (-6890) +%define VERR_NEM_IPE_1 (-6891) +%define VERR_NEM_IPE_2 (-6892) +%define VERR_NEM_IPE_3 (-6893) +%define VERR_NEM_IPE_4 (-6894) +%define VERR_NEM_IPE_5 (-6895) +%define VERR_NEM_IPE_6 (-6896) +%define VERR_NEM_IPE_7 (-6897) +%define VERR_NEM_IPE_8 (-6898) +%define VERR_NEM_IPE_9 (-6899) +%define VERR_RECORDING_CODEC_NOT_FOUND (-6900) +%define VERR_RECORDING_CODEC_INIT_FAILED (-6902) +%define VERR_RECORDING_CODEC_NOT_SUPPORTED (-6903) +%define VERR_RECORDING_FORMAT_NOT_SUPPORTED (-6904) +%define VERR_RECORDING_RESTRICTED (-6905) +%define VINF_RECORDING_LIMIT_REACHED (6906) +%define VERR_RECORDING_LIMIT_REACHED (-6906) +%define VINF_RECORDING_THROTTLED (6907) +%define VERR_RECORDING_THROTTLED (-6907) +%define VERR_RECORDING_ENCODING_FAILED (-6908) +%define VERR_SHCLPB_MAX_TRANSFERS_REACHED (-7100) +%define VERR_SHCLPB_MAX_OBJECTS_REACHED (-7101) +%define VERR_SHCLPB_MAX_LISTS_REACHED (-7102) +%define VERR_SHCLPB_LIST_HANDLE_INVALID (-7103) +%define VERR_SHCLPB_OBJ_HANDLE_INVALID (-7104) +%define VERR_SHCLPB_EVENT_ID_NOT_FOUND (-7105) +%define VERR_SHCLPB_MAX_EVENTS_REACHED (-7106) +%define VERR_SHCLPB_TRANSFER_ID_NOT_FOUND (-7150) +%define VERR_IOMMU_DTE_READ_FAILED (-7300) +%define VERR_IOMMU_DTE_BAD_OFFSET (-7301) +%define VERR_IOMMU_ADDR_TRANSLATION_FAILED (-7302) +%define VERR_IOMMU_ADDR_ACCESS_DENIED (-7303) +%define VERR_IOMMU_INTR_REMAP_FAILED (-7304) +%define VERR_IOMMU_INTR_REMAP_DENIED (-7305) +%define VERR_IOMMU_CMD_NOT_SUPPORTED (-7306) +%define VERR_IOMMU_CMD_INVALID_FORMAT (-7307) +%define VERR_IOMMU_CMD_HW_ERROR (-7308) +%define VERR_IOMMU_NOT_PRESENT (-7309) +%define VERR_IOMMU_CANNOT_CALL_SELF (-7310) +%define VINF_IOMMU_ADDR_TRANSLATION_DISABLED 7311 +%define VERR_IOMMU_IPE_0 (-7390) +%define VERR_IOMMU_IPE_1 (-7391) +%define VERR_IOMMU_IPE_2 (-7392) +%define VERR_IOMMU_IPE_3 (-7393) +%define VERR_IOMMU_IPE_4 (-7394) +%define VERR_IOMMU_IPE_5 (-7395) +%define VERR_IOMMU_IPE_6 (-7396) +%define VERR_IOMMU_IPE_7 (-7397) +%define VERR_IOMMU_IPE_8 (-7398) +%define VERR_IOMMU_IPE_9 (-7399) +%include "iprt/err.mac" diff --git a/include/VBox/err.sed b/include/VBox/err.sed new file mode 100644 index 00000000..3d659927 --- /dev/null +++ b/include/VBox/err.sed @@ -0,0 +1,66 @@ +## @file +# SED script for converting VBox/err.h to .mac. +# + +# +# Copyright (C) 2006-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +# in the VirtualBox distribution, in which case the provisions of the +# CDDL are applicable instead of those of the GPL. +# +# You may elect to license modified versions of this file under the +# terms and conditions of either the GPL or the CDDL or both. +# +# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +# + +# Pass thru the file header and copyright. +1,/^\#ifndef/{ +/^\#ifndef/b next +s/^[/ ]// +s/^\*\//;/ +s/\*/;/g +3s/^.*$/;\n; Automatically generated by err.sed. DO NOT EDIT!\n;/ +b end +} +:next + +# Handle text inside the markers. +/SED-START/,/SED-END/{ + +# if (#define) goto defines +/^[[:space:]]*#[[:space:]]*define/b defines + +} + +# Everything else is deleted! +d +b end + +## +# Convert the defines +:defines +s/^[[:space:]]*#[[:space:]]*define[[:space:]]*\([[:alnum:]_]*\)[[:space:]]*\(.*\)[[:space:]]*$/%define \1 \2/ +b end + +# next expression +:end diff --git a/include/VBox/hgcmsvc.h b/include/VBox/hgcmsvc.h new file mode 100644 index 00000000..eba36f40 --- /dev/null +++ b/include/VBox/hgcmsvc.h @@ -0,0 +1,745 @@ +/** @file + * Host-Guest Communication Manager (HGCM) - Service library definitions. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_hgcmsvc_h +#define VBOX_INCLUDED_hgcmsvc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#ifdef IN_RING3 +# include +# include +# include +# include +# include +#endif +#ifdef VBOX_TEST_HGCM_PARMS +# include +#endif + +/** @todo proper comments. */ + +/** + * Service interface version. + * + * Includes layout of both VBOXHGCMSVCFNTABLE and VBOXHGCMSVCHELPERS. + * + * A service can work with these structures if major version + * is equal and minor version of service is <= version of the + * structures. + * + * For example when a new helper is added at the end of helpers + * structure, then the minor version will be increased. All older + * services still can work because they have their old helpers + * unchanged. + * + * Revision history. + * 1.1->2.1 Because the pfnConnect now also has the pvClient parameter. + * 2.1->2.2 Because pfnSaveState and pfnLoadState were added + * 2.2->3.1 Because pfnHostCall is now synchronous, returns rc, and parameters were changed + * 3.1->3.2 Because pfnRegisterExtension was added + * 3.2->3.3 Because pfnDisconnectClient helper was added + * 3.3->4.1 Because the pvService entry and parameter was added + * 4.1->4.2 Because the VBOX_HGCM_SVC_PARM_CALLBACK parameter type was added + * 4.2->5.1 Removed the VBOX_HGCM_SVC_PARM_CALLBACK parameter type, as + * this problem is already solved by service extension callbacks + * 5.1->6.1 Because pfnCall got a new parameter. Also new helpers. (VBox 6.0) + * 6.1->6.2 Because pfnCallComplete starts returning a status code (VBox 6.0). + * 6.2->6.3 Because pfnGetRequestor was added (VBox 6.0). + * 6.3->6.4 Because pfnConnect got an additional parameter (VBox 6.0). + * 6.4->6.5 Because pfnGetVMMDevSessionId was added pfnLoadState got the version + * parameter (VBox 6.0). + * 6.5->7.1 Because pfnNotify was added (VBox 6.0). + * 7.1->8.1 Because pfnCancelled & pfnIsCallCancelled were added (VBox 6.0). + * 8.1->9.1 Because pfnDisconnectClient was (temporarily) removed, and + * acMaxClients and acMaxCallsPerClient added (VBox 6.1.26). + * 9.1->10.1 Because pfnDisconnectClient was added back (VBox 6.1.28). + * 10.1->11.1 Because pVMM added to pfnSaveState & pfnLoadState (VBox 7.0). + */ +#define VBOX_HGCM_SVC_VERSION_MAJOR (0x000b) +#define VBOX_HGCM_SVC_VERSION_MINOR (0x0001) +#define VBOX_HGCM_SVC_VERSION ((VBOX_HGCM_SVC_VERSION_MAJOR << 16) + VBOX_HGCM_SVC_VERSION_MINOR) + + +/** Typed pointer to distinguish a call to service. */ +struct VBOXHGCMCALLHANDLE_TYPEDEF; +typedef struct VBOXHGCMCALLHANDLE_TYPEDEF *VBOXHGCMCALLHANDLE; + +/** Service helpers pointers table. */ +typedef struct VBOXHGCMSVCHELPERS +{ + /** The service has processed the Call request. */ + DECLR3CALLBACKMEMBER(int, pfnCallComplete, (VBOXHGCMCALLHANDLE callHandle, int32_t rc)); + + void *pvInstance; + + /** + * The service disconnects the client. + * + * This can only be used during VBOXHGCMSVCFNTABLE::pfnConnect or + * VBOXHGCMSVCFNTABLE::pfnDisconnect and will fail if called out side that + * context. Using this on the new client during VBOXHGCMSVCFNTABLE::pfnConnect + * is not advisable, it would be better to just return a failure status for that + * and it will be done automatically. (It is not possible to call this method + * on a client passed to VBOXHGCMSVCFNTABLE::pfnDisconnect.) + * + * There will be no VBOXHGCMSVCFNTABLE::pfnDisconnect callback for a client + * disconnected in this manner. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the client ID was not found. + * @retval VERR_INVALID_CONTEXT if not called during connect or disconnect. + * + * @remarks Used by external parties, so don't remove just because we don't use + * it ourselves. + */ + DECLR3CALLBACKMEMBER(int, pfnDisconnectClient, (void *pvInstance, uint32_t idClient)); + + /** + * Check if the @a callHandle is for a call restored and re-submitted from saved state. + * + * @returns true if restored, false if not. + * @param callHandle The call we're checking up on. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsCallRestored, (VBOXHGCMCALLHANDLE callHandle)); + + /** + * Check if the @a callHandle is for a cancelled call. + * + * @returns true if cancelled, false if not. + * @param callHandle The call we're checking up on. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsCallCancelled, (VBOXHGCMCALLHANDLE callHandle)); + + /** Access to STAMR3RegisterV. */ + DECLR3CALLBACKMEMBER(int, pfnStamRegisterV,(void *pvInstance, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va) + RT_IPRT_FORMAT_ATTR(7, 0)); + /** Access to STAMR3DeregisterV. */ + DECLR3CALLBACKMEMBER(int, pfnStamDeregisterV,(void *pvInstance, const char *pszPatFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0)); + + /** Access to DBGFR3InfoRegisterExternal. */ + DECLR3CALLBACKMEMBER(int, pfnInfoRegister,(void *pvInstance, const char *pszName, const char *pszDesc, + PFNDBGFHANDLEREXT pfnHandler, void *pvUser)); + /** Access to DBGFR3InfoDeregisterExternal. */ + DECLR3CALLBACKMEMBER(int, pfnInfoDeregister,(void *pvInstance, const char *pszName)); + + /** + * Retrieves the VMMDevRequestHeader::fRequestor value. + * + * @returns The field value, VMMDEV_REQUESTOR_LEGACY if not supported by the + * guest, VMMDEV_REQUESTOR_LOWEST if invalid call. + * @param hCall The call we're checking up on. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetRequestor, (VBOXHGCMCALLHANDLE hCall)); + + /** + * Retrieves VMMDevState::idSession. + * + * @returns current VMMDev session ID value. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetVMMDevSessionId, (void *pvInstance)); + +} VBOXHGCMSVCHELPERS; + +typedef VBOXHGCMSVCHELPERS *PVBOXHGCMSVCHELPERS; + +#if defined(IN_RING3) || defined(IN_SLICKEDIT) + +/** Wrapper around STAMR3RegisterF. */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(7, 8) +HGCMSvcHlpStamRegister(PVBOXHGCMSVCHELPERS pHlp, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, const char *pszName, ...) +{ + int rc; + va_list va; + va_start(va, pszName); + rc = pHlp->pfnStamRegisterV(pHlp->pvInstance, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va); + va_end(va); + return rc; +} + +/** Wrapper around STAMR3RegisterV. */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(7, 0) +HGCMSvcHlpStamRegisterV(PVBOXHGCMSVCHELPERS pHlp, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, const char *pszName, va_list va) +{ + return pHlp->pfnStamRegisterV(pHlp->pvInstance, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va); +} + +/** Wrapper around STAMR3DeregisterF. */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(2, 3) HGCMSvcHlpStamDeregister(PVBOXHGCMSVCHELPERS pHlp, const char *pszPatFmt, ...) +{ + int rc; + va_list va; + va_start(va, pszPatFmt); + rc = pHlp->pfnStamDeregisterV(pHlp->pvInstance, pszPatFmt, va); + va_end(va); + return rc; +} + +/** Wrapper around STAMR3DeregisterV. */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(2, 0) HGCMSvcHlpStamDeregisterV(PVBOXHGCMSVCHELPERS pHlp, const char *pszPatFmt, va_list va) +{ + return pHlp->pfnStamDeregisterV(pHlp->pvInstance, pszPatFmt, va); +} + +/** Wrapper around DBGFR3InfoRegisterExternal. */ +DECLINLINE(int) HGCMSvcHlpInfoRegister(PVBOXHGCMSVCHELPERS pHlp, const char *pszName, const char *pszDesc, + PFNDBGFHANDLEREXT pfnHandler, void *pvUser) +{ + return pHlp->pfnInfoRegister(pHlp->pvInstance, pszName, pszDesc, pfnHandler, pvUser); +} + +/** Wrapper around DBGFR3InfoDeregisterExternal. */ +DECLINLINE(int) HGCMSvcHlpInfoDeregister(PVBOXHGCMSVCHELPERS pHlp, const char *pszName) +{ + return pHlp->pfnInfoDeregister(pHlp->pvInstance, pszName); +} + +#endif /* IN_RING3 */ + + +#define VBOX_HGCM_SVC_PARM_INVALID (0U) +#define VBOX_HGCM_SVC_PARM_32BIT (1U) +#define VBOX_HGCM_SVC_PARM_64BIT (2U) +#define VBOX_HGCM_SVC_PARM_PTR (3U) +#define VBOX_HGCM_SVC_PARM_PAGES (4U) + +/** VBOX_HGCM_SVC_PARM_PAGES specific data. */ +typedef struct VBOXHGCMSVCPARMPAGES +{ + uint32_t cb; + uint16_t cPages; + uint16_t u16Padding; + void **papvPages; +} VBOXHGCMSVCPARMPAGES; +typedef VBOXHGCMSVCPARMPAGES *PVBOXHGCMSVCPARMPAGES; + +typedef struct VBOXHGCMSVCPARM +{ + /** VBOX_HGCM_SVC_PARM_* values. */ + uint32_t type; + + union + { + uint32_t uint32; + uint64_t uint64; + struct + { + uint32_t size; + void *addr; + } pointer; + /** VBOX_HGCM_SVC_PARM_PAGES */ + VBOXHGCMSVCPARMPAGES Pages; + } u; +} VBOXHGCMSVCPARM; + +/** Extract an uint32_t value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetU32(VBOXHGCMSVCPARM *pParm, uint32_t *pu32) +{ + int rc = VINF_SUCCESS; + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(pu32, VERR_INVALID_POINTER); + if (pParm->type != VBOX_HGCM_SVC_PARM_32BIT) + rc = VERR_INVALID_PARAMETER; + if (RT_SUCCESS(rc)) + *pu32 = pParm->u.uint32; + return rc; +} + +/** Extract an uint64_t value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetU64(VBOXHGCMSVCPARM *pParm, uint64_t *pu64) +{ + int rc = VINF_SUCCESS; + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(pu64, VERR_INVALID_POINTER); + if (pParm->type != VBOX_HGCM_SVC_PARM_64BIT) + rc = VERR_INVALID_PARAMETER; + if (RT_SUCCESS(rc)) + *pu64 = pParm->u.uint64; + return rc; +} + +/** Extract an pointer value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetPv(VBOXHGCMSVCPARM *pParm, void **ppv, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppv, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if (pParm->type == VBOX_HGCM_SVC_PARM_PTR) + { + *ppv = pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Extract a constant pointer value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetPcv(VBOXHGCMSVCPARM *pParm, const void **ppv, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppv, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if (pParm->type == VBOX_HGCM_SVC_PARM_PTR) + { + *ppv = (const void *)pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Extract a valid pointer to a non-empty buffer from an HGCM parameter + * structure. */ +DECLINLINE(int) HGCMSvcGetBuf(VBOXHGCMSVCPARM *pParm, void **ppv, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppv, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if ( pParm->type == VBOX_HGCM_SVC_PARM_PTR + && RT_VALID_PTR(pParm->u.pointer.addr) + && pParm->u.pointer.size > 0) + { + *ppv = pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Extract a valid pointer to a non-empty constant buffer from an HGCM + * parameter structure. */ +DECLINLINE(int) HGCMSvcGetCBuf(VBOXHGCMSVCPARM *pParm, const void **ppv, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppv, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if ( pParm->type == VBOX_HGCM_SVC_PARM_PTR + && RT_VALID_PTR(pParm->u.pointer.addr) + && pParm->u.pointer.size > 0) + { + *ppv = (const void *)pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Extract a string value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetStr(VBOXHGCMSVCPARM *pParm, char **ppch, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppch, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if ( pParm->type == VBOX_HGCM_SVC_PARM_PTR + && RT_VALID_PTR(pParm->u.pointer.addr) + && pParm->u.pointer.size > 0) + { + int rc = RTStrValidateEncodingEx((char *)pParm->u.pointer.addr, + pParm->u.pointer.size, + RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); + if (RT_FAILURE(rc)) + return rc; + *ppch = (char *)pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Extract a constant string value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetCStr(VBOXHGCMSVCPARM *pParm, const char **ppch, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppch, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if ( pParm->type == VBOX_HGCM_SVC_PARM_PTR + && RT_VALID_PTR(pParm->u.pointer.addr) + && pParm->u.pointer.size > 0) + { + int rc = RTStrValidateEncodingEx((char *)pParm->u.pointer.addr, + pParm->u.pointer.size, + RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); + if (RT_FAILURE(rc)) + return rc; + *ppch = (char *)pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Extract a constant string value from an HGCM parameter structure. */ +DECLINLINE(int) HGCMSvcGetPsz(VBOXHGCMSVCPARM *pParm, const char **ppch, uint32_t *pcb) +{ + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(ppch, VERR_INVALID_POINTER); + AssertPtrReturn(pcb, VERR_INVALID_POINTER); + if ( pParm->type == VBOX_HGCM_SVC_PARM_PTR + && RT_VALID_PTR(pParm->u.pointer.addr) + && pParm->u.pointer.size > 0) + { + int rc = RTStrValidateEncodingEx((const char *)pParm->u.pointer.addr, + pParm->u.pointer.size, + RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); + if (RT_FAILURE(rc)) + return rc; + *ppch = (const char *)pParm->u.pointer.addr; + *pcb = pParm->u.pointer.size; + return VINF_SUCCESS; + } + + return VERR_INVALID_PARAMETER; +} + +/** Set a uint32_t value to an HGCM parameter structure */ +DECLINLINE(void) HGCMSvcSetU32(VBOXHGCMSVCPARM *pParm, uint32_t u32) +{ + AssertPtr(pParm); + pParm->type = VBOX_HGCM_SVC_PARM_32BIT; + pParm->u.uint32 = u32; +} + +/** Set a uint64_t value to an HGCM parameter structure */ +DECLINLINE(void) HGCMSvcSetU64(VBOXHGCMSVCPARM *pParm, uint64_t u64) +{ + AssertPtr(pParm); + pParm->type = VBOX_HGCM_SVC_PARM_64BIT; + pParm->u.uint64 = u64; +} + +/** Set a pointer value to an HGCM parameter structure */ +DECLINLINE(void) HGCMSvcSetPv(VBOXHGCMSVCPARM *pParm, void *pv, uint32_t cb) +{ + AssertPtr(pParm); + pParm->type = VBOX_HGCM_SVC_PARM_PTR; + pParm->u.pointer.addr = pv; + pParm->u.pointer.size = cb; +} + +/** Set a pointer value to an HGCM parameter structure */ +DECLINLINE(void) HGCMSvcSetStr(VBOXHGCMSVCPARM *pParm, const char *psz) +{ + AssertPtr(pParm); + pParm->type = VBOX_HGCM_SVC_PARM_PTR; + pParm->u.pointer.addr = (void *)psz; + pParm->u.pointer.size = (uint32_t)strlen(psz) + 1; +} + +#ifdef __cplusplus +# ifdef IPRT_INCLUDED_cpp_ministring_h +/** Set a const string value to an HGCM parameter structure */ +DECLINLINE(void) HGCMSvcSetRTCStr(VBOXHGCMSVCPARM *pParm, const RTCString &rString) +{ + AssertPtr(pParm); + pParm->type = VBOX_HGCM_SVC_PARM_PTR; + pParm->u.pointer.addr = (void *)rString.c_str(); + pParm->u.pointer.size = (uint32_t)rString.length() + 1; +} +# endif +#endif + +#if defined(IN_RING3) && defined(VBOX_INCLUDED_vmm_vmmr3vtable_h) + +/** + * Puts (serializes) a VBOXHGCMSVCPARM struct into SSM. + * + * @returns VBox status code. + * @param pParm VBOXHGCMSVCPARM to serialize. + * @param pSSM SSM handle to serialize to. + * @param pVMM The VMM vtable. + */ +DECLINLINE(int) HGCMSvcSSMR3Put(VBOXHGCMSVCPARM *pParm, PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM) +{ + int rc; + + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(pSSM, VERR_INVALID_POINTER); + + rc = pVMM->pfnSSMR3PutU32(pSSM, sizeof(VBOXHGCMSVCPARM)); + AssertRCReturn(rc, rc); + rc = pVMM->pfnSSMR3PutU32(pSSM, pParm->type); + AssertRCReturn(rc, rc); + + switch (pParm->type) + { + case VBOX_HGCM_SVC_PARM_32BIT: + rc = pVMM->pfnSSMR3PutU32(pSSM, pParm->u.uint32); + break; + case VBOX_HGCM_SVC_PARM_64BIT: + rc = pVMM->pfnSSMR3PutU64(pSSM, pParm->u.uint64); + break; + case VBOX_HGCM_SVC_PARM_PTR: + rc = pVMM->pfnSSMR3PutU32(pSSM, pParm->u.pointer.size); + if (RT_SUCCESS(rc)) + rc = pVMM->pfnSSMR3PutMem(pSSM, pParm->u.pointer.addr, pParm->u.pointer.size); + break; + default: + AssertMsgFailed(("Paramter type %RU32 not implemented yet\n", pParm->type)); + rc = VERR_NOT_IMPLEMENTED; + break; + } + + return rc; +} + +/** + * Gets (loads) a VBOXHGCMSVCPARM struct from SSM. + * + * @returns VBox status code. + * @param pParm VBOXHGCMSVCPARM to load into. Must be zero'ed. + * @param pSSM SSM handle to load from. + * @param pVMM The VMM vtable. + */ +DECLINLINE(int) HGCMSvcSSMR3Get(VBOXHGCMSVCPARM *pParm, PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM) +{ + uint32_t cbParm; + int rc; + + AssertPtrReturn(pParm, VERR_INVALID_POINTER); + AssertPtrReturn(pSSM, VERR_INVALID_POINTER); + + rc = pVMM->pfnSSMR3GetU32(pSSM, &cbParm); + AssertRCReturn(rc, rc); + AssertReturn(cbParm == sizeof(VBOXHGCMSVCPARM), VERR_SSM_DATA_UNIT_FORMAT_CHANGED); + + rc = pVMM->pfnSSMR3GetU32(pSSM, &pParm->type); + AssertRCReturn(rc, rc); + + switch (pParm->type) + { + case VBOX_HGCM_SVC_PARM_32BIT: + { + rc = pVMM->pfnSSMR3GetU32(pSSM, &pParm->u.uint32); + AssertRCReturn(rc, rc); + break; + } + + case VBOX_HGCM_SVC_PARM_64BIT: + { + rc = pVMM->pfnSSMR3GetU64(pSSM, &pParm->u.uint64); + AssertRCReturn(rc, rc); + break; + } + + case VBOX_HGCM_SVC_PARM_PTR: + { + AssertMsgReturn(pParm->u.pointer.size == 0, + ("Pointer size parameter already in use (or not initialized)\n"), VERR_INVALID_PARAMETER); + + rc = pVMM->pfnSSMR3GetU32(pSSM, &pParm->u.pointer.size); + AssertRCReturn(rc, rc); + + AssertMsgReturn(pParm->u.pointer.addr == NULL, + ("Pointer parameter already in use (or not initialized)\n"), VERR_INVALID_PARAMETER); + + pParm->u.pointer.addr = RTMemAlloc(pParm->u.pointer.size); + AssertPtrReturn(pParm->u.pointer.addr, VERR_NO_MEMORY); + rc = pVMM->pfnSSMR3GetMem(pSSM, pParm->u.pointer.addr, pParm->u.pointer.size); + + AssertRCReturn(rc, rc); + break; + } + + default: + AssertMsgFailedReturn(("Paramter type %RU32 not implemented yet\n", pParm->type), + VERR_NOT_IMPLEMENTED); + break; + } + + return VINF_SUCCESS; +} + +#endif /* IN_RING3 */ + +typedef VBOXHGCMSVCPARM *PVBOXHGCMSVCPARM; + + +/** Service specific extension callback. + * This callback is called by the service to perform service specific operation. + * + * @param pvExtension The extension pointer. + * @param u32Function What the callback is supposed to do. + * @param pvParm The function parameters. + * @param cbParms The size of the function parameters. + */ +typedef DECLCALLBACKTYPE(int, FNHGCMSVCEXT,(void *pvExtension, uint32_t u32Function, void *pvParm, uint32_t cbParms)); +typedef FNHGCMSVCEXT *PFNHGCMSVCEXT; + +/** + * Notification event. + */ +typedef enum HGCMNOTIFYEVENT +{ + HGCMNOTIFYEVENT_INVALID = 0, + HGCMNOTIFYEVENT_POWER_ON, + HGCMNOTIFYEVENT_RESUME, + HGCMNOTIFYEVENT_SUSPEND, + HGCMNOTIFYEVENT_RESET, + HGCMNOTIFYEVENT_POWER_OFF, + HGCMNOTIFYEVENT_END, + HGCMNOTIFYEVENT_32BIT_HACK = 0x7fffffff +} HGCMNOTIFYEVENT; + +/** @name HGCM_CLIENT_CATEGORY_XXX - Client categories + * @{ */ +#define HGCM_CLIENT_CATEGORY_KERNEL 0 /**< Guest kernel mode and legacy client. */ +#define HGCM_CLIENT_CATEGORY_ROOT 1 /**< Guest root or admin client. */ +#define HGCM_CLIENT_CATEGORY_USER 2 /**< Regular guest user client. */ +#define HGCM_CLIENT_CATEGORY_MAX 3 /**< Max number of categories. */ +/** @} */ + + +/** The Service DLL entry points. + * + * HGCM will call the DLL "VBoxHGCMSvcLoad" + * function and the DLL must fill in the VBOXHGCMSVCFNTABLE + * with function pointers. + * + * @note The structure is used in separately compiled binaries so an explicit + * packing is required. + */ +typedef struct VBOXHGCMSVCFNTABLE +{ + /** @name Filled by HGCM + * @{ */ + + /** Size of the structure. */ + uint32_t cbSize; + + /** Version of the structure, including the helpers. (VBOX_HGCM_SVC_VERSION) */ + uint32_t u32Version; + + PVBOXHGCMSVCHELPERS pHelpers; + /** @} */ + + /** @name Filled in by the service. + * @{ */ + + /** Size of client information the service want to have. */ + uint32_t cbClient; + + /** The maximum number of clients per category. Leave entries as zero for defaults. */ + uint32_t acMaxClients[HGCM_CLIENT_CATEGORY_MAX]; + /** The maximum number of concurrent calls per client for each category. + * Leave entries as as zero for default. */ + uint32_t acMaxCallsPerClient[HGCM_CLIENT_CATEGORY_MAX]; + /** The HGCM_CLIENT_CATEGORY_XXX value for legacy clients. + * Defaults to HGCM_CLIENT_CATEGORY_KERNEL. */ + uint32_t idxLegacyClientCategory; + + /** Uninitialize service */ + DECLR3CALLBACKMEMBER(int, pfnUnload, (void *pvService)); + + /** Inform the service about a client connection. */ + DECLR3CALLBACKMEMBER(int, pfnConnect, (void *pvService, uint32_t u32ClientID, void *pvClient, uint32_t fRequestor, bool fRestoring)); + + /** Inform the service that the client wants to disconnect. */ + DECLR3CALLBACKMEMBER(int, pfnDisconnect, (void *pvService, uint32_t u32ClientID, void *pvClient)); + + /** Service entry point. + * Return code is passed to pfnCallComplete callback. + */ + DECLR3CALLBACKMEMBER(void, pfnCall, (void *pvService, VBOXHGCMCALLHANDLE callHandle, uint32_t u32ClientID, void *pvClient, + uint32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[], uint64_t tsArrival)); + /** Informs the service that a call was cancelled by the guest (optional). + * + * This is called for guest calls, connect requests and disconnect requests. + * There is unfortunately no way of obtaining the call handle for a guest call + * or otherwise identify the request, so that's left to the service to figure + * out using VBOXHGCMSVCHELPERS::pfnIsCallCancelled. Because this is an + * asynchronous call, the service may have completed the request already. + */ + DECLR3CALLBACKMEMBER(void, pfnCancelled, (void *pvService, uint32_t idClient, void *pvClient)); + + /** Host Service entry point meant for privileged features invisible to the guest. + * Return code is passed to pfnCallComplete callback. + */ + DECLR3CALLBACKMEMBER(int, pfnHostCall, (void *pvService, uint32_t function, uint32_t cParms, VBOXHGCMSVCPARM paParms[])); + + /** Inform the service about a VM save operation. */ + DECLR3CALLBACKMEMBER(int, pfnSaveState, (void *pvService, uint32_t u32ClientID, void *pvClient, + PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM)); + + /** Inform the service about a VM load operation. */ + DECLR3CALLBACKMEMBER(int, pfnLoadState, (void *pvService, uint32_t u32ClientID, void *pvClient, + PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, uint32_t uVersion)); + + /** Register a service extension callback. */ + DECLR3CALLBACKMEMBER(int, pfnRegisterExtension, (void *pvService, PFNHGCMSVCEXT pfnExtension, void *pvExtension)); + + /** Notification (VM state). */ + DECLR3CALLBACKMEMBER(void, pfnNotify, (void *pvService, HGCMNOTIFYEVENT enmEvent)); + + /** User/instance data pointer for the service. */ + void *pvService; + + /** @} */ +} VBOXHGCMSVCFNTABLE; + + +/** @name HGCM saved state + * @note Need to be here so we can add saved to service which doesn't have it. + * @{ */ +/** HGCM saved state version. */ +#define HGCM_SAVED_STATE_VERSION 3 +/** HGCM saved state version w/o client state indicators. */ +#define HGCM_SAVED_STATE_VERSION_V2 2 +/** @} */ + + +/** Service initialization entry point. */ +typedef DECLCALLBACKTYPE(int, FNVBOXHGCMSVCLOAD,(VBOXHGCMSVCFNTABLE *ptable)); +typedef FNVBOXHGCMSVCLOAD *PFNVBOXHGCMSVCLOAD; +#define VBOX_HGCM_SVCLOAD_NAME "VBoxHGCMSvcLoad" + +#endif /* !VBOX_INCLUDED_hgcmsvc_h */ diff --git a/include/VBox/intnet.h b/include/VBox/intnet.h new file mode 100644 index 00000000..41ee508c --- /dev/null +++ b/include/VBox/intnet.h @@ -0,0 +1,1348 @@ +/** @file + * INTNET - Internal Networking. (DEV,++) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_intnet_h +#define VBOX_INCLUDED_intnet_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + + +/** The userspace internal network service identifier. */ +#if defined(RT_OS_DARWIN) && defined(VBOX_WITH_INTNET_SERVICE_IN_R3) +/** The XPC service identififer. */ +# define INTNET_R3_SVC_NAME "org.virtualbox.intnet" +/** The high 32 bits pattern for the "rc" status code field to recognize errors + * where xpc_dictionary_get_int64() might return 0 which could be confused with VINF_SUCCESS. */ +# define INTNET_R3_SVC_RC_PATTERN ((uint64_t)RT_MAKE_U32_FROM_U8('V', 'B', 'O', 'X')) +/** Constructs a signd 64bit value for the given 32-bit status code. */ +# define INTNET_R3_SVC_SET_RC(a_rc) ((INTNET_R3_SVC_RC_PATTERN << 32) | (uint64_t)(a_rc)) +/** Gets the status code from the given 64-bit signed status code value. */ +# define INTNET_R3_SVC_GET_RC(a_RcVal) ((int32_t)(a_RcVal)) +/** Checks whether the given 64-bit signed status code value encodes a valid IPRT/VBOX status code. */ +# define INTNET_R3_SVC_IS_VALID_RC(a_RcVal) (((a_RcVal) >> 32) == INTNET_R3_SVC_RC_PATTERN) +#endif + + +/** + * Generic two-sided ring buffer. + * + * The deal is that there is exactly one writer and one reader. + * When offRead equals offWrite the buffer is empty. In the other + * extreme the writer will not use the last free byte in the buffer. + */ +typedef struct INTNETRINGBUF +{ + /** The offset from this structure to the start of the buffer. */ + uint32_t offStart; + /** The offset from this structure to the end of the buffer. (exclusive). */ + uint32_t offEnd; + /** The current read offset. */ + uint32_t volatile offReadX; + /** Alignment. */ + uint32_t u32Align0; + + /** The committed write offset. */ + uint32_t volatile offWriteCom; + /** Writer internal current write offset. + * This is ahead of offWriteCom when buffer space is handed to a third party for + * data gathering. offWriteCom will be assigned this value by the writer then + * the frame is ready. */ + uint32_t volatile offWriteInt; + /** The number of bytes written (not counting overflows). */ + STAMCOUNTER cbStatWritten; + /** The number of frames written (not counting overflows). */ + STAMCOUNTER cStatFrames; + /** The number of overflows. */ + STAMCOUNTER cOverflows; +} INTNETRINGBUF; +AssertCompileSize(INTNETRINGBUF, 48); +/** Pointer to a ring buffer. */ +typedef INTNETRINGBUF *PINTNETRINGBUF; + +/** The alignment of a ring buffer. */ +#define INTNETRINGBUF_ALIGNMENT sizeof(INTNETHDR) + +/** + * Asserts the sanity of the specified INTNETRINGBUF structure. + */ +#ifdef VBOX_STRICT +# define INTNETRINGBUF_ASSERT_SANITY(pRingBuf) \ + do \ + { \ + AssertPtr(pRingBuf); \ + { \ + uint32_t const offWriteCom = (pRingBuf)->offWriteCom; \ + uint32_t const offRead = (pRingBuf)->offReadX; \ + uint32_t const offWriteInt = (pRingBuf)->offWriteInt; \ + \ + AssertMsg(offWriteCom == RT_ALIGN_32(offWriteCom, INTNETHDR_ALIGNMENT), ("%#x\n", offWriteCom)); \ + AssertMsg(offWriteCom >= (pRingBuf)->offStart, ("%#x %#x\n", offWriteCom, (pRingBuf)->offStart)); \ + AssertMsg(offWriteCom < (pRingBuf)->offEnd, ("%#x %#x\n", offWriteCom, (pRingBuf)->offEnd)); \ + \ + AssertMsg(offRead == RT_ALIGN_32(offRead, INTNETHDR_ALIGNMENT), ("%#x\n", offRead)); \ + AssertMsg(offRead >= (pRingBuf)->offStart, ("%#x %#x\n", offRead, (pRingBuf)->offStart)); \ + AssertMsg(offRead < (pRingBuf)->offEnd, ("%#x %#x\n", offRead, (pRingBuf)->offEnd)); \ + \ + AssertMsg(offWriteInt == RT_ALIGN_32(offWriteInt, INTNETHDR_ALIGNMENT), ("%#x\n", offWriteInt)); \ + AssertMsg(offWriteInt >= (pRingBuf)->offStart, ("%#x %#x\n", offWriteInt, (pRingBuf)->offStart)); \ + AssertMsg(offWriteInt < (pRingBuf)->offEnd, ("%#x %#x\n", offWriteInt, (pRingBuf)->offEnd)); \ + AssertMsg( offRead <= offWriteCom \ + ? offWriteCom <= offWriteInt || offWriteInt < offRead \ + : offWriteCom <= offWriteInt, \ + ("W=%#x W'=%#x R=%#x\n", offWriteCom, offWriteInt, offRead)); \ + } \ + } while (0) +#else +# define INTNETRINGBUF_ASSERT_SANITY(pRingBuf) do { } while (0) +#endif + + + +/** + * A interface buffer. + */ +typedef struct INTNETBUF +{ + /** Magic number (INTNETBUF_MAGIC). */ + uint32_t u32Magic; + /** The size of the entire buffer. */ + uint32_t cbBuf; + /** The size of the send area. */ + uint32_t cbSend; + /** The size of the receive area. */ + uint32_t cbRecv; + /** The receive buffer. */ + INTNETRINGBUF Recv; + /** The send buffer. */ + INTNETRINGBUF Send; + /** Number of times yields help solve an overflow. */ + STAMCOUNTER cStatYieldsOk; + /** Number of times yields didn't help solve an overflow. */ + STAMCOUNTER cStatYieldsNok; + /** Number of lost packets due to overflows. */ + STAMCOUNTER cStatLost; + /** Number of bad frames (both rings). */ + STAMCOUNTER cStatBadFrames; + /** Reserved for future use. */ + STAMCOUNTER aStatReserved[2]; + /** Reserved for future send profiling. */ + STAMPROFILE StatSend1; + /** Reserved for future send profiling. */ + STAMPROFILE StatSend2; + /** Reserved for future receive profiling. */ + STAMPROFILE StatRecv1; + /** Reserved for future receive profiling. */ + STAMPROFILE StatRecv2; + /** Reserved for future profiling. */ + STAMPROFILE StatReserved; +} INTNETBUF; +AssertCompileSize(INTNETBUF, 320); +AssertCompileMemberOffset(INTNETBUF, Recv, 16); +AssertCompileMemberOffset(INTNETBUF, Send, 64); + +/** Pointer to an interface buffer. */ +typedef INTNETBUF *PINTNETBUF; +/** Pointer to a const interface buffer. */ +typedef INTNETBUF const *PCINTNETBUF; + +/** Magic number for INTNETBUF::u32Magic (Sir William Gerald Golding). */ +#define INTNETBUF_MAGIC UINT32_C(0x19110919) + +/** + * Asserts the sanity of the specified INTNETBUF structure. + */ +#define INTNETBUF_ASSERT_SANITY(pBuf) \ + do \ + { \ + AssertPtr(pBuf); \ + Assert((pBuf)->u32Magic == INTNETBUF_MAGIC); \ + { \ + uint32_t const offRecvStart = (pBuf)->Recv.offStart + RT_UOFFSETOF(INTNETBUF, Recv); \ + uint32_t const offRecvEnd = (pBuf)->Recv.offStart + RT_UOFFSETOF(INTNETBUF, Recv); \ + uint32_t const offSendStart = (pBuf)->Send.offStart + RT_UOFFSETOF(INTNETBUF, Send); \ + uint32_t const offSendEnd = (pBuf)->Send.offStart + RT_UOFFSETOF(INTNETBUF, Send); \ + \ + Assert(offRecvEnd > offRecvStart); \ + Assert(offRecvEnd - offRecvStart == (pBuf)->cbRecv); \ + Assert(offRecvStart == sizeof(INTNETBUF)); \ + \ + Assert(offSendEnd > offSendStart); \ + Assert(offSendEnd - offSendStart == (pBuf)->cbSend); \ + Assert(pffSendEnd <= (pBuf)->cbBuf); \ + \ + Assert(offSendStart == offRecvEnd); \ + } \ + } while (0) + + +/** Internal networking interface handle. */ +typedef uint32_t INTNETIFHANDLE; +/** Pointer to an internal networking interface handle. */ +typedef INTNETIFHANDLE *PINTNETIFHANDLE; + +/** Or mask to obscure the handle index. */ +#define INTNET_HANDLE_MAGIC 0x88880000 +/** Mask to extract the handle index. */ +#define INTNET_HANDLE_INDEX_MASK 0xffff +/** The maximum number of handles (exclusive) */ +#define INTNET_HANDLE_MAX 0xffff +/** Invalid handle. */ +#define INTNET_HANDLE_INVALID (0) + + +/** + * The frame header. + * + * The header is intentionally 8 bytes long. It will always + * start at an 8 byte aligned address. Assuming that the buffer + * size is a multiple of 8 bytes, that means that we can guarantee + * that the entire header is contiguous in both virtual and physical + * memory. + */ +typedef struct INTNETHDR +{ + /** The size of the frame. */ + uint32_t cbFrame : 24; + /** Header type. This is currently serving as a magic, it + * can be extended later to encode special command frames and stuff. */ + uint32_t u8Type : 8; + /** The offset from the start of this header to where the actual frame starts. + * This is used to keep the frame it self contiguous in virtual memory and + * thereby both simplify access as well as the descriptor. */ + int32_t offFrame; +} INTNETHDR; +AssertCompileSize(INTNETHDR, 8); +AssertCompileSizeAlignment(INTNETBUF, sizeof(INTNETHDR)); +/** Pointer to a frame header.*/ +typedef INTNETHDR *PINTNETHDR; +/** Pointer to a const frame header.*/ +typedef INTNETHDR const *PCINTNETHDR; + +/** The alignment of a frame header. */ +#define INTNETHDR_ALIGNMENT sizeof(INTNETHDR) +AssertCompile(sizeof(INTNETHDR) == INTNETHDR_ALIGNMENT); +AssertCompile(INTNETHDR_ALIGNMENT <= INTNETRINGBUF_ALIGNMENT); + +/** @name Frame types (INTNETHDR::u8Type). + * @{ */ +/** Normal frames. */ +#define INTNETHDR_TYPE_FRAME 0x42 +/** Padding frames. */ +#define INTNETHDR_TYPE_PADDING 0x53 +/** Generic segment offload frames. + * The frame starts with a PDMNETWORKGSO structure which is followed by the + * header template and data. */ +#define INTNETHDR_TYPE_GSO 0x64 +AssertCompileSize(PDMNETWORKGSO, 8); +/** @} */ + +/** + * Asserts the sanity of the specified INTNETHDR. + */ +#ifdef VBOX_STRICT +#define INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf) \ + do \ + { \ + AssertPtr(pHdr); \ + Assert(RT_ALIGN_PT(pHdr, INTNETHDR_ALIGNMENT, INTNETHDR *) == pHdr); \ + Assert( (pHdr)->u8Type == INTNETHDR_TYPE_FRAME \ + || (pHdr)->u8Type == INTNETHDR_TYPE_GSO \ + || (pHdr)->u8Type == INTNETHDR_TYPE_PADDING); \ + { \ + uintptr_t const offHdr = (uintptr_t)pHdr - (uintptr_t)pRingBuf; \ + uintptr_t const offFrame = offHdr + (pHdr)->offFrame; \ + \ + Assert(offHdr >= (pRingBuf)->offStart); \ + Assert(offHdr < (pRingBuf)->offEnd); \ + \ + /* could do more thorough work here... later, perhaps. */ \ + Assert(offFrame >= (pRingBuf)->offStart); \ + Assert(offFrame < (pRingBuf)->offEnd); \ + } \ + } while (0) +#else +# define INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf) do { } while (0) +#endif + + +/** + * Scatter / Gather segment (internal networking). + */ +typedef struct INTNETSEG +{ + /** The physical address. NIL_RTHCPHYS is not set. */ + RTHCPHYS Phys; + /** Pointer to the segment data. */ + void *pv; + /** The segment size. */ + uint32_t cb; +} INTNETSEG; +/** Pointer to a internal networking frame segment. */ +typedef INTNETSEG *PINTNETSEG; +/** Pointer to a internal networking frame segment. */ +typedef INTNETSEG const *PCINTNETSEG; + + +/** + * Scatter / Gather list (internal networking). + * + * This is used when communicating with the trunk port. + */ +typedef struct INTNETSG +{ + /** Owner data, don't touch! */ + void *pvOwnerData; + /** User data. */ + void *pvUserData; + /** User data 2 in case anyone needs it. */ + void *pvUserData2; + /** GSO context information, set the type to invalid if not relevant. */ + PDMNETWORKGSO GsoCtx; + /** The total length of the scatter gather list. */ + uint32_t cbTotal; + /** The number of users (references). + * This is used by the SGRelease code to decide when it can be freed. */ + uint16_t volatile cUsers; + /** Flags, see INTNETSG_FLAGS_* */ + uint16_t volatile fFlags; +#if ARCH_BITS == 64 + /** Alignment padding. */ + uint16_t uPadding; +#endif + /** The number of segments allocated. */ + uint16_t cSegsAlloc; + /** The number of segments actually used. */ + uint16_t cSegsUsed; + /** Variable sized list of segments. */ + INTNETSEG aSegs[1]; +} INTNETSG; +AssertCompileSizeAlignment(INTNETSG, 8); +/** Pointer to a scatter / gather list. */ +typedef INTNETSG *PINTNETSG; +/** Pointer to a const scatter / gather list. */ +typedef INTNETSG const *PCINTNETSG; + +/** @name INTNETSG::fFlags definitions. + * @{ */ +/** Set if the SG is free. */ +#define INTNETSG_FLAGS_FREE RT_BIT_32(1) +/** Set if the SG is a temporary one that will become invalid upon return. + * Try to finish using it before returning, and if that's not possible copy + * to other buffers. + * When not set, the callee should always free the SG. + * Attempts to free it made by the callee will be quietly ignored. */ +#define INTNETSG_FLAGS_TEMP RT_BIT_32(2) +/** ARP packet, IPv4 + MAC. + * @internal */ +#define INTNETSG_FLAGS_ARP_IPV4 RT_BIT_32(3) +/** Copied to the temporary buffer. + * @internal */ +#define INTNETSG_FLAGS_PKT_CP_IN_TMP RT_BIT_32(4) +/** @} */ + + +/** @name Direction (frame source or destination) + * @{ */ +/** To/From the wire. */ +#define INTNETTRUNKDIR_WIRE RT_BIT_32(0) +/** To/From the host. */ +#define INTNETTRUNKDIR_HOST RT_BIT_32(1) +/** Mask of valid bits. */ +#define INTNETTRUNKDIR_VALID_MASK UINT32_C(3) +/** @} */ + +/** + * Switch decisions returned by INTNETTRUNKSWPORT::pfnPreRecv. + */ +typedef enum INTNETSWDECISION +{ + /** The usual invalid zero value. */ + INTNETSWDECISION_INVALID = 0, + /** Everywhere. */ + INTNETSWDECISION_BROADCAST, + /** Only to the internal network. */ + INTNETSWDECISION_INTNET, + /** Only for the trunk (host/wire). */ + INTNETSWDECISION_TRUNK, + /** Used internally to indicate that the packet cannot be handled in the + * current context. */ + INTNETSWDECISION_BAD_CONTEXT, + /** Used internally to indicate that the packet should be dropped. */ + INTNETSWDECISION_DROP, + /** The usual 32-bit type expansion. */ + INTNETSWDECISION_32BIT_HACK = 0x7fffffff +} INTNETSWDECISION; + + +/** + * Network layer address type. + */ +typedef enum INTNETADDRTYPE +{ + /** The invalid 0 entry. */ + kIntNetAddrType_Invalid = 0, + /** IP version 4. */ + kIntNetAddrType_IPv4, + /** IP version 6. */ + kIntNetAddrType_IPv6, + /** IPX. */ + kIntNetAddrType_IPX, + /** The end of the valid values. */ + kIntNetAddrType_End, + /** The usual 32-bit hack. */ + kIntNetAddrType_32BitHack = 0x7fffffff +} INTNETADDRTYPE; + + +/** Pointer to the interface side of a trunk port. */ +typedef struct INTNETTRUNKIFPORT *PINTNETTRUNKIFPORT; + + +/** + * Special variation of INTNETTRUNKIFPORT::pfnRelease for use with + * INTNETTRUNKSWPORT::pfnDisconnect. + * + * @param pIfPort Pointer to the INTNETTRUNKIFPORT instance. + */ +typedef DECLCALLBACKTYPE(void, FNINTNETTRUNKIFPORTRELEASEBUSY,(PINTNETTRUNKIFPORT pIfPort)); +/** Pointer to a FNINTNETTRUNKIFPORTRELEASEBUSY function. */ +typedef FNINTNETTRUNKIFPORTRELEASEBUSY *PFNINTNETTRUNKIFPORTRELEASEBUSY; + + +/** Pointer to the switch side of a trunk port. */ +typedef struct INTNETTRUNKSWPORT *PINTNETTRUNKSWPORT; +/** + * This is the port on the internal network 'switch', i.e. + * what the driver is connected to. + * + * This is only used for the in-kernel trunk connections. + */ +typedef struct INTNETTRUNKSWPORT +{ + /** Structure version number. (INTNETTRUNKSWPORT_VERSION) */ + uint32_t u32Version; + + /** + * Examine the packet and figure out where it is going. + * + * This method is for making packet switching decisions in contexts where + * pfnRecv cannot be called or is no longer applicable. This method can be + * called from any context. + * + * @returns INTNETSWDECISION_BROADCAST, INTNETSWDECISION_INTNET or + * INTNETSWDECISION_TRUNK. The source is excluded from broadcast & + * trunk, of course. + * + * @param pSwitchPort Pointer to this structure. + * @param pvHdrs Pointer to the packet headers. + * @param cbHdrs Size of the packet headers. This must be at least 6 + * bytes (the destination MAC address), but should if + * possible also include any VLAN tag and network + * layer header (wireless mac address sharing). + * @param fSrc Where this frame comes from. Only one bit should be + * set! + * + * @remarks Will only grab the switch table spinlock (interrupt safe). May + * signal an event semaphore iff we're racing network cleanup. The + * caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(INTNETSWDECISION, pfnPreRecv,(PINTNETTRUNKSWPORT pSwitchPort, + void const *pvHdrs, size_t cbHdrs, uint32_t fSrc)); + + /** + * Incoming frame. + * + * The frame may be modified when the trunk port on the switch is set to share + * the mac address of the host when hitting the wire. Currently frames + * containing ARP packets are subject to this, later other protocols like + * NDP/ICMPv6 may need editing as well when operating in this mode. The edited + * packet should be forwarded to the host/wire when @c false is returned. + * + * @returns true if we've handled it and it should be dropped. + * false if it should hit the wire/host. + * + * @param pSwitchPort Pointer to this structure. + * @param pvIf Pointer to the interface which received this frame + * if available. Can be NULL. + * @param pSG The (scatter /) gather structure for the frame. This + * will only be use during the call, so a temporary one can + * be used. The Phys member will not be used. + * @param fSrc Where this frame comes from. Exactly one bit shall be + * set! + * + * @remarks Will only grab the switch table spinlock (interrupt safe). Will + * signal event semaphores. The caller must be busy when calling. + * + * @remarks NAT and TAP will use this interface. + * + * @todo Do any of the host require notification before frame modifications? + * If so, we'll add a callback to INTNETTRUNKIFPORT for this + * (pfnSGModifying) and a SG flag. + */ + DECLR0CALLBACKMEMBER(bool, pfnRecv,(PINTNETTRUNKSWPORT pSwitchPort, void *pvIf, PINTNETSG pSG, uint32_t fSrc)); + + /** + * Retain a SG. + * + * @param pSwitchPort Pointer to this structure. + * @param pSG Pointer to the (scatter /) gather structure. + * + * @remarks Will not grab any locks. The caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(void, pfnSGRetain,(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)); + + /** + * Release a SG. + * + * This is called by the pfnXmit code when done with a SG. This may safe + * be done in an asynchronous manner. + * + * @param pSwitchPort Pointer to this structure. + * @param pSG Pointer to the (scatter /) gather structure. + * + * @remarks May signal an event semaphore later on, currently code won't though. + * The caller is busy when making this call. + */ + DECLR0CALLBACKMEMBER(void, pfnSGRelease,(PINTNETTRUNKSWPORT pSwitchPort, PINTNETSG pSG)); + + /** + * Selects whether outgoing SGs should have their physical address set. + * + * By enabling physical addresses in the scatter / gather segments it should + * be possible to save some unnecessary address translation and memory locking + * in the network stack. (Internal networking knows the physical address for + * all the INTNETBUF data and that it's locked memory.) There is a negative + * side effects though, frames that crosses page boundaries will require + * multiple scather / gather segments. + * + * @returns The old setting. + * + * @param pSwitchPort Pointer to this structure. + * @param fEnable Whether to enable or disable it. + * + * @remarks Will not grab any locks. The caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(bool, pfnSetSGPhys,(PINTNETTRUNKSWPORT pSwitchPort, bool fEnable)); + + /** + * Reports the MAC address of the trunk. + * + * This is supposed to be called when creating, connection or reconnecting the + * trunk and when the MAC address is changed by the system admin. + * + * @param pSwitchPort Pointer to this structure. + * @param pMacAddr The MAC address. + * + * @remarks May take a spinlock or two. The caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(void, pfnReportMacAddress,(PINTNETTRUNKSWPORT pSwitchPort, PCRTMAC pMacAddr)); + + /** + * Reports the promicuousness of the interface. + * + * This is supposed to be called when creating, connection or reconnecting the + * trunk and when the mode is changed by the system admin. + * + * @param pSwitchPort Pointer to this structure. + * @param fPromiscuous True if the host operates the interface in + * promiscuous mode, false if not. + * + * @remarks May take a spinlock or two. The caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(void, pfnReportPromiscuousMode,(PINTNETTRUNKSWPORT pSwitchPort, bool fPromiscuous)); + + /** + * Reports the GSO capabilities of the host, wire or both. + * + * This is supposed to be used only when creating, connecting or reconnecting + * the trunk. It is assumed that the GSO capabilities are kind of static the + * rest of the time. + * + * @param pSwitchPort Pointer to this structure. + * @param fGsoCapabilities The GSO capability bit mask. The bits + * corresponds to the GSO type with the same value. + * @param fDst The destination mask (INTNETTRUNKDIR_XXX). + * + * @remarks Does not take any locks. The caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(void, pfnReportGsoCapabilities,(PINTNETTRUNKSWPORT pSwitchPort, uint32_t fGsoCapabilities, uint32_t fDst)); + + /** + * Reports the no-preemption-xmit capabilities of the host and wire. + * + * This is supposed to be used only when creating, connecting or reconnecting + * the trunk. It is assumed that the GSO capabilities are kind of static the + * rest of the time. + * + * @param pSwitchPort Pointer to this structure. + * @param fNoPreemptDsts The destinations (INTNETTRUNKDIR_XXX) which it + * is safe to transmit to with preemption disabled. + * @param fDst The destination mask (INTNETTRUNKDIR_XXX). + * + * @remarks Does not take any locks. The caller must be busy when calling. + */ + DECLR0CALLBACKMEMBER(void, pfnReportNoPreemptDsts,(PINTNETTRUNKSWPORT pSwitchPort, uint32_t fNoPreemptDsts)); + + /** + * Notifications about changes to host IP addresses. + * + * This is used by networks bridged to wifi that share mac with + * the host. Host reports changes to its IP addresses so that L3 + * switching can ingore guests spoofing host's own IP addresses + * + * This callback may be null to indicate we are not interested. + * + * @param pSwitchPort Pointer to this structure. + * @param fAdded Whether address is added of removed. + * @param enmType Address type. + * @param pvAddr Pointer to the address. + */ + DECLR0CALLBACKMEMBER(void, pfnNotifyHostAddress,(PINTNETTRUNKSWPORT pSwitchPort, bool fAdded, + INTNETADDRTYPE enmType, const void *pvAddr)); + + /** + * OS triggered trunk disconnect. + * + * The caller shall must be busy when calling this method to prevent racing the + * network destruction code. This method will always consume this busy reference + * (released via @a pfnReleaseBusy using @a pIfPort). + * + * The caller shall guarantee that there are absolutely no chance of concurrent + * calls to this method on the same instance. + * + * @param pSwitchPort Pointer to this structure. + * @param pIfPort The interface port structure corresponding to @a + * pSwitchPort and which should be used when + * calling @a pfnReleaseBusy. This is required as + * the method may no longer have access to a valid + * @a pIfPort pointer. + * @param pfnReleaseBusy Callback for releasing the callers busy + * reference to it's side of things. + */ + DECLR0CALLBACKMEMBER(void, pfnDisconnect,(PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT pIfPort, + PFNINTNETTRUNKIFPORTRELEASEBUSY pfnReleaseBusy)); + + /** Structure version number. (INTNETTRUNKSWPORT_VERSION) */ + uint32_t u32VersionEnd; +} INTNETTRUNKSWPORT; + +/** + * Version number for the INTNETTRUNKIFPORT::u32Version and + * INTNETTRUNKIFPORT::u32VersionEnd fields. + * + * NB: Version @c 0xA2CDf005 is consumed by 4.x branches for the + * backport of pfnNotifyHostAddress. On the next version bump use + * @c 0xA2CDf006 and remove this reminder. + */ +# define INTNETTRUNKSWPORT_VERSION UINT32_C(0xA2CDf004) + + +/** + * The trunk interface state used set by INTNETTRUNKIFPORT::pfnSetState. + */ +typedef enum INTNETTRUNKIFSTATE +{ + /** The invalid zero entry. */ + INTNETTRUNKIFSTATE_INVALID = 0, + /** The trunk is inactive. No calls to INTNETTRUNKSWPORT::pfnRecv or + * INTNETTRUNKSWPORT::pfnPreRecv. Calling other methods is OK. */ + INTNETTRUNKIFSTATE_INACTIVE, + /** The trunk is active, no restrictions on methods or anything. */ + INTNETTRUNKIFSTATE_ACTIVE, + /** The trunk is about to be disconnected from the internal network. No + * calls to any INTNETRUNKSWPORT methods. */ + INTNETTRUNKIFSTATE_DISCONNECTING, + /** The end of the valid states. */ + INTNETTRUNKIFSTATE_END, + /** The usual 32-bit type blow up hack. */ + INTNETTRUNKIFSTATE_32BIT_HACK = 0x7fffffff +} INTNETTRUNKIFSTATE; + + +/** + * This is the port on the trunk interface, i.e. the driver side which the + * internal network is connected to. + * + * This is only used for the in-kernel trunk connections. + */ +typedef struct INTNETTRUNKIFPORT +{ + /** Structure version number. (INTNETTRUNKIFPORT_VERSION) */ + uint32_t u32Version; + + /** + * Retain the object. + * + * It will normally be called while owning the internal network semaphore. + * + * @param pIfPort Pointer to this structure. + * + * @remarks May own the big mutex, no spinlocks. + */ + DECLR0CALLBACKMEMBER(void, pfnRetain,(PINTNETTRUNKIFPORT pIfPort)); + + /** + * Releases the object. + * + * This must be called for every pfnRetain call. + * + * @param pIfPort Pointer to this structure. + * + * @remarks May own the big mutex, no spinlocks. + */ + DECLR0CALLBACKMEMBER(void, pfnRelease,(PINTNETTRUNKIFPORT pIfPort)); + + /** + * Disconnect from the switch and release the object. + * + * The is the counter action of the + * INTNETTRUNKNETFLTFACTORY::pfnCreateAndConnect method. + * + * @param pIfPort Pointer to this structure. + * + * @remarks Owns the big mutex. + */ + DECLR0CALLBACKMEMBER(void, pfnDisconnectAndRelease,(PINTNETTRUNKIFPORT pIfPort)); + + /** + * Changes the state of the trunk interface. + * + * The interface is created in the inactive state (INTNETTRUNKIFSTATE_INACTIVE). + * When the first connect VM or service is activated, the internal network + * activates the trunk (INTNETTRUNKIFSTATE_ACTIVE). The state may then be set + * back and forth between INACTIVE and ACTIVE as VMs are paused, added and + * removed. + * + * Eventually though, the network is destroyed as a result of there being no + * more VMs left in it and the state is changed to disconnecting + * (INTNETTRUNKIFSTATE_DISCONNECTING) and pfnWaitForIdle is called to make sure + * there are no active calls in either direction when pfnDisconnectAndRelease is + * called. + * + * A typical operation to performed by this method is to enable/disable promiscuous + * mode on the host network interface when entering/leaving the active state. + * + * @returns The previous state. + * + * @param pIfPort Pointer to this structure. + * @param enmState The new state. + * + * @remarks Owns the big mutex. No racing pfnSetState, pfnWaitForIdle, + * pfnDisconnectAndRelease or INTNETTRUNKFACTORY::pfnCreateAndConnect + * calls. + */ + DECLR0CALLBACKMEMBER(INTNETTRUNKIFSTATE, pfnSetState,(PINTNETTRUNKIFPORT pIfPort, INTNETTRUNKIFSTATE enmState)); + + /** + * Notifies when the MAC address of an interface is set or changes. + * + * @param pIfPort Pointer to this structure. + * @param pvIfData Pointer to the trunk's interface data (see + * pfnConnectInterface). + * @param pMac Pointer to the MAC address of the connecting VM NIC. + * + * @remarks Only busy references to the trunk and the interface. + */ + DECLR0CALLBACKMEMBER(void, pfnNotifyMacAddress,(PINTNETTRUNKIFPORT pIfPort, void *pvIfData, PCRTMAC pMac)); + + /** + * Called when an interface is connected to the network. + * + * @returns IPRT status code. + * @param pIfPort Pointer to this structure. + * @param pvIf Opaque pointer to the interface being connected. + * For use INTNETTRUNKSWPORT::pfnRecv. + * @param ppvIfData Pointer to a pointer variable that the trunk + * implementation can use to associate data with the + * interface. This pointer will be passed to the + * pfnXmit, pfnNotifyMacAddress and + * pfnDisconnectInterface methods. + * + * @remarks Owns the big mutex. No racing pfnDisconnectAndRelease. + */ + DECLR0CALLBACKMEMBER(int, pfnConnectInterface,(PINTNETTRUNKIFPORT pIfPort, void *pvIf, void **ppvIfData)); + + /** + * Called when an interface is disconnected from the network. + * + * @param pIfPort Pointer to this structure. + * @param pvIfData Pointer to the trunk's interface data (see + * pfnConnectInterface). + * + * @remarks Owns the big mutex. No racing pfnDisconnectAndRelease. + */ + DECLR0CALLBACKMEMBER(void, pfnDisconnectInterface,(PINTNETTRUNKIFPORT pIfPort, void *pvIfData)); + + /** + * Waits for the interface to become idle. + * + * This method must be called before disconnecting and releasing the object in + * order to prevent racing incoming/outgoing frames and device + * enabling/disabling. + * + * @returns IPRT status code (see RTSemEventWait). + * @param pIfPort Pointer to this structure. + * @param cMillies The number of milliseconds to wait. 0 means + * no waiting at all. Use RT_INDEFINITE_WAIT for + * an indefinite wait. + * + * @remarks Owns the big mutex. No racing pfnDisconnectAndRelease. + */ + DECLR0CALLBACKMEMBER(int, pfnWaitForIdle,(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)); + + /** + * Transmit a frame. + * + * @return VBox status code. Error generally means we'll drop the frame. + * @param pIfPort Pointer to this structure. + * @param pvIfData Pointer to the trunk's interface data (see + * pfnConnectInterface). + * @param pSG Pointer to the (scatter /) gather structure for the frame. + * This may or may not be a temporary buffer. If it's temporary + * the transmit operation(s) then it's required to make a copy + * of the frame unless it can be transmitted synchronously. + * @param fDst The destination mask. At least one bit will be set. + * + * @remarks No locks. May be called concurrently on several threads. + */ + DECLR0CALLBACKMEMBER(int, pfnXmit,(PINTNETTRUNKIFPORT pIfPort, void *pvIfData, PINTNETSG pSG, uint32_t fDst)); + + /** Structure version number. (INTNETTRUNKIFPORT_VERSION) */ + uint32_t u32VersionEnd; +} INTNETTRUNKIFPORT; + +/** Version number for the INTNETTRUNKIFPORT::u32Version and INTNETTRUNKIFPORT::u32VersionEnd fields. */ +#define INTNETTRUNKIFPORT_VERSION UINT32_C(0xA2CDe001) + + +/** + * The component factory interface for create a network + * interface filter (like VBoxNetFlt). + */ +typedef struct INTNETTRUNKFACTORY +{ + /** + * Release this factory. + * + * SUPR0ComponentQueryFactory (SUPDRVFACTORY::pfnQueryFactoryInterface to be precise) + * will retain a reference to the factory and the caller has to call this method to + * release it once the pfnCreateAndConnect call(s) has been done. + * + * @param pIfFactory Pointer to this structure. + */ + DECLR0CALLBACKMEMBER(void, pfnRelease,(struct INTNETTRUNKFACTORY *pIfFactory)); + + /** + * Create an instance for the specfied host interface and connects it + * to the internal network trunk port. + * + * The initial interface active state is false (suspended). + * + * + * @returns VBox status code. + * @retval VINF_SUCCESS and *ppIfPort set on success. + * @retval VERR_INTNET_FLT_IF_NOT_FOUND if the interface was not found. + * @retval VERR_INTNET_FLT_IF_BUSY if the interface is already connected. + * @retval VERR_INTNET_FLT_IF_FAILED if it failed for some other reason. + * + * @param pIfFactory Pointer to this structure. + * @param pszName The interface name (OS specific). + * @param pSwitchPort Pointer to the port interface on the switch that + * this interface is being connected to. + * @param fFlags Creation flags, see below. + * @param ppIfPort Where to store the pointer to the interface port + * on success. + * + * @remarks Called while owning the network and the out-bound trunk semaphores. + */ + DECLR0CALLBACKMEMBER(int, pfnCreateAndConnect,(struct INTNETTRUNKFACTORY *pIfFactory, const char *pszName, + PINTNETTRUNKSWPORT pSwitchPort, uint32_t fFlags, + PINTNETTRUNKIFPORT *ppIfPort)); +} INTNETTRUNKFACTORY; +/** Pointer to the trunk factory. */ +typedef INTNETTRUNKFACTORY *PINTNETTRUNKFACTORY; + +/** The UUID for the (current) trunk factory. (case sensitive) */ +#define INTNETTRUNKFACTORY_UUID_STR "de504d93-1d1e-4781-8b73-6ea39a0e36a2" + +/** @name INTNETTRUNKFACTORY::pfnCreateAndConnect flags. + * @{ */ +/** Don't put the filtered interface in promiscuous mode. + * This is used for wireless interface since these can misbehave if + * we try to put them in promiscuous mode. (Wireless interfaces are + * normally bridged on level 3 instead of level 2.) */ +#define INTNETTRUNKFACTORY_FLAG_NO_PROMISC RT_BIT_32(0) +/** @} */ + + +/** + * The trunk connection type. + * + * Used by IntNetR0Open and associated interfaces. + */ +typedef enum INTNETTRUNKTYPE +{ + /** Invalid trunk type. */ + kIntNetTrunkType_Invalid = 0, + /** No trunk connection. */ + kIntNetTrunkType_None, + /** We don't care which kind of trunk connection if the network exists, + * if it doesn't exist create it without a connection. */ + kIntNetTrunkType_WhateverNone, + /** VirtualBox host network interface filter driver. + * The trunk name is the name of the host network interface. */ + kIntNetTrunkType_NetFlt, + /** VirtualBox adapter host driver. */ + kIntNetTrunkType_NetAdp, + /** Nat service (ring-0). */ + kIntNetTrunkType_SrvNat, + /** The end of valid types. */ + kIntNetTrunkType_End, + /** The usual 32-bit hack. */ + kIntNetTrunkType_32bitHack = 0x7fffffff +} INTNETTRUNKTYPE; + +/** @name IntNetR0Open flags. + * + * The desired policy options must be specified explicitly, if omitted it is + * understood that whatever is current or default is fine with the caller. + * + * @todo Move the policies out of the flags, use three new parameters. + * + * @{ */ +/** Share the MAC address with the host when sending something to the wire via the trunk. + * This is typically used when the trunk is a NetFlt for a wireless interface. */ +#define INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE RT_BIT_32(0) +/** Require that the current security and promiscuous policies of the network + * is exactly as the ones specified in this open network request. + * + * Use this with INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES to prevent + * restrictions from being lifted. If no further policy changes are desired, + * apply the relevant _FIXED flags. */ +#define INTNET_OPEN_FLAGS_REQUIRE_EXACT RT_BIT_32(1) +/** Require that the security and promiscuous policies of the network is at + * least as restrictive as specified this request specifies and prevent them + * being lifted later on. */ +#define INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES RT_BIT_32(2) + +/** Network access policy: Fixed if set, changable if clear. */ +#define INTNET_OPEN_FLAGS_ACCESS_FIXED RT_BIT_32(3) +/** Network access policy: Public network. */ +#define INTNET_OPEN_FLAGS_ACCESS_PUBLIC RT_BIT_32(4) +/** Network access policy: Restricted network. */ +#define INTNET_OPEN_FLAGS_ACCESS_RESTRICTED RT_BIT_32(5) + +/** Promiscuous mode policy: Is it fixed or changable by new participants? */ +#define INTNET_OPEN_FLAGS_PROMISC_FIXED RT_BIT_32(6) +/** Promiscuous mode policy: Allow the clients to request it. */ +#define INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS RT_BIT_32(7) +/** Promiscuous mode policy: Deny the clients from requesting it. */ +#define INTNET_OPEN_FLAGS_PROMISC_DENY_CLIENTS RT_BIT_32(8) +/** Promiscuous mode policy: Allow the trunk-host to request it. */ +#define INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST RT_BIT_32(9) +/** Promiscuous mode policy: Deny the trunk-host from requesting it. */ +#define INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_HOST RT_BIT_32(10) +/** Promiscuous mode policy: Allow the trunk-wire to request it. */ +#define INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_WIRE RT_BIT_32(11) +/** Promiscuous mode policy: Deny the trunk-wire from requesting it. */ +#define INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_WIRE RT_BIT_32(12) + +/** Interface policies: Is it fixed or changable (by admin). + * @note Per interface, not network wide. */ +#define INTNET_OPEN_FLAGS_IF_FIXED RT_BIT_32(13) +/** Interface promiscuous mode policy: Allow the interface to request it. */ +#define INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW RT_BIT_32(14) +/** Interface promiscuous mode policy: Deny the interface from requesting it. */ +#define INTNET_OPEN_FLAGS_IF_PROMISC_DENY RT_BIT_32(15) +/** Interface promiscuous mode policy: See unrelated trunk traffic. */ +#define INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK RT_BIT_32(16) +/** Interface promiscuous mode policy: No unrelated trunk traffic visible. */ +#define INTNET_OPEN_FLAGS_IF_PROMISC_NO_TRUNK RT_BIT_32(17) + +/** Trunk policy: Fixed if set, changable if clear. + * @remarks The DISABLED options are considered more restrictive by + * INTNET_OPEN_FLAGS_REQUIRE_AS_RESTRICTIVE_POLICIES. */ +#define INTNET_OPEN_FLAGS_TRUNK_FIXED RT_BIT_32(18) +/** Trunk policy: The host end should be enabled. */ +#define INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED RT_BIT_32(19) +/** Trunk policy: The host end should be disabled. */ +#define INTNET_OPEN_FLAGS_TRUNK_HOST_DISABLED RT_BIT_32(20) +/** Trunk policy: The host should only see packets destined for it. */ +#define INTNET_OPEN_FLAGS_TRUNK_HOST_CHASTE_MODE RT_BIT_32(21) +/** Trunk policy: The host should see all packets. */ +#define INTNET_OPEN_FLAGS_TRUNK_HOST_PROMISC_MODE RT_BIT_32(22) +/** Trunk policy: The wire end should be enabled. */ +#define INTNET_OPEN_FLAGS_TRUNK_WIRE_ENABLED RT_BIT_32(23) +/** Trunk policy: The wire end should be disabled. */ +#define INTNET_OPEN_FLAGS_TRUNK_WIRE_DISABLED RT_BIT_32(24) +/** Trunk policy: The wire should only see packets destined for it. */ +#define INTNET_OPEN_FLAGS_TRUNK_WIRE_CHASTE_MODE RT_BIT_32(25) +/** Trunk policy: The wire should see all packets. */ +#define INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE RT_BIT_32(26) + +/** Used to enable host specific workarounds. + * + * On darwin this will clear ip_tos in DHCP packets when + * INTNET_OPEN_FLAGS_SHARED_MAC_ON_WIRE is also set. */ +#define INTNET_OPEN_FLAGS_WORKAROUND_1 RT_BIT_32(31) + + +/** The mask of valid flags. */ +#define INTNET_OPEN_FLAGS_MASK UINT32_C(0x83ffffff) +/** The mask of all flags use to fix (lock) settings. */ +#define INTNET_OPEN_FLAGS_FIXED_MASK \ + ( INTNET_OPEN_FLAGS_ACCESS_FIXED \ + | INTNET_OPEN_FLAGS_PROMISC_FIXED \ + | INTNET_OPEN_FLAGS_IF_FIXED \ + | INTNET_OPEN_FLAGS_TRUNK_FIXED ) + +/** The mask of all policy pairs. */ +#define INTNET_OPEN_FLAGS_PAIR_MASK \ + ( INTNET_OPEN_FLAGS_ACCESS_PUBLIC | INTNET_OPEN_FLAGS_ACCESS_RESTRICTED \ + | INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS | INTNET_OPEN_FLAGS_PROMISC_DENY_CLIENTS \ + | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST | INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_HOST \ + | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_WIRE | INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_WIRE \ + | INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW | INTNET_OPEN_FLAGS_IF_PROMISC_DENY \ + | INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK | INTNET_OPEN_FLAGS_IF_PROMISC_NO_TRUNK \ + | INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED | INTNET_OPEN_FLAGS_TRUNK_HOST_DISABLED \ + | INTNET_OPEN_FLAGS_TRUNK_HOST_PROMISC_MODE | INTNET_OPEN_FLAGS_TRUNK_HOST_CHASTE_MODE \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_ENABLED | INTNET_OPEN_FLAGS_TRUNK_WIRE_DISABLED \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE | INTNET_OPEN_FLAGS_TRUNK_WIRE_CHASTE_MODE \ + ) +/** The mask of all relaxed policy bits. */ +#define INTNET_OPEN_FLAGS_RELAXED_MASK \ + ( INTNET_OPEN_FLAGS_ACCESS_PUBLIC \ + | INTNET_OPEN_FLAGS_PROMISC_ALLOW_CLIENTS \ + | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_HOST \ + | INTNET_OPEN_FLAGS_PROMISC_ALLOW_TRUNK_WIRE \ + | INTNET_OPEN_FLAGS_IF_PROMISC_ALLOW \ + | INTNET_OPEN_FLAGS_IF_PROMISC_SEE_TRUNK \ + | INTNET_OPEN_FLAGS_TRUNK_HOST_ENABLED \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_ENABLED \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_PROMISC_MODE \ + ) +/** The mask of all strict policy bits. */ +#define INTNET_OPEN_FLAGS_STRICT_MASK \ + ( INTNET_OPEN_FLAGS_ACCESS_RESTRICTED \ + | INTNET_OPEN_FLAGS_PROMISC_DENY_CLIENTS \ + | INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_HOST \ + | INTNET_OPEN_FLAGS_PROMISC_DENY_TRUNK_WIRE \ + | INTNET_OPEN_FLAGS_IF_PROMISC_DENY \ + | INTNET_OPEN_FLAGS_IF_PROMISC_NO_TRUNK \ + | INTNET_OPEN_FLAGS_TRUNK_HOST_DISABLED \ + | INTNET_OPEN_FLAGS_TRUNK_HOST_CHASTE_MODE \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_DISABLED \ + | INTNET_OPEN_FLAGS_TRUNK_WIRE_CHASTE_MODE \ + ) +/** @} */ + +/** The maximum length of a network name. */ +#define INTNET_MAX_NETWORK_NAME 128 + +/** The maximum length of a trunk name. */ +#define INTNET_MAX_TRUNK_NAME 64 + + +/** + * Request buffer for IntNetR0OpenReq / VMMR0_DO_INTNET_OPEN. + * @see IntNetR0Open. + */ +typedef struct INTNETOPENREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** The network name. (input) */ + char szNetwork[INTNET_MAX_NETWORK_NAME]; + /** What to connect to the trunk port. (input) + * This is specific to the trunk type below. */ + char szTrunk[INTNET_MAX_TRUNK_NAME]; + /** The type of trunk link (NAT, Filter, TAP, etc). (input) */ + INTNETTRUNKTYPE enmTrunkType; + /** Flags, see INTNET_OPEN_FLAGS_*. (input) */ + uint32_t fFlags; + /** The size of the send buffer. (input) */ + uint32_t cbSend; + /** The size of the receive buffer. (input) */ + uint32_t cbRecv; + /** The handle to the network interface. (output) */ + INTNETIFHANDLE hIf; +} INTNETOPENREQ; +/** Pointer to an IntNetR0OpenReq / VMMR0_DO_INTNET_OPEN request buffer. */ +typedef INTNETOPENREQ *PINTNETOPENREQ; + +INTNETR0DECL(int) IntNetR0OpenReq(PSUPDRVSESSION pSession, PINTNETOPENREQ pReq); + + +/** + * Request buffer for IntNetR0IfCloseReq / VMMR0_DO_INTNET_IF_CLOSE. + * @see IntNetR0IfClose. + */ +typedef struct INTNETIFCLOSEREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** The handle to the network interface. */ + INTNETIFHANDLE hIf; +} INTNETIFCLOSEREQ; +/** Pointer to an IntNetR0IfCloseReq / VMMR0_DO_INTNET_IF_CLOSE request + * buffer. */ +typedef INTNETIFCLOSEREQ *PINTNETIFCLOSEREQ; + +INTNETR0DECL(int) IntNetR0IfCloseReq(PSUPDRVSESSION pSession, PINTNETIFCLOSEREQ pReq); + + +/** + * Request buffer for IntNetR0IfGetRing3BufferReq / + * VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS. + * @see IntNetR0IfGetRing3Buffer. + */ +typedef struct INTNETIFGETBUFFERPTRSREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; + /** The pointer to the ring-3 buffer. (output) */ + R3PTRTYPE(PINTNETBUF) pRing3Buf; + /** The pointer to the ring-0 buffer. (output) */ + R0PTRTYPE(PINTNETBUF) pRing0Buf; +} INTNETIFGETBUFFERPTRSREQ; +/** Pointer to an IntNetR0IfGetRing3BufferReq / + * VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS request buffer. */ +typedef INTNETIFGETBUFFERPTRSREQ *PINTNETIFGETBUFFERPTRSREQ; + +INTNETR0DECL(int) IntNetR0IfGetBufferPtrsReq(PSUPDRVSESSION pSession, PINTNETIFGETBUFFERPTRSREQ pReq); + + +/** + * Request buffer for IntNetR0IfSetPromiscuousModeReq / + * VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE. + * @see IntNetR0IfSetPromiscuousMode. + */ +typedef struct INTNETIFSETPROMISCUOUSMODEREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; + /** The new promiscuous mode. */ + bool fPromiscuous; +} INTNETIFSETPROMISCUOUSMODEREQ; +/** Pointer to an IntNetR0IfSetPromiscuousModeReq / + * VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE request buffer. */ +typedef INTNETIFSETPROMISCUOUSMODEREQ *PINTNETIFSETPROMISCUOUSMODEREQ; + +INTNETR0DECL(int) IntNetR0IfSetPromiscuousModeReq(PSUPDRVSESSION pSession, PINTNETIFSETPROMISCUOUSMODEREQ pReq); + + +/** + * Request buffer for IntNetR0IfSetMacAddressReq / + * VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS. + * @see IntNetR0IfSetMacAddress. + */ +typedef struct INTNETIFSETMACADDRESSREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; + /** The new MAC address. */ + RTMAC Mac; +} INTNETIFSETMACADDRESSREQ; +/** Pointer to an IntNetR0IfSetMacAddressReq / + * VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS request buffer. */ +typedef INTNETIFSETMACADDRESSREQ *PINTNETIFSETMACADDRESSREQ; + +INTNETR0DECL(int) IntNetR0IfSetMacAddressReq(PSUPDRVSESSION pSession, PINTNETIFSETMACADDRESSREQ pReq); + + +/** + * Request buffer for IntNetR0IfSetActiveReq / VMMR0_DO_INTNET_IF_SET_ACTIVE. + * @see IntNetR0IfSetActive. + */ +typedef struct INTNETIFSETACTIVEREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; + /** The new state. */ + bool fActive; +} INTNETIFSETACTIVEREQ; +/** Pointer to an IntNetR0IfSetActiveReq / VMMR0_DO_INTNET_IF_SET_ACTIVE + * request buffer. */ +typedef INTNETIFSETACTIVEREQ *PINTNETIFSETACTIVEREQ; + +INTNETR0DECL(int) IntNetR0IfSetActiveReq(PSUPDRVSESSION pSession, PINTNETIFSETACTIVEREQ pReq); + + +/** + * Request buffer for IntNetR0IfSendReq / VMMR0_DO_INTNET_IF_SEND. + * @see IntNetR0IfSend. + */ +typedef struct INTNETIFSENDREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; +} INTNETIFSENDREQ; +/** Pointer to an IntNetR0IfSend() argument package. */ +typedef INTNETIFSENDREQ *PINTNETIFSENDREQ; + +INTNETR0DECL(int) IntNetR0IfSendReq(PSUPDRVSESSION pSession, PINTNETIFSENDREQ pReq); + + +/** + * Request buffer for IntNetR0IfWaitReq / VMMR0_DO_INTNET_IF_WAIT. + * @see IntNetR0IfWait. + */ +typedef struct INTNETIFWAITREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; + /** The number of milliseconds to wait. */ + uint32_t cMillies; +} INTNETIFWAITREQ; +/** Pointer to an IntNetR0IfWaitReq / VMMR0_DO_INTNET_IF_WAIT request buffer. */ +typedef INTNETIFWAITREQ *PINTNETIFWAITREQ; + +INTNETR0DECL(int) IntNetR0IfWaitReq(PSUPDRVSESSION pSession, PINTNETIFWAITREQ pReq); + + +/** + * Request buffer for IntNetR0IfAbortWaitReq / VMMR0_DO_INTNET_IF_ABORT_WAIT. + * @see IntNetR0IfAbortWait. + */ +typedef struct INTNETIFABORTWAITREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. */ + PSUPDRVSESSION pSession; + /** Handle to the interface. */ + INTNETIFHANDLE hIf; + /** Set this to fend off all future IntNetR0Wait calls. */ + bool fNoMoreWaits; +} INTNETIFABORTWAITREQ; +/** Pointer to an IntNetR0IfAbortWaitReq / VMMR0_DO_INTNET_IF_ABORT_WAIT + * request buffer. */ +typedef INTNETIFABORTWAITREQ *PINTNETIFABORTWAITREQ; + +INTNETR0DECL(int) IntNetR0IfAbortWaitReq(PSUPDRVSESSION pSession, PINTNETIFABORTWAITREQ pReq); + + +#if defined(IN_RING0) || defined(IN_INTNET_TESTCASE) +/** @name + * @{ + */ + +INTNETR0DECL(int) IntNetR0Init(void); +INTNETR0DECL(void) IntNetR0Term(void); +INTNETR0DECL(int) IntNetR0Open(PSUPDRVSESSION pSession, const char *pszNetwork, + INTNETTRUNKTYPE enmTrunkType, const char *pszTrunk, uint32_t fFlags, + uint32_t cbSend, uint32_t cbRecv, PINTNETIFHANDLE phIf); +INTNETR0DECL(uint32_t) IntNetR0GetNetworkCount(void); + +INTNETR0DECL(int) IntNetR0IfClose(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession); +INTNETR0DECL(int) IntNetR0IfGetBufferPtrs(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, + R3PTRTYPE(PINTNETBUF) *ppRing3Buf, R0PTRTYPE(PINTNETBUF) *ppRing0Buf); +INTNETR0DECL(int) IntNetR0IfSetPromiscuousMode(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fPromiscuous); +INTNETR0DECL(int) IntNetR0IfSetMacAddress(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, PCRTMAC pMac); +INTNETR0DECL(int) IntNetR0IfSetActive(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, bool fActive); +INTNETR0DECL(int) IntNetR0IfSend(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession); +INTNETR0DECL(int) IntNetR0IfWait(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession, uint32_t cMillies); +INTNETR0DECL(int) IntNetR0IfAbortWait(INTNETIFHANDLE hIf, PSUPDRVSESSION pSession); + +/** @} */ +#endif /* IN_RING0 */ + +/** + * Callback function for use with IntNetR3Open to signalling incoming data. + * + * @param hIf Interface handle. + * @param pvUser User parameter. + */ +typedef DECLCALLBACKTYPE(void, FNINTNETIFRECVAVAIL,(INTNETIFHANDLE hIf, void *pvUser)); +/** Pointer to a FNINTNETIFRECVAVAIL callback. */ +typedef FNINTNETIFRECVAVAIL *PFNINTNETIFRECVAVAIL; + +#if defined(VBOX_WITH_INTNET_SERVICE_IN_R3) && defined(IN_RING3) +INTNETR3DECL(int) IntNetR3Open(PSUPDRVSESSION pSession, const char *pszNetwork, + INTNETTRUNKTYPE enmTrunkType, const char *pszTrunk, uint32_t fFlags, + uint32_t cbSend, uint32_t cbRecv, PFNINTNETIFRECVAVAIL pfnRecvAvail, + void *pvUserRecvAvail, PINTNETIFHANDLE phIf); +#endif + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_intnet_h */ diff --git a/include/VBox/intnetinline.h b/include/VBox/intnetinline.h new file mode 100644 index 00000000..adb338ef --- /dev/null +++ b/include/VBox/intnetinline.h @@ -0,0 +1,837 @@ +/* $Id: intnetinline.h $ */ +/** @file + * INTNET - Internal Networking, Inlined Code. (DEV,++) + * + * This is all inlined because it's too tedious to create 2-3 libraries to + * contain it all. Large parts of this header is only accessible from C++ + * sources because of mixed code and variables. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_intnetinline_h +#define VBOX_INCLUDED_intnetinline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include + + + +/** + * Valid internal networking frame type. + * + * @returns true / false. + * @param u8Type The frame type to check. + */ +DECLINLINE(bool) IntNetIsValidFrameType(uint8_t u8Type) +{ + if (RT_LIKELY( u8Type == INTNETHDR_TYPE_FRAME + || u8Type == INTNETHDR_TYPE_GSO + || u8Type == INTNETHDR_TYPE_PADDING)) + return true; + return false; +} + + +/** + * Partly initializes a scatter / gather buffer, leaving the segments to the + * caller. + * + * @returns Pointer to the start of the frame. + * @param pSG Pointer to the scatter / gather structure. + * @param cbTotal The total size. + * @param cSegs The number of segments. + * @param cSegsUsed The number of used segments. + */ +DECLINLINE(void) IntNetSgInitTempSegs(PINTNETSG pSG, uint32_t cbTotal, unsigned cSegs, unsigned cSegsUsed) +{ + pSG->pvOwnerData = NULL; + pSG->pvUserData = NULL; + pSG->pvUserData2 = NULL; + pSG->cbTotal = cbTotal; + pSG->cUsers = 1; + pSG->fFlags = INTNETSG_FLAGS_TEMP; + pSG->GsoCtx.u8Type = (uint8_t)PDMNETWORKGSOTYPE_INVALID; + pSG->GsoCtx.cbHdrsTotal = 0; + pSG->GsoCtx.cbHdrsSeg = 0; + pSG->GsoCtx.cbMaxSeg= 0; + pSG->GsoCtx.offHdr1 = 0; + pSG->GsoCtx.offHdr2 = 0; + pSG->GsoCtx.u8Unused= 0; +#if ARCH_BITS == 64 + pSG->uPadding = 0; +#endif + pSG->cSegsAlloc = (uint16_t)cSegs; + Assert(pSG->cSegsAlloc == cSegs); + pSG->cSegsUsed = (uint16_t)cSegsUsed; + Assert(pSG->cSegsUsed == cSegsUsed); + Assert(cSegs >= cSegsUsed); +} + + +/** + * Partly initializes a scatter / gather buffer w/ GSO, leaving the segments to + * the caller. + * + * @returns Pointer to the start of the frame. + * @param pSG Pointer to the scatter / gather structure. + * @param cbTotal The total size. + * @param cSegs The number of segments. + * @param cSegsUsed The number of used segments. + * @param pGso The GSO context. + */ +DECLINLINE(void) IntNetSgInitTempSegsGso(PINTNETSG pSG, uint32_t cbTotal, unsigned cSegs, + unsigned cSegsUsed, PCPDMNETWORKGSO pGso) +{ + pSG->pvOwnerData = NULL; + pSG->pvUserData = NULL; + pSG->pvUserData2 = NULL; + pSG->cbTotal = cbTotal; + pSG->cUsers = 1; + pSG->fFlags = INTNETSG_FLAGS_TEMP; + pSG->GsoCtx.u8Type = pGso->u8Type; + pSG->GsoCtx.cbHdrsTotal = pGso->cbHdrsTotal; + pSG->GsoCtx.cbHdrsSeg = pGso->cbHdrsSeg; + pSG->GsoCtx.cbMaxSeg= pGso->cbMaxSeg; + pSG->GsoCtx.offHdr1 = pGso->offHdr1; + pSG->GsoCtx.offHdr2 = pGso->offHdr2; + pSG->GsoCtx.u8Unused= 0; +#if ARCH_BITS == 64 + pSG->uPadding = 0; +#endif + pSG->cSegsAlloc = (uint16_t)cSegs; + Assert(pSG->cSegsAlloc == cSegs); + pSG->cSegsUsed = (uint16_t)cSegsUsed; + Assert(pSG->cSegsUsed == cSegsUsed); + Assert(cSegs >= cSegsUsed); +} + + + +/** + * Initializes a scatter / gather buffer describing a simple linear buffer. + * + * @returns Pointer to the start of the frame. + * @param pSG Pointer to the scatter / gather structure. + * @param pvFrame Pointer to the frame + * @param cbFrame The size of the frame. + */ +DECLINLINE(void) IntNetSgInitTemp(PINTNETSG pSG, void *pvFrame, uint32_t cbFrame) +{ + IntNetSgInitTempSegs(pSG, cbFrame, 1, 1); + pSG->aSegs[0].Phys = NIL_RTHCPHYS; + pSG->aSegs[0].pv = pvFrame; + pSG->aSegs[0].cb = cbFrame; +} + +/** + * Initializes a scatter / gather buffer describing a simple linear buffer. + * + * @returns Pointer to the start of the frame. + * @param pSG Pointer to the scatter / gather structure. + * @param pvFrame Pointer to the frame + * @param cbFrame The size of the frame. + * @param pGso The GSO context. + */ +DECLINLINE(void) IntNetSgInitTempGso(PINTNETSG pSG, void *pvFrame, uint32_t cbFrame, PCPDMNETWORKGSO pGso) +{ + IntNetSgInitTempSegsGso(pSG, cbFrame, 1, 1, pGso); + pSG->aSegs[0].Phys = NIL_RTHCPHYS; + pSG->aSegs[0].pv = pvFrame; + pSG->aSegs[0].cb = cbFrame; +} + + +/** + * Reads an entire SG into a fittingly size buffer. + * + * @param pSG The SG list to read. + * @param pvBuf The buffer to read into (at least pSG->cbTotal in size). + */ +DECLINLINE(void) IntNetSgRead(PCINTNETSG pSG, void *pvBuf) +{ + memcpy(pvBuf, pSG->aSegs[0].pv, pSG->aSegs[0].cb); + if (pSG->cSegsUsed == 1) + Assert(pSG->cbTotal == pSG->aSegs[0].cb); + else + { + uint8_t *pbDst = (uint8_t *)pvBuf + pSG->aSegs[0].cb; + unsigned iSeg = 0; + unsigned const cSegs = pSG->cSegsUsed; + while (++iSeg < cSegs) + { + uint32_t cbSeg = pSG->aSegs[iSeg].cb; + Assert((uintptr_t)pbDst - (uintptr_t)pvBuf + cbSeg <= pSG->cbTotal); + memcpy(pbDst, pSG->aSegs[iSeg].pv, cbSeg); + pbDst += cbSeg; + } + } +} + + +/** + * Reads a portion of an SG into a buffer. + * + * @param pSG The SG list to read. + * @param offSrc The offset to start start copying from. + * @param cbToRead The number of bytes to copy. + * @param pvBuf The buffer to read into, cb or more in size. + */ +DECLINLINE(void) IntNetSgReadEx(PCINTNETSG pSG, uint32_t offSrc, uint32_t cbToRead, void *pvBuf) +{ + uint8_t *pbDst = (uint8_t *)pvBuf; + uint32_t iSeg = 0; + + /* validate assumptions */ + Assert(cbToRead <= pSG->cbTotal); + Assert(offSrc <= pSG->cbTotal); + Assert(offSrc + cbToRead <= pSG->cbTotal); + + /* Find the right segment and copy any bits from within the segment. */ + while (offSrc) + { + uint32_t cbSeg = pSG->aSegs[iSeg].cb; + if (offSrc < cbSeg) + { + uint32_t cbChunk = cbSeg - offSrc; + if (cbChunk >= cbToRead) + { + memcpy(pbDst, (uint8_t const *)pSG->aSegs[iSeg].pv + offSrc, cbToRead); + return; + } + + memcpy(pbDst, (uint8_t const *)pSG->aSegs[iSeg].pv + offSrc, cbChunk); + pbDst += cbChunk; + cbToRead -= cbChunk; + break; + } + + /* advance */ + offSrc -= cbSeg; + iSeg++; + } + + /* We're not at the start of a segment, copy until we're done. */ + for (;;) + { + uint32_t cbSeg = pSG->aSegs[iSeg].cb; + if (cbSeg >= cbToRead) + { + memcpy(pbDst, pSG->aSegs[iSeg].pv, cbToRead); + return; + } + + memcpy(pbDst, pSG->aSegs[iSeg].pv, cbSeg); + pbDst += cbSeg; + cbToRead -= cbSeg; + iSeg++; + Assert(iSeg < pSG->cSegsUsed); + } +} + +#ifdef __cplusplus + +/** + * Get the amount of space available for writing. + * + * @returns Number of available bytes. + * @param pRingBuf The ring buffer. + */ +DECLINLINE(uint32_t) IntNetRingGetWritable(PINTNETRINGBUF pRingBuf) +{ + uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + uint32_t const offWriteInt = ASMAtomicUoReadU32(&pRingBuf->offWriteInt); + return offRead <= offWriteInt + ? pRingBuf->offEnd - offWriteInt + offRead - pRingBuf->offStart - 1 + : offRead - offWriteInt - 1; +} + + +/** + * Checks if the ring has more for us to read. + * + * @returns Number of ready bytes. + * @param pRingBuf The ring buffer. + */ +DECLINLINE(bool) IntNetRingHasMoreToRead(PINTNETRINGBUF pRingBuf) +{ + uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom); + return offRead != offWriteCom; +} + + +/** + * Gets the next frame to read. + * + * @returns Pointer to the next frame. NULL if done. + * @param pRingBuf The ring buffer. + */ +DECLINLINE(PINTNETHDR) IntNetRingGetNextFrameToRead(PINTNETRINGBUF pRingBuf) +{ + uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom); + if (offRead == offWriteCom) + return NULL; + return (PINTNETHDR)((uint8_t *)pRingBuf + offRead); +} + + +/** + * Get the amount of data ready for reading. + * + * @returns Number of ready bytes. + * @param pRingBuf The ring buffer. + */ +DECLINLINE(uint32_t) IntNetRingGetReadable(PINTNETRINGBUF pRingBuf) +{ + uint32_t const offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom); + return offRead <= offWriteCom + ? offWriteCom - offRead + : pRingBuf->offEnd - offRead + offWriteCom - pRingBuf->offStart; +} + + +/** + * Calculates the pointer to the frame. + * + * @returns Pointer to the start of the frame. + * @param pHdr Pointer to the packet header + * @param pBuf The buffer the header is within. Only used in strict builds. + */ +DECLINLINE(void *) IntNetHdrGetFramePtr(PCINTNETHDR pHdr, PCINTNETBUF pBuf) +{ + uint8_t *pu8 = (uint8_t *)pHdr + pHdr->offFrame; +#ifdef VBOX_STRICT + const uintptr_t off = (uintptr_t)pu8 - (uintptr_t)pBuf; + Assert(IntNetIsValidFrameType(pHdr->u8Type)); + Assert(off < pBuf->cbBuf); + Assert(off + pHdr->cbFrame <= pBuf->cbBuf); +#endif + NOREF(pBuf); + return pu8; +} + + +/** + * Calculates the pointer to the GSO context. + * + * ASSUMES the frame is a GSO frame. + * + * The GSO context is immediately followed by the headers and payload. The size + * is INTNETBUF::cbFrame - sizeof(PDMNETWORKGSO). + * + * @returns Pointer to the GSO context. + * @param pHdr Pointer to the packet header + * @param pBuf The buffer the header is within. Only used in strict builds. + */ +DECLINLINE(PPDMNETWORKGSO) IntNetHdrGetGsoContext(PCINTNETHDR pHdr, PCINTNETBUF pBuf) +{ + PPDMNETWORKGSO pGso = (PPDMNETWORKGSO)((uint8_t *)pHdr + pHdr->offFrame); +#ifdef VBOX_STRICT + const uintptr_t off = (uintptr_t)pGso - (uintptr_t)pBuf; + Assert(pHdr->u8Type == INTNETHDR_TYPE_GSO); + Assert(off < pBuf->cbBuf); + Assert(off + pHdr->cbFrame <= pBuf->cbBuf); +#endif + NOREF(pBuf); + return pGso; +} + + +/** + * Skips to the next (read) frame in the buffer. + * + * @param pRingBuf The ring buffer in question. + */ +DECLINLINE(void) IntNetRingSkipFrame(PINTNETRINGBUF pRingBuf) +{ + uint32_t const offReadOld = ASMAtomicUoReadU32(&pRingBuf->offReadX); + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offReadOld); + Assert(offReadOld >= pRingBuf->offStart); + Assert(offReadOld < pRingBuf->offEnd); + Assert(RT_ALIGN_PT(pHdr, INTNETHDR_ALIGNMENT, INTNETHDR *) == pHdr); + Assert(IntNetIsValidFrameType(pHdr->u8Type)); + + /* skip the frame */ + uint32_t offReadNew = offReadOld + pHdr->offFrame + pHdr->cbFrame; + offReadNew = RT_ALIGN_32(offReadNew, INTNETHDR_ALIGNMENT); + Assert(offReadNew <= pRingBuf->offEnd && offReadNew >= pRingBuf->offStart); + if (offReadNew >= pRingBuf->offEnd) + offReadNew = pRingBuf->offStart; + Log2(("IntNetRingSkipFrame: offReadX: %#x -> %#x (1)\n", offReadOld, offReadNew)); +#ifdef INTNET_POISON_READ_FRAMES + memset((uint8_t *)pHdr + pHdr->offFrame, 0xfe, RT_ALIGN_32(pHdr->cbFrame, INTNETHDR_ALIGNMENT)); + memset(pHdr, 0xef, sizeof(*pHdr)); +#endif + ASMAtomicWriteU32(&pRingBuf->offReadX, offReadNew); +} + + +/** + * Allocates a frame in the specified ring. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pRingBuf The ring buffer. + * @param cbFrame The frame size. + * @param u8Type The header type. + * @param ppHdr Where to return the frame header. + * Don't touch this! + * @param ppvFrame Where to return the frame pointer. + */ +DECLINLINE(int) intnetRingAllocateFrameInternal(PINTNETRINGBUF pRingBuf, uint32_t cbFrame, uint8_t u8Type, + PINTNETHDR *ppHdr, void **ppvFrame) +{ + /* + * Validate input and adjust the input. + */ + INTNETRINGBUF_ASSERT_SANITY(pRingBuf); + Assert(cbFrame >= sizeof(RTMAC) * 2); + + const uint32_t cb = RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT); + uint32_t offWriteInt = ASMAtomicUoReadU32(&pRingBuf->offWriteInt); + uint32_t offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + if (offRead <= offWriteInt) + { + /* + * Try fit it all before the end of the buffer. + */ + if (pRingBuf->offEnd - offWriteInt >= cb + sizeof(INTNETHDR)) + { + uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR); + if (offNew >= pRingBuf->offEnd) + offNew = pRingBuf->offStart; + if (RT_LIKELY(ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt))) + { /* likely */ } else return VERR_WRONG_ORDER; /* race */ + Log2(("intnetRingAllocateFrameInternal: offWriteInt: %#x -> %#x (1) (R=%#x T=%#x S=%#x)\n", offWriteInt, offNew, offRead, u8Type, cbFrame)); + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt); + pHdr->u8Type = u8Type; + pHdr->cbFrame = cbFrame; Assert(pHdr->cbFrame == cbFrame); + pHdr->offFrame = sizeof(INTNETHDR); + + *ppHdr = pHdr; + *ppvFrame = pHdr + 1; + return VINF_SUCCESS; + } + /* + * Try fit the frame at the start of the buffer. + * (The header fits before the end of the buffer because of alignment.) + */ + AssertMsg(pRingBuf->offEnd - offWriteInt >= sizeof(INTNETHDR), ("offEnd=%x offWriteInt=%x\n", pRingBuf->offEnd, offWriteInt)); + if (offRead - pRingBuf->offStart > cb) /* not >= ! */ + { + uint32_t offNew = pRingBuf->offStart + cb; + if (RT_LIKELY(ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt))) + { /* likely */ } else return VERR_WRONG_ORDER; /* race */ + Log2(("intnetRingAllocateFrameInternal: offWriteInt: %#x -> %#x (2) (R=%#x T=%#x S=%#x)\n", offWriteInt, offNew, offRead, u8Type, cbFrame)); + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt); + pHdr->u8Type = u8Type; + pHdr->cbFrame = cbFrame; Assert(pHdr->cbFrame == cbFrame); + pHdr->offFrame = pRingBuf->offStart - offWriteInt; + + *ppHdr = pHdr; + *ppvFrame = (uint8_t *)pRingBuf + pRingBuf->offStart; + return VINF_SUCCESS; + } + } + /* + * The reader is ahead of the writer, try fit it into that space. + */ + else if (offRead - offWriteInt > cb + sizeof(INTNETHDR)) /* not >= ! */ + { + uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR); + if (RT_LIKELY(ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt))) + { /* likely */ } else return VERR_WRONG_ORDER; /* race */ + Log2(("intnetRingAllocateFrameInternal: offWriteInt: %#x -> %#x (3) (R=%#x T=%#x S=%#x)\n", offWriteInt, offNew, offRead, u8Type, cbFrame)); + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt); + pHdr->u8Type = u8Type; + pHdr->cbFrame = cbFrame; Assert(pHdr->cbFrame == cbFrame); + pHdr->offFrame = sizeof(INTNETHDR); + + *ppHdr = pHdr; + *ppvFrame = pHdr + 1; + return VINF_SUCCESS; + } + + /* (it didn't fit) */ + *ppHdr = NULL; /* shut up gcc, */ + *ppvFrame = NULL; /* ditto. */ + STAM_REL_COUNTER_INC(&pRingBuf->cOverflows); + return VERR_BUFFER_OVERFLOW; +} + + +/** + * Allocates a normal frame in the specified ring. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pRingBuf The ring buffer. + * @param cbFrame The frame size. + * @param ppHdr Where to return the frame header. + * Don't touch this! + * @param ppvFrame Where to return the frame pointer. + */ +DECLINLINE(int) IntNetRingAllocateFrame(PINTNETRINGBUF pRingBuf, uint32_t cbFrame, PINTNETHDR *ppHdr, void **ppvFrame) +{ + return intnetRingAllocateFrameInternal(pRingBuf, cbFrame, INTNETHDR_TYPE_FRAME, ppHdr, ppvFrame); +} + + +/** + * Allocates a GSO frame in the specified ring. + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pRingBuf The ring buffer. + * @param cbFrame The frame size. + * @param pGso Pointer to the GSO context. + * @param ppHdr Where to return the frame header. + * Don't touch this! + * @param ppvFrame Where to return the frame pointer. + */ +DECLINLINE(int) IntNetRingAllocateGsoFrame(PINTNETRINGBUF pRingBuf, uint32_t cbFrame, PCPDMNETWORKGSO pGso, + PINTNETHDR *ppHdr, void **ppvFrame) +{ + void *pvFrame = NULL; /* gcc maybe used uninitialized */ + int rc = intnetRingAllocateFrameInternal(pRingBuf, cbFrame + sizeof(*pGso), INTNETHDR_TYPE_GSO, ppHdr, &pvFrame); + if (RT_SUCCESS(rc)) + { + PPDMNETWORKGSO pGsoCopy = (PPDMNETWORKGSO)pvFrame; + *pGsoCopy = *pGso; + *ppvFrame = pGsoCopy + 1; + } + return rc; +} + + +/** + * Commits a frame. + * + * Make sure to commit the frames in the order they've been allocated! + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pRingBuf The ring buffer. + * @param pHdr The frame header returned by + * IntNetRingAllocateFrame. + */ +DECLINLINE(void) IntNetRingCommitFrame(PINTNETRINGBUF pRingBuf, PINTNETHDR pHdr) +{ + /* + * Validate input and commit order. + */ + INTNETRINGBUF_ASSERT_SANITY(pRingBuf); + INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf); + Assert(pRingBuf->offWriteCom == ((uintptr_t)pHdr - (uintptr_t)pRingBuf)); + + /* + * Figure out the offWriteCom for this packet and update the ring. + */ + const uint32_t cbFrame = pHdr->cbFrame; + const uint32_t cb = RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT); + uint32_t offWriteCom = (uint32_t)((uintptr_t)pHdr - (uintptr_t)pRingBuf) + + pHdr->offFrame + + cb; + if (offWriteCom >= pRingBuf->offEnd) + { + Assert(offWriteCom == pRingBuf->offEnd); + offWriteCom = pRingBuf->offStart; + } + Log2(("IntNetRingCommitFrame: offWriteCom: %#x -> %#x (R=%#x T=%#x S=%#x)\n", pRingBuf->offWriteCom, offWriteCom, pRingBuf->offReadX, pHdr->u8Type, cbFrame)); + ASMAtomicWriteU32(&pRingBuf->offWriteCom, offWriteCom); + STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame); + STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames); +} + + +/** + * Commits a frame and injects a filler frame if not all of the buffer was used. + * + * Make sure to commit the frames in the order they've been allocated! + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pRingBuf The ring buffer. + * @param pHdr The frame header returned by + * IntNetRingAllocateFrame. + * @param cbUsed The amount of space actually used. This does + * not include the GSO part. + */ +DECLINLINE(void) IntNetRingCommitFrameEx(PINTNETRINGBUF pRingBuf, PINTNETHDR pHdr, size_t cbUsed) +{ + /* + * Validate input and commit order. + */ + INTNETRINGBUF_ASSERT_SANITY(pRingBuf); + INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf); + Assert(pRingBuf->offWriteCom == ((uintptr_t)pHdr - (uintptr_t)pRingBuf)); + + if (pHdr->u8Type == INTNETHDR_TYPE_GSO) + cbUsed += sizeof(PDMNETWORKGSO); + + /* + * Calc the new write commit offset. + */ + const uint32_t cbAlignedFrame = RT_ALIGN_32(pHdr->cbFrame, INTNETHDR_ALIGNMENT); + const uint32_t cbAlignedUsed = RT_ALIGN_32(cbUsed, INTNETHDR_ALIGNMENT); + uint32_t offWriteCom = (uint32_t)((uintptr_t)pHdr - (uintptr_t)pRingBuf) + + pHdr->offFrame + + cbAlignedFrame; + if (offWriteCom >= pRingBuf->offEnd) + { + Assert(offWriteCom == pRingBuf->offEnd); + offWriteCom = pRingBuf->offStart; + } + + /* + * Insert a dummy frame to pad any unused space. + */ + if (cbAlignedFrame != cbAlignedUsed) + { + /** @todo Later: Try unallocate the extra memory. */ + PINTNETHDR pHdrPadding = (PINTNETHDR)((uint8_t *)pHdr + pHdr->offFrame + cbAlignedUsed); + pHdrPadding->u8Type = INTNETHDR_TYPE_PADDING; + pHdrPadding->cbFrame = cbAlignedFrame - cbAlignedUsed - sizeof(INTNETHDR); + Assert(pHdrPadding->cbFrame == cbAlignedFrame - cbAlignedUsed - sizeof(INTNETHDR)); + pHdrPadding->offFrame = sizeof(INTNETHDR); + pHdr->cbFrame = cbUsed; Assert(pHdr->cbFrame == cbUsed); + } + + Log2(("IntNetRingCommitFrameEx: offWriteCom: %#x -> %#x (R=%#x T=%#x S=%#x P=%#x)\n", pRingBuf->offWriteCom, offWriteCom, pRingBuf->offReadX, pHdr->u8Type, pHdr->cbFrame, cbAlignedFrame - cbAlignedUsed)); + ASMAtomicWriteU32(&pRingBuf->offWriteCom, offWriteCom); + STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbUsed); + STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames); +} + + +/** + * Writes a frame to the specified ring. + * + * Make sure you don't have any uncommitted frames when calling this function! + * + * @returns VINF_SUCCESS or VERR_BUFFER_OVERFLOW. + * @param pRingBuf The ring buffer. + * @param pvFrame The bits to write. + * @param cbFrame How much to write. + */ +DECLINLINE(int) IntNetRingWriteFrame(PINTNETRINGBUF pRingBuf, const void *pvFrame, size_t cbFrame) +{ + /* + * Validate input. + */ + INTNETRINGBUF_ASSERT_SANITY(pRingBuf); + Assert(cbFrame >= sizeof(RTMAC) * 2); + + /* + * Align the size and read the volatile ring buffer variables. + */ + const uint32_t cb = RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT); + uint32_t offWriteInt = ASMAtomicUoReadU32(&pRingBuf->offWriteInt); + uint32_t offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + if (offRead <= offWriteInt) + { + /* + * Try fit it all before the end of the buffer. + */ + if (pRingBuf->offEnd - offWriteInt >= cb + sizeof(INTNETHDR)) + { + uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR); + if (offNew >= pRingBuf->offEnd) + offNew = pRingBuf->offStart; + if (RT_LIKELY(ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt))) + { /* likely */ } else return VERR_WRONG_ORDER; /* race */ + Log2(("IntNetRingWriteFrame: offWriteInt: %#x -> %#x (1)\n", offWriteInt, offNew)); + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt); + pHdr->u8Type = INTNETHDR_TYPE_FRAME; + pHdr->cbFrame = cbFrame; Assert(pHdr->cbFrame == cbFrame); + pHdr->offFrame = sizeof(INTNETHDR); + + memcpy(pHdr + 1, pvFrame, cbFrame); + + Log2(("IntNetRingWriteFrame: offWriteCom: %#x -> %#x (1)\n", pRingBuf->offWriteCom, offNew)); + ASMAtomicWriteU32(&pRingBuf->offWriteCom, offNew); + STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame); + STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames); + return VINF_SUCCESS; + } + /* + * Try fit the frame at the start of the buffer. + * (The header fits before the end of the buffer because of alignment.) + */ + AssertMsg(pRingBuf->offEnd - offWriteInt >= sizeof(INTNETHDR), ("offEnd=%x offWriteInt=%x\n", pRingBuf->offEnd, offWriteInt)); + if (offRead - pRingBuf->offStart > cb) /* not >= ! */ + { + uint32_t offNew = pRingBuf->offStart + cb; + if (RT_LIKELY(ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt))) + { /* likely */ } else return VERR_WRONG_ORDER; /* race */ + Log2(("IntNetRingWriteFrame: offWriteInt: %#x -> %#x (2)\n", offWriteInt, offNew)); + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt); + pHdr->u8Type = INTNETHDR_TYPE_FRAME; + pHdr->cbFrame = cbFrame; Assert(pHdr->cbFrame == cbFrame); + pHdr->offFrame = pRingBuf->offStart - offWriteInt; + + memcpy((uint8_t *)pRingBuf + pRingBuf->offStart, pvFrame, cbFrame); + + Log2(("IntNetRingWriteFrame: offWriteCom: %#x -> %#x (2)\n", pRingBuf->offWriteCom, offNew)); + ASMAtomicWriteU32(&pRingBuf->offWriteCom, offNew); + STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame); + STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames); + return VINF_SUCCESS; + } + } + /* + * The reader is ahead of the writer, try fit it into that space. + */ + else if (offRead - offWriteInt > cb + sizeof(INTNETHDR)) /* not >= ! */ + { + uint32_t offNew = offWriteInt + cb + sizeof(INTNETHDR); + if (RT_LIKELY(ASMAtomicCmpXchgU32(&pRingBuf->offWriteInt, offNew, offWriteInt))) + { /* likely */ } else return VERR_WRONG_ORDER; /* race */ + Log2(("IntNetRingWriteFrame: offWriteInt: %#x -> %#x (3)\n", offWriteInt, offNew)); + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offWriteInt); + pHdr->u8Type = INTNETHDR_TYPE_FRAME; + pHdr->cbFrame = cbFrame; Assert(pHdr->cbFrame == cbFrame); + pHdr->offFrame = sizeof(INTNETHDR); + + memcpy(pHdr + 1, pvFrame, cbFrame); + + Log2(("IntNetRingWriteFrame: offWriteCom: %#x -> %#x (3)\n", pRingBuf->offWriteCom, offNew)); + ASMAtomicWriteU32(&pRingBuf->offWriteCom, offNew); + STAM_REL_COUNTER_ADD(&pRingBuf->cbStatWritten, cbFrame); + STAM_REL_COUNTER_INC(&pRingBuf->cStatFrames); + return VINF_SUCCESS; + } + + /* (it didn't fit) */ + STAM_REL_COUNTER_INC(&pRingBuf->cOverflows); + return VERR_BUFFER_OVERFLOW; +} + + +/** + * Reads the next frame in the buffer and moves the read cursor past it. + * + * @returns Size of the frame in bytes. 0 is returned if nothing in the buffer. + * @param pRingBuf The ring buffer to read from. + * @param pvFrameDst Where to put the frame. The caller is responsible for + * ensuring that there is sufficient space for the frame. + * + * @deprecated Bad interface, do NOT use it! Only for tstIntNetR0. + */ +DECLINLINE(uint32_t) IntNetRingReadAndSkipFrame(PINTNETRINGBUF pRingBuf, void *pvFrameDst) +{ + INTNETRINGBUF_ASSERT_SANITY(pRingBuf); + + uint32_t offRead = ASMAtomicUoReadU32(&pRingBuf->offReadX); + uint32_t const offWriteCom = ASMAtomicUoReadU32(&pRingBuf->offWriteCom); + if (offRead == offWriteCom) + return 0; + + PINTNETHDR pHdr = (PINTNETHDR)((uint8_t *)pRingBuf + offRead); + INTNETHDR_ASSERT_SANITY(pHdr, pRingBuf); + + uint32_t const cbFrame = pHdr->cbFrame; + int32_t const offFrame = pHdr->offFrame; + const void *pvFrameSrc = (uint8_t *)pHdr + offFrame; + memcpy(pvFrameDst, pvFrameSrc, cbFrame); +#ifdef INTNET_POISON_READ_FRAMES + memset((void *)pvFrameSrc, 0xfe, RT_ALIGN_32(cbFrame, INTNETHDR_ALIGNMENT)); + memset(pHdr, 0xef, sizeof(*pHdr)); +#endif + + /* skip the frame */ + offRead += offFrame + cbFrame; + offRead = RT_ALIGN_32(offRead, INTNETHDR_ALIGNMENT); + Assert(offRead <= pRingBuf->offEnd && offRead >= pRingBuf->offStart); + if (offRead >= pRingBuf->offEnd) + offRead = pRingBuf->offStart; + ASMAtomicWriteU32(&pRingBuf->offReadX, offRead); + return cbFrame; +} + + +/** + * Initializes a buffer structure. + * + * @param pIntBuf The internal networking interface buffer. This + * expected to be cleared prior to calling this + * function. + * @param cbBuf The size of the whole buffer. + * @param cbRecv The receive size. + * @param cbSend The send size. + */ +DECLINLINE(void) IntNetBufInit(PINTNETBUF pIntBuf, uint32_t cbBuf, uint32_t cbRecv, uint32_t cbSend) +{ + AssertCompileSizeAlignment(INTNETBUF, INTNETHDR_ALIGNMENT); + AssertCompileSizeAlignment(INTNETBUF, INTNETRINGBUF_ALIGNMENT); + Assert(cbBuf >= sizeof(INTNETBUF) + cbRecv + cbSend); + Assert(RT_ALIGN_32(cbRecv, INTNETRINGBUF_ALIGNMENT) == cbRecv); + Assert(RT_ALIGN_32(cbSend, INTNETRINGBUF_ALIGNMENT) == cbSend); + Assert(ASMMemIsZero(pIntBuf, cbBuf)); + + pIntBuf->u32Magic = INTNETBUF_MAGIC; + pIntBuf->cbBuf = cbBuf; + pIntBuf->cbRecv = cbRecv; + pIntBuf->cbSend = cbSend; + + /* receive ring buffer. */ + uint32_t offBuf = RT_ALIGN_32(sizeof(INTNETBUF), INTNETRINGBUF_ALIGNMENT) - RT_UOFFSETOF(INTNETBUF, Recv); + pIntBuf->Recv.offStart = offBuf; + pIntBuf->Recv.offReadX = offBuf; + pIntBuf->Recv.offWriteInt = offBuf; + pIntBuf->Recv.offWriteCom = offBuf; + pIntBuf->Recv.offEnd = offBuf + cbRecv; + + /* send ring buffer. */ + offBuf += cbRecv + RT_UOFFSETOF(INTNETBUF, Recv) - RT_UOFFSETOF(INTNETBUF, Send); + pIntBuf->Send.offStart = offBuf; + pIntBuf->Send.offReadX = offBuf; + pIntBuf->Send.offWriteCom = offBuf; + pIntBuf->Send.offWriteInt = offBuf; + pIntBuf->Send.offEnd = offBuf + cbSend; + Assert(cbBuf >= offBuf + cbSend); +} + +#endif /* __cplusplus */ + +#endif /* !VBOX_INCLUDED_intnetinline_h */ + diff --git a/include/VBox/iommu-amd.h b/include/VBox/iommu-amd.h new file mode 100644 index 00000000..76558831 --- /dev/null +++ b/include/VBox/iommu-amd.h @@ -0,0 +1,2718 @@ +/** @file + * IOMMU - Input/Output Memory Management Unit (AMD). + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_iommu_amd_h +#define VBOX_INCLUDED_iommu_amd_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +/** + * @name PCI configuration register offsets. + * In accordance with the AMD spec. + * @{ + */ +#define IOMMU_PCI_OFF_CAP_HDR 0x40 +#define IOMMU_PCI_OFF_BASE_ADDR_REG_LO 0x44 +#define IOMMU_PCI_OFF_BASE_ADDR_REG_HI 0x48 +#define IOMMU_PCI_OFF_RANGE_REG 0x4c +#define IOMMU_PCI_OFF_MISCINFO_REG_0 0x50 +#define IOMMU_PCI_OFF_MISCINFO_REG_1 0x54 +#define IOMMU_PCI_OFF_MSI_CAP_HDR 0x64 +#define IOMMU_PCI_OFF_MSI_ADDR_LO 0x68 +#define IOMMU_PCI_OFF_MSI_ADDR_HI 0x6c +#define IOMMU_PCI_OFF_MSI_DATA 0x70 +#define IOMMU_PCI_OFF_MSI_MAP_CAP_HDR 0x74 +/** @} */ + +/** + * @name MMIO register offsets. + * In accordance with the AMD spec. + * @{ + */ +#define IOMMU_MMIO_OFF_QWORD_TABLE_0_START IOMMU_MMIO_OFF_DEV_TAB_BAR +#define IOMMU_MMIO_OFF_DEV_TAB_BAR 0x00 +#define IOMMU_MMIO_OFF_CMD_BUF_BAR 0x08 +#define IOMMU_MMIO_OFF_EVT_LOG_BAR 0x10 +#define IOMMU_MMIO_OFF_CTRL 0x18 +#define IOMMU_MMIO_OFF_EXCL_BAR 0x20 +#define IOMMU_MMIO_OFF_EXCL_RANGE_LIMIT 0x28 +#define IOMMU_MMIO_OFF_EXT_FEAT 0x30 + +#define IOMMU_MMIO_OFF_PPR_LOG_BAR 0x38 +#define IOMMU_MMIO_OFF_HW_EVT_HI 0x40 +#define IOMMU_MMIO_OFF_HW_EVT_LO 0x48 +#define IOMMU_MMIO_OFF_HW_EVT_STATUS 0x50 + +#define IOMMU_MMIO_OFF_SMI_FLT_FIRST 0x60 +#define IOMMU_MMIO_OFF_SMI_FLT_LAST 0xd8 + +#define IOMMU_MMIO_OFF_GALOG_BAR 0xe0 +#define IOMMU_MMIO_OFF_GALOG_TAIL_ADDR 0xe8 + +#define IOMMU_MMIO_OFF_PPR_LOG_B_BAR 0xf0 +#define IOMMU_MMIO_OFF_PPR_EVT_B_BAR 0xf8 + +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_FIRST 0x100 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_1 0x100 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_2 0x108 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_3 0x110 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_4 0x118 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_5 0x120 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_6 0x128 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_7 0x130 +#define IOMMU_MMIO_OFF_DEV_TAB_SEG_LAST 0x130 + +#define IOMMU_MMIO_OFF_DEV_SPECIFIC_FEAT 0x138 +#define IOMMU_MMIO_OFF_DEV_SPECIFIC_CTRL 0x140 +#define IOMMU_MMIO_OFF_DEV_SPECIFIC_STATUS 0x148 + +#define IOMMU_MMIO_OFF_MSI_VECTOR_0 0x150 +#define IOMMU_MMIO_OFF_MSI_VECTOR_1 0x154 +#define IOMMU_MMIO_OFF_MSI_CAP_HDR 0x158 +#define IOMMU_MMIO_OFF_MSI_ADDR_LO 0x15c +#define IOMMU_MMIO_OFF_MSI_ADDR_HI 0x160 +#define IOMMU_MMIO_OFF_MSI_DATA 0x164 +#define IOMMU_MMIO_OFF_MSI_MAPPING_CAP_HDR 0x168 + +#define IOMMU_MMIO_OFF_PERF_OPT_CTRL 0x16c + +#define IOMMU_MMIO_OFF_XT_GEN_INTR_CTRL 0x170 +#define IOMMU_MMIO_OFF_XT_PPR_INTR_CTRL 0x178 +#define IOMMU_MMIO_OFF_XT_GALOG_INT_CTRL 0x180 +#define IOMMU_MMIO_OFF_QWORD_TABLE_0_END (IOMMU_MMIO_OFF_XT_GALOG_INT_CTRL + 8) + +#define IOMMU_MMIO_OFF_QWORD_TABLE_1_START IOMMU_MMIO_OFF_MARC_APER_BAR_0 +#define IOMMU_MMIO_OFF_MARC_APER_BAR_0 0x200 +#define IOMMU_MMIO_OFF_MARC_APER_RELOC_0 0x208 +#define IOMMU_MMIO_OFF_MARC_APER_LEN_0 0x210 +#define IOMMU_MMIO_OFF_MARC_APER_BAR_1 0x218 +#define IOMMU_MMIO_OFF_MARC_APER_RELOC_1 0x220 +#define IOMMU_MMIO_OFF_MARC_APER_LEN_1 0x228 +#define IOMMU_MMIO_OFF_MARC_APER_BAR_2 0x230 +#define IOMMU_MMIO_OFF_MARC_APER_RELOC_2 0x238 +#define IOMMU_MMIO_OFF_MARC_APER_LEN_2 0x240 +#define IOMMU_MMIO_OFF_MARC_APER_BAR_3 0x248 +#define IOMMU_MMIO_OFF_MARC_APER_RELOC_3 0x250 +#define IOMMU_MMIO_OFF_MARC_APER_LEN_3 0x258 +#define IOMMU_MMIO_OFF_QWORD_TABLE_1_END (IOMMU_MMIO_OFF_MARC_APER_LEN_3 + 8) + +#define IOMMU_MMIO_OFF_QWORD_TABLE_2_START IOMMU_MMIO_OFF_RSVD_REG +#define IOMMU_MMIO_OFF_RSVD_REG 0x1ff8 + +#define IOMMU_MMIO_OFF_CMD_BUF_HEAD_PTR 0x2000 +#define IOMMU_MMIO_OFF_CMD_BUF_TAIL_PTR 0x2008 +#define IOMMU_MMIO_OFF_EVT_LOG_HEAD_PTR 0x2010 +#define IOMMU_MMIO_OFF_EVT_LOG_TAIL_PTR 0x2018 + +#define IOMMU_MMIO_OFF_STATUS 0x2020 + +#define IOMMU_MMIO_OFF_PPR_LOG_HEAD_PTR 0x2030 +#define IOMMU_MMIO_OFF_PPR_LOG_TAIL_PTR 0x2038 + +#define IOMMU_MMIO_OFF_GALOG_HEAD_PTR 0x2040 +#define IOMMU_MMIO_OFF_GALOG_TAIL_PTR 0x2048 + +#define IOMMU_MMIO_OFF_PPR_LOG_B_HEAD_PTR 0x2050 +#define IOMMU_MMIO_OFF_PPR_LOG_B_TAIL_PTR 0x2058 + +#define IOMMU_MMIO_OFF_EVT_LOG_B_HEAD_PTR 0x2070 +#define IOMMU_MMIO_OFF_EVT_LOG_B_TAIL_PTR 0x2078 + +#define IOMMU_MMIO_OFF_PPR_LOG_AUTO_RESP 0x2080 +#define IOMMU_MMIO_OFF_PPR_LOG_OVERFLOW_EARLY 0x2088 +#define IOMMU_MMIO_OFF_PPR_LOG_B_OVERFLOW_EARLY 0x2090 +#define IOMMU_MMIO_OFF_QWORD_TABLE_2_END (IOMMU_MMIO_OFF_PPR_LOG_B_OVERFLOW_EARLY + 8) +/** @} */ + +/** + * @name MMIO register-access table offsets. + * Each table [first..last] (both inclusive) represents the range of registers + * covered by a distinct register-access table. This is done due to arbitrary large + * gaps in the MMIO register offsets themselves. + * @{ + */ +#define IOMMU_MMIO_OFF_TABLE_0_FIRST 0x00 +#define IOMMU_MMIO_OFF_TABLE_0_LAST 0x258 + +#define IOMMU_MMIO_OFF_TABLE_1_FIRST 0x1ff8 +#define IOMMU_MMIO_OFF_TABLE_1_LAST 0x2090 +/** @} */ + +/** + * @name Commands. + * In accordance with the AMD spec. + * @{ + */ +#define IOMMU_CMD_COMPLETION_WAIT 0x01 +#define IOMMU_CMD_INV_DEV_TAB_ENTRY 0x02 +#define IOMMU_CMD_INV_IOMMU_PAGES 0x03 +#define IOMMU_CMD_INV_IOTLB_PAGES 0x04 +#define IOMMU_CMD_INV_INTR_TABLE 0x05 +#define IOMMU_CMD_PREFETCH_IOMMU_PAGES 0x06 +#define IOMMU_CMD_COMPLETE_PPR_REQ 0x07 +#define IOMMU_CMD_INV_IOMMU_ALL 0x08 +/** @} */ + +/** + * @name Event codes. + * In accordance with the AMD spec. + * @{ + */ +#define IOMMU_EVT_ILLEGAL_DEV_TAB_ENTRY 0x01 +#define IOMMU_EVT_IO_PAGE_FAULT 0x02 +#define IOMMU_EVT_DEV_TAB_HW_ERROR 0x03 +#define IOMMU_EVT_PAGE_TAB_HW_ERROR 0x04 +#define IOMMU_EVT_ILLEGAL_CMD_ERROR 0x05 +#define IOMMU_EVT_COMMAND_HW_ERROR 0x06 +#define IOMMU_EVT_IOTLB_INV_TIMEOUT 0x07 +#define IOMMU_EVT_INVALID_DEV_REQ 0x08 +#define IOMMU_EVT_INVALID_PPR_REQ 0x09 +#define IOMMU_EVT_EVENT_COUNTER_ZERO 0x10 +#define IOMMU_EVT_GUEST_EVENT_FAULT 0x11 +/** @} */ + +/** + * @name IOMMU Capability Header. + * In accordance with the AMD spec. + * @{ + */ +/** CapId: Capability ID. */ +#define IOMMU_BF_CAPHDR_CAP_ID_SHIFT 0 +#define IOMMU_BF_CAPHDR_CAP_ID_MASK UINT32_C(0x000000ff) +/** CapPtr: Capability Pointer. */ +#define IOMMU_BF_CAPHDR_CAP_PTR_SHIFT 8 +#define IOMMU_BF_CAPHDR_CAP_PTR_MASK UINT32_C(0x0000ff00) +/** CapType: Capability Type. */ +#define IOMMU_BF_CAPHDR_CAP_TYPE_SHIFT 16 +#define IOMMU_BF_CAPHDR_CAP_TYPE_MASK UINT32_C(0x00070000) +/** CapRev: Capability Revision. */ +#define IOMMU_BF_CAPHDR_CAP_REV_SHIFT 19 +#define IOMMU_BF_CAPHDR_CAP_REV_MASK UINT32_C(0x00f80000) +/** IoTlbSup: IO TLB Support. */ +#define IOMMU_BF_CAPHDR_IOTLB_SUP_SHIFT 24 +#define IOMMU_BF_CAPHDR_IOTLB_SUP_MASK UINT32_C(0x01000000) +/** HtTunnel: HyperTransport Tunnel translation support. */ +#define IOMMU_BF_CAPHDR_HT_TUNNEL_SHIFT 25 +#define IOMMU_BF_CAPHDR_HT_TUNNEL_MASK UINT32_C(0x02000000) +/** NpCache: Not Present table entries Cached. */ +#define IOMMU_BF_CAPHDR_NP_CACHE_SHIFT 26 +#define IOMMU_BF_CAPHDR_NP_CACHE_MASK UINT32_C(0x04000000) +/** EFRSup: Extended Feature Register (EFR) Supported. */ +#define IOMMU_BF_CAPHDR_EFR_SUP_SHIFT 27 +#define IOMMU_BF_CAPHDR_EFR_SUP_MASK UINT32_C(0x08000000) +/** CapExt: Miscellaneous Information Register Supported . */ +#define IOMMU_BF_CAPHDR_CAP_EXT_SHIFT 28 +#define IOMMU_BF_CAPHDR_CAP_EXT_MASK UINT32_C(0x10000000) +/** Bits 31:29 reserved. */ +#define IOMMU_BF_CAPHDR_RSVD_29_31_SHIFT 29 +#define IOMMU_BF_CAPHDR_RSVD_29_31_MASK UINT32_C(0xe0000000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_CAPHDR_, UINT32_C(0), UINT32_MAX, + (CAP_ID, CAP_PTR, CAP_TYPE, CAP_REV, IOTLB_SUP, HT_TUNNEL, NP_CACHE, EFR_SUP, CAP_EXT, RSVD_29_31)); +/** @} */ + +/** + * @name IOMMU Base Address Low Register. + * In accordance with the AMD spec. + * @{ + */ +/** Enable: Enables access to the address specified in the Base Address Register. */ +#define IOMMU_BF_BASEADDR_LO_ENABLE_SHIFT 0 +#define IOMMU_BF_BASEADDR_LO_ENABLE_MASK UINT32_C(0x00000001) +/** Bits 13:1 reserved. */ +#define IOMMU_BF_BASEADDR_LO_RSVD_1_13_SHIFT 1 +#define IOMMU_BF_BASEADDR_LO_RSVD_1_13_MASK UINT32_C(0x00003ffe) +/** Base Address[31:14]: Low Base address of IOMMU MMIO control registers. */ +#define IOMMU_BF_BASEADDR_LO_ADDR_SHIFT 14 +#define IOMMU_BF_BASEADDR_LO_ADDR_MASK UINT32_C(0xffffc000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_BASEADDR_LO_, UINT32_C(0), UINT32_MAX, + (ENABLE, RSVD_1_13, ADDR)); +/** @} */ + +/** + * @name IOMMU Range Register. + * In accordance with the AMD spec. + * @{ + */ +/** UnitID: HyperTransport Unit ID. */ +#define IOMMU_BF_RANGE_UNIT_ID_SHIFT 0 +#define IOMMU_BF_RANGE_UNIT_ID_MASK UINT32_C(0x0000001f) +/** Bits 6:5 reserved. */ +#define IOMMU_BF_RANGE_RSVD_5_6_SHIFT 5 +#define IOMMU_BF_RANGE_RSVD_5_6_MASK UINT32_C(0x00000060) +/** RngValid: Range valid. */ +#define IOMMU_BF_RANGE_VALID_SHIFT 7 +#define IOMMU_BF_RANGE_VALID_MASK UINT32_C(0x00000080) +/** BusNumber: Device range bus number. */ +#define IOMMU_BF_RANGE_BUS_NUMBER_SHIFT 8 +#define IOMMU_BF_RANGE_BUS_NUMBER_MASK UINT32_C(0x0000ff00) +/** First Device. */ +#define IOMMU_BF_RANGE_FIRST_DEVICE_SHIFT 16 +#define IOMMU_BF_RANGE_FIRST_DEVICE_MASK UINT32_C(0x00ff0000) +/** Last Device. */ +#define IOMMU_BF_RANGE_LAST_DEVICE_SHIFT 24 +#define IOMMU_BF_RANGE_LAST_DEVICE_MASK UINT32_C(0xff000000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_RANGE_, UINT32_C(0), UINT32_MAX, + (UNIT_ID, RSVD_5_6, VALID, BUS_NUMBER, FIRST_DEVICE, LAST_DEVICE)); +/** @} */ + +/** + * @name IOMMU Miscellaneous Information Register 0. + * In accordance with the AMD spec. + * @{ + */ +/** MsiNum: MSI message number. */ +#define IOMMU_BF_MISCINFO_0_MSI_NUM_SHIFT 0 +#define IOMMU_BF_MISCINFO_0_MSI_NUM_MASK UINT32_C(0x0000001f) +/** GvaSize: Guest Virtual Address Size. */ +#define IOMMU_BF_MISCINFO_0_GVA_SIZE_SHIFT 5 +#define IOMMU_BF_MISCINFO_0_GVA_SIZE_MASK UINT32_C(0x000000e0) +/** PaSize: Physical Address Size. */ +#define IOMMU_BF_MISCINFO_0_PA_SIZE_SHIFT 8 +#define IOMMU_BF_MISCINFO_0_PA_SIZE_MASK UINT32_C(0x00007f00) +/** VaSize: Virtual Address Size. */ +#define IOMMU_BF_MISCINFO_0_VA_SIZE_SHIFT 15 +#define IOMMU_BF_MISCINFO_0_VA_SIZE_MASK UINT32_C(0x003f8000) +/** HtAtsResv: HyperTransport ATS Response Address range Reserved. */ +#define IOMMU_BF_MISCINFO_0_HT_ATS_RESV_SHIFT 22 +#define IOMMU_BF_MISCINFO_0_HT_ATS_RESV_MASK UINT32_C(0x00400000) +/** Bits 26:23 reserved. */ +#define IOMMU_BF_MISCINFO_0_RSVD_23_26_SHIFT 23 +#define IOMMU_BF_MISCINFO_0_RSVD_23_26_MASK UINT32_C(0x07800000) +/** MsiNumPPR: Peripheral Page Request MSI message number. */ +#define IOMMU_BF_MISCINFO_0_MSI_NUM_PPR_SHIFT 27 +#define IOMMU_BF_MISCINFO_0_MSI_NUM_PPR_MASK UINT32_C(0xf8000000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_MISCINFO_0_, UINT32_C(0), UINT32_MAX, + (MSI_NUM, GVA_SIZE, PA_SIZE, VA_SIZE, HT_ATS_RESV, RSVD_23_26, MSI_NUM_PPR)); +/** @} */ + +/** + * @name IOMMU Miscellaneous Information Register 1. + * In accordance with the AMD spec. + * @{ + */ +/** MsiNumGA: MSI message number for guest virtual-APIC log. */ +#define IOMMU_BF_MISCINFO_1_MSI_NUM_GA_SHIFT 0 +#define IOMMU_BF_MISCINFO_1_MSI_NUM_GA_MASK UINT32_C(0x0000001f) +/** Bits 31:5 reserved. */ +#define IOMMU_BF_MISCINFO_1_RSVD_5_31_SHIFT 5 +#define IOMMU_BF_MISCINFO_1_RSVD_5_31_MASK UINT32_C(0xffffffe0) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_MISCINFO_1_, UINT32_C(0), UINT32_MAX, + (MSI_NUM_GA, RSVD_5_31)); +/** @} */ + +/** + * @name MSI Capability Header Register. + * In accordance with the AMD spec. + * @{ + */ +/** MsiCapId: Capability ID. */ +#define IOMMU_BF_MSI_CAP_HDR_CAP_ID_SHIFT 0 +#define IOMMU_BF_MSI_CAP_HDR_CAP_ID_MASK UINT32_C(0x000000ff) +/** MsiCapPtr: Pointer (PCI config offset) to the next capability. */ +#define IOMMU_BF_MSI_CAP_HDR_CAP_PTR_SHIFT 8 +#define IOMMU_BF_MSI_CAP_HDR_CAP_PTR_MASK UINT32_C(0x0000ff00) +/** MsiEn: Message Signal Interrupt enable. */ +#define IOMMU_BF_MSI_CAP_HDR_EN_SHIFT 16 +#define IOMMU_BF_MSI_CAP_HDR_EN_MASK UINT32_C(0x00010000) +/** MsiMultMessCap: MSI Multi-Message Capability. */ +#define IOMMU_BF_MSI_CAP_HDR_MULTMESS_CAP_SHIFT 17 +#define IOMMU_BF_MSI_CAP_HDR_MULTMESS_CAP_MASK UINT32_C(0x000e0000) +/** MsiMultMessEn: MSI Mult-Message Enable. */ +#define IOMMU_BF_MSI_CAP_HDR_MULTMESS_EN_SHIFT 20 +#define IOMMU_BF_MSI_CAP_HDR_MULTMESS_EN_MASK UINT32_C(0x00700000) +/** Msi64BitEn: MSI 64-bit Enabled. */ +#define IOMMU_BF_MSI_CAP_HDR_64BIT_EN_SHIFT 23 +#define IOMMU_BF_MSI_CAP_HDR_64BIT_EN_MASK UINT32_C(0x00800000) +/** Bits 31:24 reserved. */ +#define IOMMU_BF_MSI_CAP_HDR_RSVD_24_31_SHIFT 24 +#define IOMMU_BF_MSI_CAP_HDR_RSVD_24_31_MASK UINT32_C(0xff000000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_MSI_CAP_HDR_, UINT32_C(0), UINT32_MAX, + (CAP_ID, CAP_PTR, EN, MULTMESS_CAP, MULTMESS_EN, 64BIT_EN, RSVD_24_31)); +/** @} */ + +/** + * @name MSI Mapping Capability Header Register. + * In accordance with the AMD spec. + * @{ + */ +/** MsiMapCapId: Capability ID. */ +#define IOMMU_BF_MSI_MAP_CAPHDR_CAP_ID_SHIFT 0 +#define IOMMU_BF_MSI_MAP_CAPHDR_CAP_ID_MASK UINT32_C(0x000000ff) +/** MsiMapCapPtr: Pointer (PCI config offset) to the next capability. */ +#define IOMMU_BF_MSI_MAP_CAPHDR_CAP_PTR_SHIFT 8 +#define IOMMU_BF_MSI_MAP_CAPHDR_CAP_PTR_MASK UINT32_C(0x0000ff00) +/** MsiMapEn: MSI mapping capability enable. */ +#define IOMMU_BF_MSI_MAP_CAPHDR_EN_SHIFT 16 +#define IOMMU_BF_MSI_MAP_CAPHDR_EN_MASK UINT32_C(0x00010000) +/** MsiMapFixd: MSI interrupt mapping range is not programmable. */ +#define IOMMU_BF_MSI_MAP_CAPHDR_FIXED_SHIFT 17 +#define IOMMU_BF_MSI_MAP_CAPHDR_FIXED_MASK UINT32_C(0x00020000) +/** Bits 18:28 reserved. */ +#define IOMMU_BF_MSI_MAP_CAPHDR_RSVD_18_28_SHIFT 18 +#define IOMMU_BF_MSI_MAP_CAPHDR_RSVD_18_28_MASK UINT32_C(0x07fc0000) +/** MsiMapCapType: MSI mapping capability. */ +#define IOMMU_BF_MSI_MAP_CAPHDR_CAP_TYPE_SHIFT 27 +#define IOMMU_BF_MSI_MAP_CAPHDR_CAP_TYPE_MASK UINT32_C(0xf8000000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_MSI_MAP_CAPHDR_, UINT32_C(0), UINT32_MAX, + (CAP_ID, CAP_PTR, EN, FIXED, RSVD_18_28, CAP_TYPE)); +/** @} */ + +/** + * @name IOMMU Status Register Bits. + * In accordance with the AMD spec. + * @{ + */ +/** EventOverflow: Event log overflow. */ +#define IOMMU_STATUS_EVT_LOG_OVERFLOW RT_BIT_64(0) +/** EventLogInt: Event log interrupt. */ +#define IOMMU_STATUS_EVT_LOG_INTR RT_BIT_64(1) +/** ComWaitInt: Completion wait interrupt. */ +#define IOMMU_STATUS_COMPLETION_WAIT_INTR RT_BIT_64(2) +/** EventLogRun: Event log is running. */ +#define IOMMU_STATUS_EVT_LOG_RUNNING RT_BIT_64(3) +/** CmdBufRun: Command buffer is running. */ +#define IOMMU_STATUS_CMD_BUF_RUNNING RT_BIT_64(4) +/** PprOverflow: Peripheral page request log overflow. */ +#define IOMMU_STATUS_PPR_LOG_OVERFLOW RT_BIT_64(5) +/** PprInt: Peripheral page request log interrupt. */ +#define IOMMU_STATUS_PPR_LOG_INTR RT_BIT_64(6) +/** PprLogRun: Peripheral page request log is running. */ +#define IOMMU_STATUS_PPR_LOG_RUN RT_BIT_64(7) +/** GALogRun: Guest virtual-APIC log is running. */ +#define IOMMU_STATUS_GA_LOG_RUN RT_BIT_64(8) +/** GALOverflow: Guest virtual-APIC log overflow. */ +#define IOMMU_STATUS_GA_LOG_OVERFLOW RT_BIT_64(9) +/** GAInt: Guest virtual-APIC log interrupt. */ +#define IOMMU_STATUS_GA_LOG_INTR RT_BIT_64(10) +/** PprOvrflwB: PPR Log B overflow. */ +#define IOMMU_STATUS_PPR_LOG_B_OVERFLOW RT_BIT_64(11) +/** PprLogActive: PPR Log B is active. */ +#define IOMMU_STATUS_PPR_LOG_B_ACTIVE RT_BIT_64(12) +/** EvtOvrflwB: Event log B overflow. */ +#define IOMMU_STATUS_EVT_LOG_B_OVERFLOW RT_BIT_64(15) +/** EventLogActive: Event log B active. */ +#define IOMMU_STATUS_EVT_LOG_B_ACTIVE RT_BIT_64(16) +/** PprOvrflwEarlyB: PPR log B overflow early warning. */ +#define IOMMU_STATUS_PPR_LOG_B_OVERFLOW_EARLY RT_BIT_64(17) +/** PprOverflowEarly: PPR log overflow early warning. */ +#define IOMMU_STATUS_PPR_LOG_OVERFLOW_EARLY RT_BIT_64(18) +/** @} */ + +/** @name IOMMU_IO_PERM_XXX: IOMMU I/O access permissions bits. + * In accordance with the AMD spec. + * + * These values match the shifted values of the IR and IW field of the DTE and the + * PTE, PDE of the I/O page tables. + * + * @{ */ +#define IOMMU_IO_PERM_NONE (0) +#define IOMMU_IO_PERM_READ RT_BIT_64(0) +#define IOMMU_IO_PERM_WRITE RT_BIT_64(1) +#define IOMMU_IO_PERM_READ_WRITE (IOMMU_IO_PERM_READ | IOMMU_IO_PERM_WRITE) +#define IOMMU_IO_PERM_SHIFT 61 +#define IOMMU_IO_PERM_MASK 0x3 +/** @} */ + +/** @name SYSMGT_TYPE_XXX: System Management Message Enable Types. + * In accordance with the AMD spec. + * @{ */ +#define SYSMGTTYPE_DMA_DENY (0) +#define SYSMGTTYPE_MSG_ALL_ALLOW (1) +#define SYSMGTTYPE_MSG_INT_ALLOW (2) +#define SYSMGTTYPE_DMA_ALLOW (3) +/** @} */ + +/** @name IOMMU_INTR_CTRL_XX: DTE::IntCtl field values. + * These are control bits for handling fixed and arbitrated interrupts. + * In accordance with the AMD spec. + * @{ */ +#define IOMMU_INTR_CTRL_TARGET_ABORT (0) +#define IOMMU_INTR_CTRL_FWD_UNMAPPED (1) +#define IOMMU_INTR_CTRL_REMAP (2) +#define IOMMU_INTR_CTRL_RSVD (3) +/** @} */ + +/** Gets the device table length (in bytes) given the device table pointer. */ +#define IOMMU_GET_DEV_TAB_LEN(a_pDevTab) (((a_pDevTab)->n.u9Size + 1) << X86_PAGE_4K_SHIFT) + +/** + * The Device ID. + * In accordance with VirtualBox's PCI configuration. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint16_t u3Function : 3; /**< Bits 2:0 - Function. */ + RT_GCC_EXTENSION uint16_t u9Device : 9; /**< Bits 11:3 - Device. */ + RT_GCC_EXTENSION uint16_t u4Bus : 4; /**< Bits 15:12 - Bus. */ + } n; + /** The unsigned integer view. */ + uint16_t u; +} DEVICE_ID_T; +AssertCompileSize(DEVICE_ID_T, 2); + +/** + * Device Table Entry (DTE). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u1Valid : 1; /**< Bit 0 - V: Valid. */ + RT_GCC_EXTENSION uint64_t u1TranslationValid : 1; /**< Bit 1 - TV: Translation information Valid. */ + RT_GCC_EXTENSION uint64_t u5Rsvd0 : 5; /**< Bits 6:2 - Reserved. */ + RT_GCC_EXTENSION uint64_t u2Had : 2; /**< Bits 8:7 - HAD: Host Access Dirty. */ + RT_GCC_EXTENSION uint64_t u3Mode : 3; /**< Bits 11:9 - Mode: Paging mode. */ + RT_GCC_EXTENSION uint64_t u40PageTableRootPtrLo : 40; /**< Bits 51:12 - Page Table Root Pointer. */ + RT_GCC_EXTENSION uint64_t u1Ppr : 1; /**< Bit 52 - PPR: Peripheral Page Request. */ + RT_GCC_EXTENSION uint64_t u1GstPprRespPasid : 1; /**< Bit 53 - GRPR: Guest PPR Response with PASID. */ + RT_GCC_EXTENSION uint64_t u1GstIoValid : 1; /**< Bit 54 - GIoV: Guest I/O Protection Valid. */ + RT_GCC_EXTENSION uint64_t u1GstTranslateValid : 1; /**< Bit 55 - GV: Guest translation Valid. */ + RT_GCC_EXTENSION uint64_t u2GstMode : 2; /**< Bits 57:56 - GLX: Guest Paging mode levels. */ + RT_GCC_EXTENSION uint64_t u3GstCr3TableRootPtrLo : 3; /**< Bits 60:58 - GCR3 TRP: Guest CR3 Table Root Ptr (Lo). */ + RT_GCC_EXTENSION uint64_t u1IoRead : 1; /**< Bit 61 - IR: I/O Read permission. */ + RT_GCC_EXTENSION uint64_t u1IoWrite : 1; /**< Bit 62 - IW: I/O Write permission. */ + RT_GCC_EXTENSION uint64_t u1Rsvd0 : 1; /**< Bit 63 - Reserved. */ + RT_GCC_EXTENSION uint64_t u16DomainId : 16; /**< Bits 79:64 - Domain ID. */ + RT_GCC_EXTENSION uint64_t u16GstCr3TableRootPtrMid : 16; /**< Bits 95:80 - GCR3 TRP: Guest CR3 Table Root Ptr (Mid). */ + RT_GCC_EXTENSION uint64_t u1IoTlbEnable : 1; /**< Bit 96 - I: IOTLB Enable (remote). */ + RT_GCC_EXTENSION uint64_t u1SuppressPfEvents : 1; /**< Bit 97 - SE: Suppress Page-fault events. */ + RT_GCC_EXTENSION uint64_t u1SuppressAllPfEvents : 1; /**< Bit 98 - SA: Suppress All Page-fault events. */ + RT_GCC_EXTENSION uint64_t u2IoCtl : 2; /**< Bits 100:99 - IoCtl: Port I/O Control. */ + RT_GCC_EXTENSION uint64_t u1Cache : 1; /**< Bit 101 - Cache: IOTLB Cache Hint. */ + RT_GCC_EXTENSION uint64_t u1SnoopDisable : 1; /**< Bit 102 - SD: Snoop Disable. */ + RT_GCC_EXTENSION uint64_t u1AllowExclusion : 1; /**< Bit 103 - EX: Allow Exclusion. */ + RT_GCC_EXTENSION uint64_t u2SysMgt : 2; /**< Bits 105:104 - SysMgt: System Management message enable. */ + RT_GCC_EXTENSION uint64_t u1Rsvd1 : 1; /**< Bit 106 - Reserved. */ + RT_GCC_EXTENSION uint64_t u21GstCr3TableRootPtrHi : 21; /**< Bits 127:107 - GCR3 TRP: Guest CR3 Table Root Ptr (Hi). */ + RT_GCC_EXTENSION uint64_t u1IntrMapValid : 1; /**< Bit 128 - IV: Interrupt map Valid. */ + RT_GCC_EXTENSION uint64_t u4IntrTableLength : 4; /**< Bits 132:129 - IntTabLen: Interrupt Table Length. */ + RT_GCC_EXTENSION uint64_t u1IgnoreUnmappedIntrs : 1; /**< Bits 133 - IG: Ignore unmapped interrupts. */ + RT_GCC_EXTENSION uint64_t u46IntrTableRootPtr : 46; /**< Bits 179:134 - Interrupt Root Table Pointer. */ + RT_GCC_EXTENSION uint64_t u4Rsvd0 : 4; /**< Bits 183:180 - Reserved. */ + RT_GCC_EXTENSION uint64_t u1InitPassthru : 1; /**< Bits 184 - INIT Pass-through. */ + RT_GCC_EXTENSION uint64_t u1ExtIntPassthru : 1; /**< Bits 185 - External Interrupt Pass-through. */ + RT_GCC_EXTENSION uint64_t u1NmiPassthru : 1; /**< Bits 186 - NMI Pass-through. */ + RT_GCC_EXTENSION uint64_t u1Rsvd2 : 1; /**< Bits 187 - Reserved. */ + RT_GCC_EXTENSION uint64_t u2IntrCtrl : 2; /**< Bits 189:188 - IntCtl: Interrupt Control. */ + RT_GCC_EXTENSION uint64_t u1Lint0Passthru : 1; /**< Bit 190 - Lint0Pass: LINT0 Pass-through. */ + RT_GCC_EXTENSION uint64_t u1Lint1Passthru : 1; /**< Bit 191 - Lint1Pass: LINT1 Pass-through. */ + RT_GCC_EXTENSION uint64_t u32Rsvd0 : 32; /**< Bits 223:192 - Reserved. */ + RT_GCC_EXTENSION uint64_t u22Rsvd0 : 22; /**< Bits 245:224 - Reserved. */ + RT_GCC_EXTENSION uint64_t u1AttrOverride : 1; /**< Bit 246 - AttrV: Attribute Override. */ + RT_GCC_EXTENSION uint64_t u1Mode0FC : 1; /**< Bit 247 - Mode0FC. */ + RT_GCC_EXTENSION uint64_t u8SnoopAttr : 8; /**< Bits 255:248 - Snoop Attribute. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[8]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[4]; +} DTE_T; +AssertCompileSize(DTE_T, 32); +/** Pointer to a device table entry. */ +typedef DTE_T *PDTE_T; +/** Pointer to a const device table entry. */ +typedef DTE_T const *PCDTE_T; + +/** Mask of valid bits for EPHSUP (Enhanced Peripheral Page Request Handling + * Support) feature (bits 52:53). */ +#define IOMMU_DTE_QWORD_0_FEAT_EPHSUP_MASK UINT64_C(0x0030000000000000) + +/** Mask of valid bits for GTSup (Guest Translation Support) feature (bits 55:60, + * bits 80:95). */ +#define IOMMU_DTE_QWORD_0_FEAT_GTSUP_MASK UINT64_C(0x1f80000000000000) +#define IOMMU_DTE_QWORD_1_FEAT_GTSUP_MASK UINT64_C(0x00000000ffff0000) + +/** Mask of valid bits for GIoSup (Guest I/O Protection Support) feature (bit 54). */ +#define IOMMU_DTE_QWORD_0_FEAT_GIOSUP_MASK UINT64_C(0x0040000000000000) + +/** Mask of valid DTE feature bits. */ +#define IOMMU_DTE_QWORD_0_FEAT_MASK ( IOMMU_DTE_QWORD_0_FEAT_EPHSUP_MASK \ + | IOMMU_DTE_QWORD_0_FEAT_GTSUP_MASK \ + | IOMMU_DTE_QWORD_0_FEAT_GIOSUP_MASK) +#define IOMMU_DTE_QWORD_1_FEAT_MASK IOMMU_DTE_QWORD_0_FEAT_GIOSUP_MASK + +/** Mask of all valid DTE bits (including all feature bits). */ +#define IOMMU_DTE_QWORD_0_VALID_MASK UINT64_C(0x7fffffffffffff83) +#define IOMMU_DTE_QWORD_1_VALID_MASK UINT64_C(0xfffffbffffffffff) +#define IOMMU_DTE_QWORD_2_VALID_MASK UINT64_C(0xff0fffffffffffff) +#define IOMMU_DTE_QWORD_3_VALID_MASK UINT64_C(0xffc0000000000000) + +/** Mask of the interrupt table root pointer. */ +#define IOMMU_DTE_IRTE_ROOT_PTR_MASK UINT64_C(0x000fffffffffffc0) +/** Number of bits to shift to get the interrupt root table pointer at + qword 2 (qword 0 being the first one) - 128-byte aligned. */ +#define IOMMU_DTE_IRTE_ROOT_PTR_SHIFT 6 + +/** Maximum encoded IRTE length (exclusive). */ +#define IOMMU_DTE_INTR_TAB_LEN_MAX 12 +/** Gets the interrupt table entries (in bytes) given the DTE pointer. */ +#define IOMMU_DTE_GET_INTR_TAB_ENTRIES(a_pDte) (UINT64_C(1) << (a_pDte)->n.u4IntrTableLength) +/** Gets the interrupt table length (in bytes) given the DTE pointer. */ +#define IOMMU_DTE_GET_INTR_TAB_LEN(a_pDte) (IOMMU_DTE_GET_INTR_TAB_ENTRIES(a_pDte) * sizeof(IRTE_T)) +/** Mask of interrupt control bits. */ +#define IOMMU_DTE_INTR_CTRL_MASK 0x3 +/** Gets the interrupt control bits from the DTE. */ +#define IOMMU_DTE_GET_INTR_CTRL(a_pDte) (((a_pDte)->au64[2] >> 60) & IOMMU_DTE_INTR_CTRL_MASK) +/** Gets the ignore unmapped interrupt bit from DTE. */ +#define IOMMU_DTE_GET_IG(a_pDte) (((a_pDte)->au64[2] >> 5) & 0x1) + +/** + * I/O Page Translation Entry. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u1Present : 1; /**< Bit 0 - PR: Present. */ + RT_GCC_EXTENSION uint64_t u4Ign0 : 4; /**< Bits 4:1 - Ignored. */ + RT_GCC_EXTENSION uint64_t u1Accessed : 1; /**< Bit 5 - A: Accessed. */ + RT_GCC_EXTENSION uint64_t u1Dirty : 1; /**< Bit 6 - D: Dirty. */ + RT_GCC_EXTENSION uint64_t u2Ign0 : 2; /**< Bits 8:7 - Ignored. */ + RT_GCC_EXTENSION uint64_t u3NextLevel : 3; /**< Bits 11:9 - Next Level: Next page translation level. */ + RT_GCC_EXTENSION uint64_t u40PageAddr : 40; /**< Bits 51:12 - Page address. */ + RT_GCC_EXTENSION uint64_t u7Rsvd0 : 7; /**< Bits 58:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u1UntranslatedAccess : 1; /**< Bit 59 - U: Untranslated Access Only. */ + RT_GCC_EXTENSION uint64_t u1ForceCoherent : 1; /**< Bit 60 - FC: Force Coherent. */ + RT_GCC_EXTENSION uint64_t u1IoRead : 1; /**< Bit 61 - IR: I/O Read permission. */ + RT_GCC_EXTENSION uint64_t u1IoWrite : 1; /**< Bit 62 - IW: I/O Wead permission. */ + RT_GCC_EXTENSION uint64_t u1Ign0 : 1; /**< Bit 63 - Ignored. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOPTE_T; +AssertCompileSize(IOPTE_T, 8); + +/** + * I/O Page Directory Entry. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u1Present : 1; /**< Bit 0 - PR: Present. */ + RT_GCC_EXTENSION uint64_t u4Ign0 : 4; /**< Bits 4:1 - Ignored. */ + RT_GCC_EXTENSION uint64_t u1Accessed : 1; /**< Bit 5 - A: Accessed. */ + RT_GCC_EXTENSION uint64_t u3Ign0 : 3; /**< Bits 8:6 - Ignored. */ + RT_GCC_EXTENSION uint64_t u3NextLevel : 3; /**< Bits 11:9 - Next Level: Next page translation level. */ + RT_GCC_EXTENSION uint64_t u40PageAddr : 40; /**< Bits 51:12 - Page address (Next Table Address). */ + RT_GCC_EXTENSION uint64_t u9Rsvd0 : 9; /**< Bits 60:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u1IoRead : 1; /**< Bit 61 - IR: I/O Read permission. */ + RT_GCC_EXTENSION uint64_t u1IoWrite : 1; /**< Bit 62 - IW: I/O Wead permission. */ + RT_GCC_EXTENSION uint64_t u1Ign0 : 1; /**< Bit 63 - Ignored. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOPDE_T; +AssertCompileSize(IOPDE_T, 8); + +/** + * I/O Page Table Entity. + * In accordance with the AMD spec. + * + * This a common subset of an DTE.au64[0], PTE and PDE. + * Named as an "entity" to avoid confusing it with PTE. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u1Present : 1; /**< Bit 0 - PR: Present. */ + RT_GCC_EXTENSION uint64_t u8Ign0 : 8; /**< Bits 8:1 - Ignored. */ + RT_GCC_EXTENSION uint64_t u3NextLevel : 3; /**< Bits 11:9 - Mode / Next Level: Next page translation level. */ + RT_GCC_EXTENSION uint64_t u40Addr : 40; /**< Bits 51:12 - Page address. */ + RT_GCC_EXTENSION uint64_t u9Ign0 : 9; /**< Bits 60:52 - Ignored. */ + RT_GCC_EXTENSION uint64_t u1IoRead : 1; /**< Bit 61 - IR: I/O Read permission. */ + RT_GCC_EXTENSION uint64_t u1IoWrite : 1; /**< Bit 62 - IW: I/O Wead permission. */ + RT_GCC_EXTENSION uint64_t u1Ign0 : 1; /**< Bit 63 - Ignored. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOPTENTITY_T; +AssertCompileSize(IOPTENTITY_T, 8); +AssertCompile(sizeof(IOPTENTITY_T) == sizeof(IOPTE_T)); +AssertCompile(sizeof(IOPTENTITY_T) == sizeof(IOPDE_T)); +/** Pointer to an IOPT_ENTITY_T struct. */ +typedef IOPTENTITY_T *PIOPTENTITY_T; +/** Pointer to a const IOPT_ENTITY_T struct. */ +typedef IOPTENTITY_T const *PCIOPTENTITY_T; +/** Mask of the address field. */ +#define IOMMU_PTENTITY_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** Reserved bits in the PDE (bits 60:52). */ +#define IOMMU_PDE_RSVD_MASK UINT64_C(0x1ff0000000000000) +/** Reserved bits in the PTE (bits 58:52 - U, FC bits not reserved). */ +#define IOMMU_PTE_RSVD_MASK UINT64_C(0x07f0000000000000) + +/** + * Interrupt Remapping Table Entry (IRTE) - Basic Format. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1RemapEnable : 1; /**< Bit 0 - RemapEn: Remap Enable. */ + uint32_t u1SuppressIoPf : 1; /**< Bit 1 - SupIOPF: Suppress I/O Page Fault. */ + uint32_t u3IntrType : 3; /**< Bits 4:2 - IntType: Interrupt Type. */ + uint32_t u1ReqEoi : 1; /**< Bit 5 - RqEoi: Request EOI. */ + uint32_t u1DestMode : 1; /**< Bit 6 - DM: Destination Mode. */ + uint32_t u1GuestMode : 1; /**< Bit 7 - GuestMode. */ + uint32_t u8Dest : 8; /**< Bits 15:8 - Destination. */ + uint32_t u8Vector : 8; /**< Bits 23:16 - Vector. */ + uint32_t u8Rsvd0 : 8; /**< Bits 31:24 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} IRTE_T; +AssertCompileSize(IRTE_T, 4); +/** Pointer to an IRTE_T struct. */ +typedef IRTE_T *PIRTE_T; +/** Pointer to a const IRTE_T struct. */ +typedef IRTE_T const *PCIRTE_T; + +/** The IRTE offset corresponds directly to bits 10:0 of the originating MSI + * interrupt message. See AMD IOMMU spec. 2.2.5 "Interrupt Remapping Tables". */ +#define IOMMU_MSI_DATA_IRTE_OFFSET_MASK UINT32_C(0x000007ff) +/** Gets the IRTE offset from the originating MSI interrupt message. */ +#define IOMMU_GET_IRTE_OFF(a_u32MsiData) (((a_u32MsiData) & IOMMU_MSI_DATA_IRTE_OFFSET_MASK) * sizeof(IRTE_T)) + +/** + * Interrupt Remapping Table Entry (IRTE) - Guest Virtual APIC Enabled. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1RemapEnable : 1; /**< Bit 0 - RemapEn: Remap Enable. */ + uint32_t u1SuppressIoPf : 1; /**< Bit 1 - SupIOPF: Suppress I/O Page Fault. */ + uint32_t u1GALogIntr : 1; /**< Bit 2 - GALogIntr: Guest APIC Log Interrupt. */ + uint32_t u3Rsvd : 3; /**< Bits 5:3 - Reserved. */ + uint32_t u1IsRunning : 1; /**< Bit 6 - IsRun: Hint whether the guest is running. */ + uint32_t u1GuestMode : 1; /**< Bit 7 - GuestMode. */ + uint32_t u8Dest : 8; /**< Bits 15:8 - Destination. */ + uint32_t u8Rsvd0 : 8; /**< Bits 31:16 - Reserved. */ + uint32_t u32GATag : 32; /**< Bits 63:31 - GATag: Tag used when writing to GA log. */ + uint32_t u8Vector : 8; /**< Bits 71:64 - Vector: Interrupt vector. */ + uint32_t u4Reserved : 4; /**< Bits 75:72 - Reserved or ignored depending on RemapEn. */ + uint32_t u20GATableRootPtrLo : 20; /**< Bits 95:76 - Bits [31:12] of Guest vAPIC Table Root Pointer. */ + uint32_t u20GATableRootPtrHi : 20; /**< Bits 115:76 - Bits [51:32] of Guest vAPIC Table Root Pointer. */ + uint32_t u12Rsvd : 12; /**< Bits 127:116 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64[2]; +} IRTE_GVA_T; +AssertCompileSize(IRTE_GVA_T, 16); +/** Pointer to an IRTE_GVA_T struct. */ +typedef IRTE_GVA_T *PIRTE_GVA_T; +/** Pointer to a const IRTE_GVA_T struct. */ +typedef IRTE_GVA_T const *PCIRTE_GVA_T; + +/** + * Command: Generic Command Buffer Entry. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u32Operand1Lo; /**< Bits 31:0 - Operand 1 (Lo). */ + uint32_t u28Operand1Hi : 28; /**< Bits 59:32 - Operand 1 (Hi). */ + uint32_t u4Opcode : 4; /**< Bits 63:60 - Op Code. */ + uint64_t u64Operand2; /**< Bits 127:64 - Operand 2. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_GENERIC_T; +AssertCompileSize(CMD_GENERIC_T, 16); +/** Pointer to a generic command buffer entry. */ +typedef CMD_GENERIC_T *PCMD_GENERIC_T; +/** Pointer to a const generic command buffer entry. */ +typedef CMD_GENERIC_T const *PCCMD_GENERIC_T; + +/** Number of bits to shift the byte offset of a command in the command buffer to + * get its index. */ +#define IOMMU_CMD_GENERIC_SHIFT 4 + +/** + * Command: COMPLETION_WAIT. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1Store : 1; /**< Bit 0 - S: Completion Store. */ + uint32_t u1Interrupt : 1; /**< Bit 1 - I: Completion Interrupt. */ + uint32_t u1Flush : 1; /**< Bit 2 - F: Flush Queue. */ + uint32_t u29StoreAddrLo : 29; /**< Bits 31:3 - Store Address (Lo). */ + uint32_t u20StoreAddrHi : 20; /**< Bits 51:32 - Store Address (Hi). */ + uint32_t u8Rsvd0 : 8; /**< Bits 59:52 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - OpCode (Command). */ + uint64_t u64StoreData; /**< Bits 127:64 - Store Data. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_COMWAIT_T; +AssertCompileSize(CMD_COMWAIT_T, 16); +/** Pointer to a completion wait command. */ +typedef CMD_COMWAIT_T *PCMD_COMWAIT_T; +/** Pointer to a const completion wait command. */ +typedef CMD_COMWAIT_T const *PCCMD_COMWAIT_T; +#define IOMMU_CMD_COM_WAIT_QWORD_0_VALID_MASK UINT64_C(0xf00fffffffffffff) + +/** + * Command: INVALIDATE_DEVTAB_ENTRY. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint16_t u16Rsvd0; /**< Bits 31:16 - Reserved. */ + uint32_t u28Rsvd0 : 28; /**< Bits 59:32 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint64_t u64Rsvd0; /**< Bits 127:64 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_INV_DTE_T; +AssertCompileSize(CMD_INV_DTE_T, 16); +/** Pointer to a invalidate DTE command. */ +typedef CMD_INV_DTE_T *PCMD_INV_DTE_T; +/** Pointer to a const invalidate DTE command. */ +typedef CMD_INV_DTE_T const *PCCMD_INV_DTE_T; +#define IOMMU_CMD_INV_DTE_QWORD_0_VALID_MASK UINT64_C(0xf00000000000ffff) +#define IOMMU_CMD_INV_DTE_QWORD_1_VALID_MASK UINT64_C(0x0000000000000000) + +/** + * Command: INVALIDATE_IOMMU_PAGES. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u20Pasid : 20; /**< Bits 19:0 - PASID: Process Address-Space ID. */ + uint32_t u12Rsvd0 : 12; /**< Bits 31:20 - Reserved. */ + uint32_t u16DomainId : 16; /**< Bits 47:32 - Domain ID. */ + uint32_t u12Rsvd1 : 12; /**< Bits 59:48 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint32_t u1Size : 1; /**< Bit 64 - S: Size. */ + uint32_t u1PageDirEntries : 1; /**< Bit 65 - PDE: Page Directory Entries. */ + uint32_t u1GuestOrNested : 1; /**< Bit 66 - GN: Guest (GPA) or Nested (GVA). */ + uint32_t u9Rsvd0 : 9; /**< Bits 75:67 - Reserved. */ + uint32_t u20AddrLo : 20; /**< Bits 95:76 - Address (Lo). */ + uint32_t u32AddrHi; /**< Bits 127:96 - Address (Hi). */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_INV_IOMMU_PAGES_T; +AssertCompileSize(CMD_INV_IOMMU_PAGES_T, 16); +/** Pointer to a invalidate iommu pages command. */ +typedef CMD_INV_IOMMU_PAGES_T *PCMD_INV_IOMMU_PAGES_T; +/** Pointer to a const invalidate iommu pages command. */ +typedef CMD_INV_IOMMU_PAGES_T const *PCCMD_INV_IOMMU_PAGES_T; +#define IOMMU_CMD_INV_IOMMU_PAGES_QWORD_0_VALID_MASK UINT64_C(0xf000ffff000fffff) +#define IOMMU_CMD_INV_IOMMU_PAGES_QWORD_1_VALID_MASK UINT64_C(0xfffffffffffff007) + +/** + * Command: INVALIDATE_IOTLB_PAGES. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint8_t u8PasidLo; /**< Bits 23:16 - PASID: Process Address-Space ID (Lo). */ + uint8_t u8MaxPend; /**< Bits 31:24 - Maxpend: Maximum simultaneous in-flight transactions. */ + uint32_t u16QueueId : 16; /**< Bits 47:32 - Queue ID. */ + uint32_t u12PasidHi : 12; /**< Bits 59:48 - PASID: Process Address-Space ID (Hi). */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint32_t u1Size : 1; /**< Bit 64 - S: Size. */ + uint32_t u1Rsvd0: 1; /**< Bit 65 - Reserved. */ + uint32_t u1GuestOrNested : 1; /**< Bit 66 - GN: Guest (GPA) or Nested (GVA). */ + uint32_t u1Rsvd1 : 1; /**< Bit 67 - Reserved. */ + uint32_t u2Type : 2; /**< Bit 69:68 - Type. */ + uint32_t u6Rsvd0 : 6; /**< Bits 75:70 - Reserved. */ + uint32_t u20AddrLo : 20; /**< Bits 95:76 - Address (Lo). */ + uint32_t u32AddrHi; /**< Bits 127:96 - Address (Hi). */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_INV_IOTLB_PAGES_T; +AssertCompileSize(CMD_INV_IOTLB_PAGES_T, 16); + +/** + * Command: INVALIDATE_INTR_TABLE. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint16_t u16Rsvd0; /**< Bits 31:16 - Reserved. */ + uint32_t u32Rsvd0 : 28; /**< Bits 59:32 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint64_t u64Rsvd0; /**< Bits 127:64 - Reserved. */ + } u; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_INV_INTR_TABLE_T; +AssertCompileSize(CMD_INV_INTR_TABLE_T, 16); +/** Pointer to a invalidate interrupt table command. */ +typedef CMD_INV_INTR_TABLE_T *PCMD_INV_INTR_TABLE_T; +/** Pointer to a const invalidate interrupt table command. */ +typedef CMD_INV_INTR_TABLE_T const *PCCMD_INV_INTR_TABLE_T; +#define IOMMU_CMD_INV_INTR_TABLE_QWORD_0_VALID_MASK UINT64_C(0xf00000000000ffff) +#define IOMMU_CMD_INV_INTR_TABLE_QWORD_1_VALID_MASK UINT64_C(0x0000000000000000) + +/** + * Command: PREFETCH_IOMMU_PAGES. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint8_t u8Rsvd0; /**< Bits 23:16 - Reserved. */ + uint8_t u8PrefCount; /**< Bits 31:24 - PFCount: Number of translations to prefetch. */ + uint32_t u20Pasid : 20; /**< Bits 51:32 - PASID: Process Address-Space ID. */ + uint32_t u8Rsvd1 : 8; /**< Bits 59:52 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint32_t u1Size : 1; /**< Bit 64 - S: Size of the prefetched pages. */ + uint32_t u1Rsvd0 : 1; /**< Bit 65 - Reserved. */ + uint32_t u1GuestOrNested : 1; /**< Bit 66 - GN: Guest (GPA) or Nested (GVA). */ + uint32_t u1Rsvd1 : 1; /**< Bit 67 - Reserved. */ + uint32_t u1Invalidate : 1; /**< Bit 68 - Inval: Invalidate prior to prefetch. */ + uint32_t u7Rsvd0 : 7; /**< Bits 75:69 - Reserved */ + uint32_t u20AddrLo : 7; /**< Bits 95:76 - Address (Lo). */ + uint32_t u32AddrHi; /**< Bits 127:96 - Address (Hi). */ + } u; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_PREF_IOMMU_PAGES_T; +AssertCompileSize(CMD_PREF_IOMMU_PAGES_T, 16); +/** Pointer to a invalidate iommu pages command. */ +typedef CMD_PREF_IOMMU_PAGES_T *PCMD_PREF_IOMMU_PAGES_T; +/** Pointer to a const invalidate iommu pages command. */ +typedef CMD_PREF_IOMMU_PAGES_T const *PCCMD_PREF_IOMMU_PAGES_T; +#define IOMMU_CMD_PREF_IOMMU_PAGES_QWORD_0_VALID_MASK UINT64_C(0x780fffffff00ffff) +#define IOMMU_CMD_PREF_IOMMU_PAGES_QWORD_1_VALID_MASK UINT64_C(0xfffffffffffff015) + + +/** + * Command: COMPLETE_PPR_REQ. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint16_t u16Rsvd0; /**< Bits 31:16 - Reserved. */ + uint32_t u20Pasid : 20; /**< Bits 51:32 - PASID: Process Address-Space ID. */ + uint32_t u8Rsvd0 : 8; /**< Bits 59:52 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint32_t u2Rsvd0 : 2; /**< Bits 65:64 - Reserved. */ + uint32_t u1GuestOrNested : 1; /**< Bit 66 - GN: Guest (GPA) or Nested (GVA). */ + uint32_t u29Rsvd0 : 29; /**< Bits 95:67 - Reserved. */ + uint32_t u16CompletionTag : 16; /**< Bits 111:96 - Completion Tag. */ + uint32_t u16Rsvd1 : 16; /**< Bits 127:112 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_COMPLETE_PPR_REQ_T; +AssertCompileSize(CMD_COMPLETE_PPR_REQ_T, 16); + +/** + * Command: INV_IOMMU_ALL. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u32Rsvd0; /**< Bits 31:0 - Reserved. */ + uint32_t u28Rsvd0 : 28; /**< Bits 59:32 - Reserved. */ + uint32_t u4OpCode : 4; /**< Bits 63:60 - Op Code (Command). */ + uint64_t u64Rsvd0; /**< Bits 127:64 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} CMD_INV_IOMMU_ALL_T; +AssertCompileSize(CMD_INV_IOMMU_ALL_T, 16); +/** Pointer to a invalidate IOMMU all command. */ +typedef CMD_INV_IOMMU_ALL_T *PCMD_INV_IOMMU_ALL_T; +/** Pointer to a const invalidate IOMMU all command. */ +typedef CMD_INV_IOMMU_ALL_T const *PCCMD_INV_IOMMU_ALL_T; +#define IOMMU_CMD_INV_IOMMU_ALL_QWORD_0_VALID_MASK UINT64_C(0xf000000000000000) +#define IOMMU_CMD_INV_IOMMU_ALL_QWORD_1_VALID_MASK UINT64_C(0x0000000000000000) + +/** + * Event Log Entry: Generic. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u32Operand1Lo; /**< Bits 31:0 - Operand 1 (Lo). */ + uint32_t u28Operand1Hi : 28; /**< Bits 59:32 - Operand 1 (Hi). */ + uint32_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint32_t u32Operand2Lo; /**< Bits 95:64 - Operand 2 (Lo). */ + uint32_t u32Operand2Hi; /**< Bits 127:96 - Operand 2 (Hi). */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; +} EVT_GENERIC_T; +AssertCompileSize(EVT_GENERIC_T, 16); +/** Number of bits to shift the byte offset of an event entry in the event log + * buffer to get its index. */ +#define IOMMU_EVT_GENERIC_SHIFT 4 +/** Pointer to a generic event log entry. */ +typedef EVT_GENERIC_T *PEVT_GENERIC_T; +/** Pointer to a const generic event log entry. */ +typedef const EVT_GENERIC_T *PCEVT_GENERIC_T; + +/** + * Hardware event types. + * In accordance with the AMD spec. + */ +typedef enum HWEVTTYPE +{ + HWEVTTYPE_RSVD = 0, + HWEVTTYPE_MASTER_ABORT, + HWEVTTYPE_TARGET_ABORT, + HWEVTTYPE_DATA_ERROR +} HWEVTTYPE; +AssertCompileSize(HWEVTTYPE, 4); + +/** + * Event Log Entry: ILLEGAL_DEV_TABLE_ENTRY. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + RT_GCC_EXTENSION uint16_t u4PasidHi : 4; /**< Bits 19:16 - PASID: Process Address-Space ID (Hi). */ + RT_GCC_EXTENSION uint16_t u12Rsvd0 : 12; /**< Bits 31:20 - Reserved. */ + uint16_t u16PasidLo; /**< Bits 47:32 - PASID: Process Address-Space ID (Lo). */ + RT_GCC_EXTENSION uint16_t u1GuestOrNested : 1; /**< Bit 48 - GN: Guest (GPA) or Nested (GVA). */ + RT_GCC_EXTENSION uint16_t u2Rsvd0 : 2; /**< Bits 50:49 - Reserved. */ + RT_GCC_EXTENSION uint16_t u1Interrupt : 1; /**< Bit 51 - I: Interrupt. */ + RT_GCC_EXTENSION uint16_t u1Rsvd0 : 1; /**< Bit 52 - Reserved. */ + RT_GCC_EXTENSION uint16_t u1ReadWrite : 1; /**< Bit 53 - RW: Read/Write. */ + RT_GCC_EXTENSION uint16_t u1Rsvd1 : 1; /**< Bit 54 - Reserved. */ + RT_GCC_EXTENSION uint16_t u1RsvdNotZero : 1; /**< Bit 55 - RZ: Reserved bit not Zero (0=invalid level encoding). */ + RT_GCC_EXTENSION uint16_t u1Translation : 1; /**< Bit 56 - TN: Translation. */ + RT_GCC_EXTENSION uint16_t u3Rsvd0 : 3; /**< Bits 59:57 - Reserved. */ + RT_GCC_EXTENSION uint16_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint64_t u64Addr; /**< Bits 127:64 - Address: I/O Virtual Address (IOVA). */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} EVT_ILLEGAL_DTE_T; +AssertCompileSize(EVT_ILLEGAL_DTE_T, 16); +/** Pointer to an illegal device table entry event. */ +typedef EVT_ILLEGAL_DTE_T *PEVT_ILLEGAL_DTE_T; +/** Pointer to a const illegal device table entry event. */ +typedef EVT_ILLEGAL_DTE_T const *PCEVT_ILLEGAL_DTE_T; + +/** + * Event Log Entry: IO_PAGE_FAULT_EVENT. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + RT_GCC_EXTENSION uint16_t u4PasidHi : 4; /**< Bits 19:16 - PASID: Process Address-Space ID (Hi). */ + RT_GCC_EXTENSION uint16_t u16DomainOrPasidLo; /**< Bits 47:32 - D/P: Domain ID or Process Address-Space ID (Lo). */ + RT_GCC_EXTENSION uint16_t u1GuestOrNested : 1; /**< Bit 48 - GN: Guest (GPA) or Nested (GVA). */ + RT_GCC_EXTENSION uint16_t u1NoExecute : 1; /**< Bit 49 - NX: No Execute. */ + RT_GCC_EXTENSION uint16_t u1User : 1; /**< Bit 50 - US: User/Supervisor. */ + RT_GCC_EXTENSION uint16_t u1Interrupt : 1; /**< Bit 51 - I: Interrupt. */ + RT_GCC_EXTENSION uint16_t u1Present : 1; /**< Bit 52 - PR: Present. */ + RT_GCC_EXTENSION uint16_t u1ReadWrite : 1; /**< Bit 53 - RW: Read/Write. */ + RT_GCC_EXTENSION uint16_t u1PermDenied : 1; /**< Bit 54 - PE: Permission Indicator. */ + RT_GCC_EXTENSION uint16_t u1RsvdNotZero : 1; /**< Bit 55 - RZ: Reserved bit not Zero (0=invalid level encoding). */ + RT_GCC_EXTENSION uint16_t u1Translation : 1; /**< Bit 56 - TN: Translation. */ + RT_GCC_EXTENSION uint16_t u3Rsvd0 : 3; /**< Bit 59:57 - Reserved. */ + RT_GCC_EXTENSION uint16_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint64_t u64Addr; /**< Bits 127:64 - Address: I/O Virtual Address (IOVA). */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} EVT_IO_PAGE_FAULT_T; +AssertCompileSize(EVT_IO_PAGE_FAULT_T, 16); +/** Pointer to an I/O page fault event. */ +typedef EVT_IO_PAGE_FAULT_T *PEVT_IO_PAGE_FAULT_T; +/** Pointer to a const I/O page fault event. */ +typedef EVT_IO_PAGE_FAULT_T const *PCEVT_IO_PAGE_FAULT_T; + + +/** + * Event Log Entry: DEV_TAB_HARDWARE_ERROR. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint16_t u16Rsvd0; /**< Bits 31:16 - Reserved. */ + uint32_t u19Rsvd0 : 19; /**< Bits 50:32 - Reserved. */ + uint32_t u1Intr : 1; /**< Bit 51 - I: Interrupt (1=interrupt request, 0=memory request). */ + uint32_t u1Rsvd0 : 1; /**< Bit 52 - Reserved. */ + uint32_t u1ReadWrite : 1; /**< Bit 53 - RW: Read/Write transaction (only meaninful when I=0 and TR=0). */ + uint32_t u2Rsvd0 : 2; /**< Bits 55:54 - Reserved. */ + uint32_t u1Translation : 1; /**< Bit 56 - TR: Translation (1=translation, 0=transaction). */ + uint32_t u2Type : 2; /**< Bits 58:57 - Type: The type of hardware error. */ + uint32_t u1Rsvd1 : 1; /**< Bit 59 - Reserved. */ + uint32_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint64_t u64Addr; /**< Bits 127:64 - Address. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} EVT_DEV_TAB_HW_ERROR_T; +AssertCompileSize(EVT_DEV_TAB_HW_ERROR_T, 16); +/** Pointer to a device table hardware error event. */ +typedef EVT_DEV_TAB_HW_ERROR_T *PEVT_DEV_TAB_HW_ERROR_T; +/** Pointer to a const device table hardware error event. */ +typedef EVT_DEV_TAB_HW_ERROR_T const *PCEVT_DEV_TAB_HW_ERROR_T; + +/** + * Event Log Entry: EVT_PAGE_TAB_HARDWARE_ERROR. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint16_t u16Rsvd0; /**< Bits 31:16 - Reserved. */ + uint32_t u16DomainOrPasidLo : 16; /**< Bits 47:32 - D/P: Domain ID or Process Address-Space ID (Lo). */ + uint32_t u1GuestOrNested : 1; /**< Bit 48 - GN: Guest (GPA) or Nested (GVA). */ + uint32_t u2Rsvd0 : 2; /**< Bits 50:49 - Reserved. */ + uint32_t u1Interrupt : 1; /**< Bit 51 - I: Interrupt. */ + uint32_t u1Rsvd0 : 1; /**< Bit 52 - Reserved. */ + uint32_t u1ReadWrite : 1; /**< Bit 53 - RW: Read/Write. */ + uint32_t u2Rsvd1 : 2; /**< Bit 55:54 - Reserved. */ + uint32_t u1Translation : 1; /**< Bit 56 - TR: Translation. */ + uint32_t u2Type : 2; /**< Bits 58:57 - Type: The type of hardware error. */ + uint32_t u1Rsvd1 : 1; /**< Bit 59 - Reserved. */ + uint32_t u4EvtCode : 4; /**< Bit 63:60 - Event code. */ + /** @todo r=ramshankar: Figure 55: PAGE_TAB_HARDWARE_ERROR says Addr[31:3] but + * table 58 mentions Addr[31:4], we just use the full 64-bits. Looks like a + * typo in the figure.See AMD AMD IOMMU spec (3.05-PUB, Jan 2020). */ + uint64_t u64Addr; /** Bits 127:64 - Address: SPA of the page table entry. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} EVT_PAGE_TAB_HW_ERR_T; +AssertCompileSize(EVT_PAGE_TAB_HW_ERR_T, 16); +/** Pointer to a page table hardware error event. */ +typedef EVT_PAGE_TAB_HW_ERR_T *PEVT_PAGE_TAB_HW_ERR_T; +/** Pointer to a const page table hardware error event. */ +typedef EVT_PAGE_TAB_HW_ERR_T const *PCEVT_PAGE_TAB_HW_ERR_T; + +/** + * Event Log Entry: ILLEGAL_COMMAND_ERROR. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u32Rsvd0; /**< Bits 31:0 - Reserved. */ + uint32_t u28Rsvd0 : 28; /**< Bits 47:32 - Reserved. */ + uint32_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint64_t u64Addr; /**< Bits 127:64 - Address: SPA of the invalid command. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} EVT_ILLEGAL_CMD_ERR_T; +AssertCompileSize(EVT_ILLEGAL_CMD_ERR_T, 16); +/** Pointer to an illegal command error event. */ +typedef EVT_ILLEGAL_CMD_ERR_T *PEVT_ILLEGAL_CMD_ERR_T; +/** Pointer to a const illegal command error event. */ +typedef EVT_ILLEGAL_CMD_ERR_T const *PCEVT_ILLEGAL_CMD_ERR_T; + +/** + * Event Log Entry: COMMAND_HARDWARE_ERROR. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u32Rsvd0; /**< Bits 31:0 - Reserved. */ + uint32_t u25Rsvd1 : 25; /**< Bits 56:32 - Reserved. */ + uint32_t u2Type : 2; /**< Bits 58:57 - Type: The type of hardware error. */ + uint32_t u1Rsvd1 : 1; /**< Bit 59 - Reserved. */ + uint32_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint64_t u64Addr; /**< Bits 128:64 - Address: SPA of the attempted access. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; + /** The 64-bit unsigned integer view. */ + uint64_t au64[2]; +} EVT_CMD_HW_ERR_T; +AssertCompileSize(EVT_CMD_HW_ERR_T, 16); +/** Pointer to a command hardware error event. */ +typedef EVT_CMD_HW_ERR_T *PEVT_CMD_HW_ERR_T; +/** Pointer to a const command hardware error event. */ +typedef EVT_CMD_HW_ERR_T const *PCEVT_CMD_HW_ERR_T; + +/** + * Event Log Entry: IOTLB_INV_TIMEOUT. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint16_t u16DevId; /**< Bits 15:0 - Device ID. */ + uint16_t u16Rsvd0; /**< Bits 31:16 - Reserved.*/ + uint32_t u28Rsvd0 : 28; /**< Bits 59:32 - Reserved. */ + uint32_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint32_t u4Rsvd0 : 4; /**< Bits 67:64 - Reserved. */ + uint32_t u28AddrLo : 28; /**< Bits 95:68 - Address: SPA of the invalidation command that timedout (Lo). */ + uint32_t u32AddrHi; /**< Bits 127:96 - Address: SPA of the invalidation command that timedout (Hi). */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; +} EVT_IOTLB_INV_TIMEOUT_T; +AssertCompileSize(EVT_IOTLB_INV_TIMEOUT_T, 16); + +/** + * Event Log Entry: INVALID_DEVICE_REQUEST. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u16DevId : 16; /***< Bits 15:0 - Device ID. */ + uint32_t u4PasidHi : 4; /***< Bits 19:16 - PASID: Process Address-Space ID (Hi). */ + uint32_t u12Rsvd0 : 12; /***< Bits 31:20 - Reserved. */ + uint32_t u16PasidLo : 16; /***< Bits 47:32 - PASID: Process Address-Space ID (Lo). */ + uint32_t u1GuestOrNested : 1; /***< Bit 48 - GN: Guest (GPA) or Nested (GVA). */ + uint32_t u1User : 1; /***< Bit 49 - US: User/Supervisor. */ + uint32_t u6Rsvd0 : 6; /***< Bits 55:50 - Reserved. */ + uint32_t u1Translation: 1; /***< Bit 56 - TR: Translation. */ + uint32_t u3Type: 3; /***< Bits 59:57 - Type: The type of hardware error. */ + uint32_t u4EvtCode : 4; /***< Bits 63:60 - Event code. */ + uint64_t u64Addr; /***< Bits 127:64 - Address: Translation or access address. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; +} EVT_INVALID_DEV_REQ_T; +AssertCompileSize(EVT_INVALID_DEV_REQ_T, 16); + +/** + * Event Log Entry: EVENT_COUNTER_ZERO. + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u32Rsvd0; /**< Bits 31:0 - Reserved. */ + uint32_t u28Rsvd0 : 28; /**< Bits 59:32 - Reserved. */ + uint32_t u4EvtCode : 4; /**< Bits 63:60 - Event code. */ + uint32_t u20CounterNoteHi : 20; /**< Bits 83:64 - CounterNote: Counter value for the event counter register (Hi). */ + uint32_t u12Rsvd0 : 12; /**< Bits 95:84 - Reserved. */ + uint32_t u32CounterNoteLo; /**< Bits 127:96 - CounterNote: Counter value for the event cuonter register (Lo). */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[4]; +} EVT_EVENT_COUNTER_ZERO_T; +AssertCompileSize(EVT_EVENT_COUNTER_ZERO_T, 16); + +/** + * IOMMU Capability Header (PCI). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u8CapId : 8; /**< Bits 7:0 - CapId: Capability ID. */ + uint32_t u8CapPtr : 8; /**< Bits 15:8 - CapPtr: Pointer (PCI config offset) to the next capability. */ + uint32_t u3CapType : 3; /**< Bits 18:16 - CapType: Capability Type. */ + uint32_t u5CapRev : 5; /**< Bits 23:19 - CapRev: Capability revision. */ + uint32_t u1IoTlbSup : 1; /**< Bit 24 - IotlbSup: IOTLB Support. */ + uint32_t u1HtTunnel : 1; /**< Bit 25 - HtTunnel: HyperTransport Tunnel translation support. */ + uint32_t u1NpCache : 1; /**< Bit 26 - NpCache: Not Present table entries are cached. */ + uint32_t u1EfrSup : 1; /**< Bit 27 - EFRSup: Extended Feature Register Support. */ + uint32_t u1CapExt : 1; /**< Bit 28 - CapExt: Misc. Information Register 1 Support. */ + uint32_t u3Rsvd0 : 3; /**< Bits 31:29 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} IOMMU_CAP_HDR_T; +AssertCompileSize(IOMMU_CAP_HDR_T, 4); + +/** + * IOMMU Base Address (Lo and Hi) Register (PCI). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1Enable : 1; /**< Bit 1 - Enable: RW1S - Enable IOMMU MMIO region. */ + uint32_t u12Rsvd0 : 12; /**< Bits 13:1 - Reserved. */ + uint32_t u18BaseAddrLo : 18; /**< Bits 31:14 - Base address (Lo) of the MMIO region. */ + uint32_t u32BaseAddrHi; /**< Bits 63:32 - Base address (Hi) of the MMIO region. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_BAR_T; +AssertCompileSize(IOMMU_BAR_T, 8); +#define IOMMU_BAR_VALID_MASK UINT64_C(0xffffffffffffc001) + +/** + * IOMMU Range Register (PCI). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u5HtUnitId : 5; /**< Bits 4:0 - UnitID: IOMMU HyperTransport Unit ID (not used). */ + uint32_t u2Rsvd0 : 2; /**< Bits 6:5 - Reserved. */ + uint32_t u1RangeValid : 1; /**< Bit 7 - RngValid: Range Valid. */ + uint32_t u8Bus : 8; /**< Bits 15:8 - BusNumber: Bus number of the first and last device. */ + uint32_t u8FirstDevice : 8; /**< Bits 23:16 - FirstDevice: Device and function number of the first device. */ + uint32_t u8LastDevice: 8; /**< Bits 31:24 - LastDevice: Device and function number of the last device. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} IOMMU_RANGE_T; +AssertCompileSize(IOMMU_RANGE_T, 4); + +/** + * Device Table Base Address Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u9Size : 9; /**< Bits 8:0 - Size: Size of the device table. */ + RT_GCC_EXTENSION uint64_t u3Rsvd0 : 3; /**< Bits 11:9 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40Base : 40; /**< Bits 51:12 - DevTabBase: Device table base address. */ + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 63:52 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} DEV_TAB_BAR_T; +AssertCompileSize(DEV_TAB_BAR_T, 8); +#define IOMMU_DEV_TAB_BAR_VALID_MASK UINT64_C(0x000ffffffffff1ff) +#define IOMMU_DEV_TAB_SEG_BAR_VALID_MASK UINT64_C(0x000ffffffffff0ff) + +/** + * Command Buffer Base Address Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 11:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40Base : 40; /**< Bits 51:12 - ComBase: Command buffer base address. */ + RT_GCC_EXTENSION uint64_t u4Rsvd0 : 4; /**< Bits 55:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u4Len : 4; /**< Bits 59:56 - ComLen: Command buffer length. */ + RT_GCC_EXTENSION uint64_t u4Rsvd1 : 4; /**< Bits 63:60 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} CMD_BUF_BAR_T; +AssertCompileSize(CMD_BUF_BAR_T, 8); +#define IOMMU_CMD_BUF_BAR_VALID_MASK UINT64_C(0x0f0ffffffffff000) + +/** + * Event Log Base Address Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 11:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40Base : 40; /**< Bits 51:12 - EventBase: Event log base address. */ + RT_GCC_EXTENSION uint64_t u4Rsvd0 : 4; /**< Bits 55:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u4Len : 4; /**< Bits 59:56 - EventLen: Event log length. */ + RT_GCC_EXTENSION uint64_t u4Rsvd1 : 4; /**< Bits 63:60 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} EVT_LOG_BAR_T; +AssertCompileSize(EVT_LOG_BAR_T, 8); +#define IOMMU_EVT_LOG_BAR_VALID_MASK UINT64_C(0x0f0ffffffffff000) + +/** + * IOMMU Control Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1IommuEn : 1; /**< Bit 0 - IommuEn: IOMMU Enable. */ + uint32_t u1HtTunEn : 1; /**< Bit 1 - HtTunEn: HyperTransport Tunnel Enable. */ + uint32_t u1EvtLogEn : 1; /**< Bit 2 - EventLogEn: Event Log Enable. */ + uint32_t u1EvtIntrEn : 1; /**< Bit 3 - EventIntEn: Event Log Interrupt Enable. */ + uint32_t u1CompWaitIntrEn : 1; /**< Bit 4 - ComWaitIntEn: Completion Wait Interrupt Enable. */ + uint32_t u3InvTimeOut : 3; /**< Bits 7:5 - InvTimeOut: Invalidation Timeout. */ + uint32_t u1PassPW : 1; /**< Bit 8 - PassPW: Pass Posted Write. */ + uint32_t u1ResPassPW : 1; /**< Bit 9 - ResPassPW: Response Pass Posted Write. */ + uint32_t u1Coherent : 1; /**< Bit 10 - Coherent: HT read request packet Coherent bit. */ + uint32_t u1Isoc : 1; /**< Bit 11 - Isoc: HT read request packet Isochronous bit. */ + uint32_t u1CmdBufEn : 1; /**< Bit 12 - CmdBufEn: Command Buffer Enable. */ + uint32_t u1PprLogEn : 1; /**< Bit 13 - PprLogEn: Peripheral Page Request (PPR) Log Enable. */ + uint32_t u1PprIntrEn : 1; /**< Bit 14 - PprIntrEn: Peripheral Page Request Interrupt Enable. */ + uint32_t u1PprEn : 1; /**< Bit 15 - PprEn: Peripheral Page Request processing Enable. */ + uint32_t u1GstTranslateEn : 1; /**< Bit 16 - GTEn: Guest Translate Enable. */ + uint32_t u1GstVirtApicEn : 1; /**< Bit 17 - GAEn: Guest Virtual-APIC Enable. */ + uint32_t u4Crw : 1; /**< Bits 21:18 - CRW: Intended for future use (not documented). */ + uint32_t u1SmiFilterEn : 1; /**< Bit 22 - SmiFEn: SMI Filter Enable. */ + uint32_t u1SelfWriteBackDis : 1; /**< Bit 23 - SlfWBDis: Self Write-Back Disable. */ + uint32_t u1SmiFilterLogEn : 1; /**< Bit 24 - SmiFLogEn: SMI Filter Log Enable. */ + uint32_t u3GstVirtApicModeEn : 3; /**< Bits 27:25 - GAMEn: Guest Virtual-APIC Mode Enable. */ + uint32_t u1GstLogEn : 1; /**< Bit 28 - GALogEn: Guest Virtual-APIC GA Log Enable. */ + uint32_t u1GstIntrEn : 1; /**< Bit 29 - GAIntEn: Guest Virtual-APIC Interrupt Enable. */ + uint32_t u2DualPprLogEn : 2; /**< Bits 31:30 - DualPprLogEn: Dual Peripheral Page Request Log Enable. */ + uint32_t u2DualEvtLogEn : 2; /**< Bits 33:32 - DualEventLogEn: Dual Event Log Enable. */ + uint32_t u3DevTabSegEn : 3; /**< Bits 36:34 - DevTblSegEn: Device Table Segment Enable. */ + uint32_t u2PrivAbortEn : 2; /**< Bits 38:37 - PrivAbrtEn: Privilege Abort Enable. */ + uint32_t u1PprAutoRespEn : 1; /**< Bit 39 - PprAutoRspEn: Peripheral Page Request Auto Response Enable. */ + uint32_t u1MarcEn : 1; /**< Bit 40 - MarcEn: Memory Address Routing and Control Enable. */ + uint32_t u1BlockStopMarkEn : 1; /**< Bit 41 - BlkStopMarkEn: Block StopMark messages Enable. */ + uint32_t u1PprAutoRespAlwaysOnEn : 1; /**< Bit 42 - PprAutoRspAon:: PPR Auto Response - Always On Enable. */ + uint32_t u1DomainIDPNE : 1; /**< Bit 43 - DomainIDPE: Reserved (not documented). */ + uint32_t u1Rsvd0 : 1; /**< Bit 44 - Reserved. */ + uint32_t u1EnhancedPpr : 1; /**< Bit 45 - EPHEn: Enhanced Peripheral Page Request Handling Enable. */ + uint32_t u2HstAccDirtyBitUpdate : 2; /**< Bits 47:46 - HADUpdate: Access and Dirty Bit updated in host page table. */ + uint32_t u1GstDirtyUpdateDis : 1; /**< Bit 48 - GDUpdateDis: Disable hardare update of Dirty bit in GPT. */ + uint32_t u1Rsvd1 : 1; /**< Bit 49 - Reserved. */ + uint32_t u1X2ApicEn : 1; /**< Bit 50 - XTEn: Enable X2APIC. */ + uint32_t u1X2ApicIntrGenEn : 1; /**< Bit 51 - IntCapXTEn: Enable IOMMU X2APIC Interrupt generation. */ + uint32_t u2Rsvd0 : 2; /**< Bits 53:52 - Reserved. */ + uint32_t u1GstAccessUpdateDis : 1; /**< Bit 54 - GAUpdateDis: Disable hardare update of Access bit in GPT. */ + uint32_t u8Rsvd0 : 8; /**< Bits 63:55 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_CTRL_T; +AssertCompileSize(IOMMU_CTRL_T, 8); +#define IOMMU_CTRL_VALID_MASK UINT64_C(0x004defffffffffff) +#define IOMMU_CTRL_CMD_BUF_EN_MASK UINT64_C(0x0000000000001001) + +/** + * IOMMU Exclusion Base Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u1ExclEnable : 1; /**< Bit 0 - ExEn: Exclusion Range Enable. */ + RT_GCC_EXTENSION uint64_t u1AllowAll : 1; /**< Bit 1 - Allow: Allow All Devices. */ + RT_GCC_EXTENSION uint64_t u10Rsvd0 : 10; /**< Bits 11:2 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40ExclRangeBase : 40; /**< Bits 51:12 - Exclusion Range Base Address. */ + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 63:52 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_EXCL_RANGE_BAR_T; +AssertCompileSize(IOMMU_EXCL_RANGE_BAR_T, 8); +#define IOMMU_EXCL_RANGE_BAR_VALID_MASK UINT64_C(0x000ffffffffff003) + +/** + * IOMMU Exclusion Range Limit Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 63:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40ExclRangeLimit : 40; /**< Bits 51:12 - Exclusion Range Limit Address. */ + RT_GCC_EXTENSION uint64_t u12Rsvd1 : 12; /**< Bits 63:52 - Reserved (treated as 1s). */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_EXCL_RANGE_LIMIT_T; +AssertCompileSize(IOMMU_EXCL_RANGE_LIMIT_T, 8); +#define IOMMU_EXCL_RANGE_LIMIT_VALID_MASK UINT64_C(0x000fffffffffffff) + +/** + * IOMMU Extended Feature Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1PrefetchSup : 1; /**< Bit 0 - PreFSup: Prefetch Support. */ + uint32_t u1PprSup : 1; /**< Bit 1 - PPRSup: Peripheral Page Request Support. */ + uint32_t u1X2ApicSup : 1; /**< Bit 2 - XTSup: x2Apic Support. */ + uint32_t u1NoExecuteSup : 1; /**< Bit 3 - NXSup: No-Execute and Privilege Level Support. */ + uint32_t u1GstTranslateSup : 1; /**< Bit 4 - GTSup: Guest Translations (for GVAs) Support. */ + uint32_t u1Rsvd0 : 1; /**< Bit 5 - Reserved. */ + uint32_t u1InvAllSup : 1; /**< Bit 6 - IASup: Invalidate-All Support. */ + uint32_t u1GstVirtApicSup : 1; /**< Bit 7 - GASup: Guest Virtual-APIC Support. */ + uint32_t u1HwErrorSup : 1; /**< Bit 8 - HESup: Hardware Error registers Support. */ + uint32_t u1PerfCounterSup : 1; /**< Bit 9 - PCSup: Performance Counter Support. */ + uint32_t u2HostAddrTranslateSize : 2; /**< Bits 11:10 - HATS: Host Address Translation Size. */ + uint32_t u2GstAddrTranslateSize : 2; /**< Bits 13:12 - GATS: Guest Address Translation Size. */ + uint32_t u2GstCr3RootTblLevel : 2; /**< Bits 15:14 - GLXSup: Guest CR3 Root Table Level (Max) Size Support. */ + uint32_t u2SmiFilterSup : 2; /**< Bits 17:16 - SmiFSup: SMI Filter Register Support. */ + uint32_t u3SmiFilterCount : 3; /**< Bits 20:18 - SmiFRC: SMI Filter Register Count. */ + uint32_t u3GstVirtApicModeSup : 3; /**< Bits 23:21 - GAMSup: Guest Virtual-APIC Modes Supported. */ + uint32_t u2DualPprLogSup : 2; /**< Bits 25:24 - DualPprLogSup: Dual Peripheral Page Request Log Support. */ + uint32_t u2Rsvd0 : 2; /**< Bits 27:26 - Reserved. */ + uint32_t u2DualEvtLogSup : 2; /**< Bits 29:28 - DualEventLogSup: Dual Event Log Support. */ + uint32_t u2Rsvd1 : 2; /**< Bits 31:30 - Reserved. */ + uint32_t u5MaxPasidSup : 5; /**< Bits 36:32 - PASMax: Maximum PASID Supported. */ + uint32_t u1UserSupervisorSup : 1; /**< Bit 37 - USSup: User/Supervisor Page Protection Support. */ + uint32_t u2DevTabSegSup : 2; /**< Bits 39:38 - DevTlbSegSup: Segmented Device Table Support. */ + uint32_t u1PprLogOverflowWarn : 1; /**< Bit 40 - PprOvrflwEarlySup: PPR Log Overflow Early Warning Support. */ + uint32_t u1PprAutoRespSup : 1; /**< Bit 41 - PprAutoRspSup: PPR Automatic Response Support. */ + uint32_t u2MarcSup : 2; /**< Bit 43:42 - MarcSup: Memory Access Routing and Control Support. */ + uint32_t u1BlockStopMarkSup : 1; /**< Bit 44 - BlkStopMarkSup: Block StopMark messages Support. */ + uint32_t u1PerfOptSup : 1; /**< Bit 45 - PerfOptSup: IOMMU Performance Optimization Support. */ + uint32_t u1MsiCapMmioSup : 1; /**< Bit 46 - MsiCapMmioSup: MSI Capability Register MMIO Access Support. */ + uint32_t u1Rsvd1 : 1; /**< Bit 47 - Reserved. */ + uint32_t u1GstIoSup : 1; /**< Bit 48 - GIoSup: Guest I/O Protection Support. */ + uint32_t u1HostAccessSup : 1; /**< Bit 49 - HASup: Host Access Support. */ + uint32_t u1EnhancedPprSup : 1; /**< Bit 50 - EPHSup: Enhanced Peripheral Page Request Handling Support. */ + uint32_t u1AttrForwardSup : 1; /**< Bit 51 - AttrFWSup: Attribute Forward Support. */ + uint32_t u1HostDirtySup : 1; /**< Bit 52 - HDSup: Host Dirty Support. */ + uint32_t u1Rsvd2 : 1; /**< Bit 53 - Reserved. */ + uint32_t u1InvIoTlbTypeSup : 1; /**< Bit 54 - InvIotlbTypeSup: Invalidate IOTLB Type Support. */ + uint32_t u6Rsvd0 : 6; /**< Bit 60:55 - Reserved. */ + uint32_t u1GstUpdateDisSup : 1; /**< Bit 61 - GAUpdateDisSup: Disable hardware update on GPT Support. */ + uint32_t u1ForcePhysDstSup : 1; /**< Bit 62 - ForcePhyDestSup: Force Phys. Dst. Mode for Remapped Intr. */ + uint32_t u1Rsvd3 : 1; /**< Bit 63 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_EXT_FEAT_T; +AssertCompileSize(IOMMU_EXT_FEAT_T, 8); + +/** + * Peripheral Page Request Log Base Address Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bit 11:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40Base : 40; /**< Bits 51:12 - PPRLogBase: Peripheral Page Request Log Base Address. */ + RT_GCC_EXTENSION uint64_t u4Rsvd0 : 4; /**< Bits 55:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u4Len : 4; /**< Bits 59:56 - PPRLogLen: Peripheral Page Request Log Length. */ + RT_GCC_EXTENSION uint64_t u4Rsvd1 : 4; /**< Bits 63:60 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} PPR_LOG_BAR_T; +AssertCompileSize(PPR_LOG_BAR_T, 8); +#define IOMMU_PPR_LOG_BAR_VALID_MASK UINT64_C(0x0f0ffffffffff000) + +/** + * IOMMU Hardware Event Upper Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u60FirstOperand : 60; /**< Bits 59:0 - First event code dependent operand. */ + RT_GCC_EXTENSION uint64_t u4EvtCode : 4; /**< Bits 63:60 - Event Code. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_HW_EVT_HI_T; +AssertCompileSize(IOMMU_HW_EVT_HI_T, 8); + +/** + * IOMMU Hardware Event Lower Register (MMIO). + * In accordance with the AMD spec. + */ +typedef uint64_t IOMMU_HW_EVT_LO_T; + +/** + * IOMMU Hardware Event Status (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1Valid : 1; /**< Bit 0 - HEV: Hardware Event Valid. */ + uint32_t u1Overflow : 1; /**< Bit 1 - HEO: Hardware Event Overflow. */ + uint32_t u30Rsvd0 : 30; /**< Bits 31:2 - Reserved. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_HW_EVT_STATUS_T; +AssertCompileSize(IOMMU_HW_EVT_STATUS_T, 8); +#define IOMMU_HW_EVT_STATUS_VALID_MASK UINT64_C(0x0000000000000003) + +/** + * Guest Virtual-APIC Log Base Address Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bit 11:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40Base : 40; /**< Bits 51:12 - GALogBase: Guest Virtual-APIC Log Base Address. */ + RT_GCC_EXTENSION uint64_t u4Rsvd0 : 4; /**< Bits 55:52 - Reserved. */ + RT_GCC_EXTENSION uint64_t u4Len : 4; /**< Bits 59:56 - GALogLen: Guest Virtual-APIC Log Length. */ + RT_GCC_EXTENSION uint64_t u4Rsvd1 : 4; /**< Bits 63:60 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} GALOG_BAR_T; +AssertCompileSize(GALOG_BAR_T, 8); + +/** + * Guest Virtual-APIC Log Tail Address Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u3Rsvd0 : 3; /**< Bits 2:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40GALogTailAddr : 48; /**< Bits 51:3 - GATAddr: Guest Virtual-APIC Tail Log Address. */ + RT_GCC_EXTENSION uint64_t u11Rsvd1 : 11; /**< Bits 63:52 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} GALOG_TAIL_ADDR_T; +AssertCompileSize(GALOG_TAIL_ADDR_T, 8); + +/** + * PPR Log B Base Address Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to PPR_LOG_BAR_T. + */ +typedef PPR_LOG_BAR_T PPR_LOG_B_BAR_T; + +/** + * Event Log B Base Address Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to EVT_LOG_BAR_T. + */ +typedef EVT_LOG_BAR_T EVT_LOG_B_BAR_T; + +/** + * Device-specific Feature Extension (DSFX) Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u24DevSpecFeat : 24; /**< Bits 23:0 - DevSpecificFeatSupp: Implementation specific features. */ + uint32_t u4RevMinor : 4; /**< Bits 27:24 - RevMinor: Minor revision identifier. */ + uint32_t u4RevMajor : 4; /**< Bits 31:28 - RevMajor: Major revision identifier. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved.*/ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} DEV_SPECIFIC_FEAT_T; +AssertCompileSize(DEV_SPECIFIC_FEAT_T, 8); + +/** + * Device-specific Control Extension (DSCX) Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u24DevSpecCtrl : 24; /**< Bits 23:0 - DevSpecificFeatCntrl: Implementation specific control. */ + uint32_t u4RevMinor : 4; /**< Bits 27:24 - RevMinor: Minor revision identifier. */ + uint32_t u4RevMajor : 4; /**< Bits 31:28 - RevMajor: Major revision identifier. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved.*/ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} DEV_SPECIFIC_CTRL_T; +AssertCompileSize(DEV_SPECIFIC_CTRL_T, 8); + +/** + * Device-specific Status Extension (DSSX) Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u24DevSpecStatus : 24; /**< Bits 23:0 - DevSpecificFeatStatus: Implementation specific status. */ + uint32_t u4RevMinor : 4; /**< Bits 27:24 - RevMinor: Minor revision identifier. */ + uint32_t u4RevMajor : 4; /**< Bits 31:28 - RevMajor: Major revision identifier. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved.*/ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} DEV_SPECIFIC_STATUS_T; +AssertCompileSize(DEV_SPECIFIC_STATUS_T, 8); + +/** + * MSI Information Register 0 and 1 (PCI) / MSI Vector Register 0 and 1 (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u5MsiNumEvtLog : 5; /**< Bits 4:0 - MsiNum: Event Log MSI message number. */ + uint32_t u3GstVirtAddrSize: 3; /**< Bits 7:5 - GVAsize: Guest Virtual Address Size. */ + uint32_t u7PhysAddrSize : 7; /**< Bits 14:8 - PAsize: Physical Address Size. */ + uint32_t u7VirtAddrSize : 7; /**< Bits 21:15 - VAsize: Virtual Address Size. */ + uint32_t u1HtAtsResv: 1; /**< Bit 22 - HtAtsResv: HyperTransport ATS Response Address range Reserved. */ + uint32_t u4Rsvd0 : 4; /**< Bits 26:23 - Reserved. */ + uint32_t u5MsiNumPpr : 5; /**< Bits 31:27 - MsiNumPPR: Peripheral Page Request MSI message number. */ + uint32_t u5MsiNumGa : 5; /**< Bits 36:32 - MsiNumGa: MSI message number for guest virtual-APIC log. */ + uint32_t u27Rsvd0: 27; /**< Bits 63:37 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} MSI_MISC_INFO_T; +AssertCompileSize(MSI_MISC_INFO_T, 8); +/** MSI Vector Register 0 and 1 (MMIO). */ +typedef MSI_MISC_INFO_T MSI_VECTOR_T; +/** Mask of valid bits in MSI Vector Register 1 (or high dword of MSI Misc. + * info). */ +#define IOMMU_MSI_VECTOR_1_VALID_MASK UINT32_C(0x1f) + +/** + * MSI Capability Header Register (PCI + MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u8MsiCapId : 8; /**< Bits 7:0 - MsiCapId: Capability ID. */ + uint32_t u8MsiCapPtr : 8; /**< Bits 15:8 - MsiCapPtr: Pointer (PCI config offset) to the next capability. */ + uint32_t u1MsiEnable : 1; /**< Bit 16 - MsiEn: Message Signal Interrupt Enable. */ + uint32_t u3MsiMultiMessCap : 3; /**< Bits 19:17 - MsiMultMessCap: MSI Multi-Message Capability. */ + uint32_t u3MsiMultiMessEn : 3; /**< Bits 22:20 - MsiMultMessEn: MSI Multi-Message Enable. */ + uint32_t u1Msi64BitEn : 1; /**< Bit 23 - Msi64BitEn: MSI 64-bit Enable. */ + uint32_t u8Rsvd0 : 8; /**< Bits 31:24 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} MSI_CAP_HDR_T; +AssertCompileSize(MSI_CAP_HDR_T, 4); +#define IOMMU_MSI_CAP_HDR_MSI_EN_MASK RT_BIT(16) + +/** + * MSI Mapping Capability Header Register (PCI + MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u8MsiMapCapId : 8; /**< Bits 7:0 - MsiMapCapId: MSI Map capability ID. */ + uint32_t u8Rsvd0 : 8; /**< Bits 15:8 - Reserved. */ + uint32_t u1MsiMapEn : 1; /**< Bit 16 - MsiMapEn: MSI Map enable. */ + uint32_t u1MsiMapFixed : 1; /**< Bit 17 - MsiMapFixd: MSI Map fixed. */ + uint32_t u9Rsvd0 : 9; /**< Bits 26:18 - Reserved. */ + uint32_t u5MapCapType : 5; /**< Bits 31:27 - MsiMapCapType: MSI Mapping capability type. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} MSI_MAP_CAP_HDR_T; +AssertCompileSize(MSI_MAP_CAP_HDR_T, 4); + +/** + * Performance Optimization Control Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u13Rsvd0 : 13; /**< Bits 12:0 - Reserved. */ + uint32_t u1PerfOptEn : 1; /**< Bit 13 - PerfOptEn: Performance Optimization Enable. */ + uint32_t u17Rsvd0 : 18; /**< Bits 31:14 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} IOMMU_PERF_OPT_CTRL_T; +AssertCompileSize(IOMMU_PERF_OPT_CTRL_T, 4); + +/** + * XT (x2APIC) IOMMU General Interrupt Control Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u2Rsvd0 : 2; /**< Bits 1:0 - Reserved.*/ + uint32_t u1X2ApicIntrDstMode : 1; /**< Bit 2 - Destination Mode for general interrupt.*/ + uint32_t u4Rsvd0 : 4; /**< Bits 7:3 - Reserved.*/ + uint32_t u24X2ApicIntrDstLo : 24; /**< Bits 31:8 - Destination for general interrupt (Lo).*/ + uint32_t u8X2ApicIntrVector : 8; /**< Bits 39:32 - Vector for general interrupt.*/ + uint32_t u1X2ApicIntrDeliveryMode : 1; /**< Bit 40 - Delivery Mode for general interrupt.*/ + uint32_t u15Rsvd0 : 15; /**< Bits 55:41 - Reserved.*/ + uint32_t u7X2ApicIntrDstHi : 7; /**< Bits 63:56 - Destination for general interrupt (Hi) .*/ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_XT_GEN_INTR_CTRL_T; +AssertCompileSize(IOMMU_XT_GEN_INTR_CTRL_T, 8); + +/** + * XT (x2APIC) IOMMU General Interrupt Control Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u2Rsvd0 : 2; /**< Bits 1:0 - Reserved.*/ + uint32_t u1X2ApicIntrDstMode : 1; /**< Bit 2 - Destination Mode for the interrupt.*/ + uint32_t u4Rsvd0 : 4; /**< Bits 7:3 - Reserved.*/ + uint32_t u24X2ApicIntrDstLo : 24; /**< Bits 31:8 - Destination for the interrupt (Lo).*/ + uint32_t u8X2ApicIntrVector : 8; /**< Bits 39:32 - Vector for the interrupt.*/ + uint32_t u1X2ApicIntrDeliveryMode : 1; /**< Bit 40 - Delivery Mode for the interrupt.*/ + uint32_t u15Rsvd0 : 15; /**< Bits 55:41 - Reserved.*/ + uint32_t u7X2ApicIntrDstHi : 7; /**< Bits 63:56 - Destination for the interrupt (Hi) .*/ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_XT_INTR_CTRL_T; +AssertCompileSize(IOMMU_XT_INTR_CTRL_T, 8); + +/** + * XT (x2APIC) IOMMU PPR Interrupt Control Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to IOMMU_XT_INTR_CTRL_T. + */ +typedef IOMMU_XT_INTR_CTRL_T IOMMU_XT_PPR_INTR_CTRL_T; + +/** + * XT (x2APIC) IOMMU GA (Guest Address) Log Control Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to IOMMU_XT_INTR_CTRL_T. + */ +typedef IOMMU_XT_INTR_CTRL_T IOMMU_XT_GALOG_INTR_CTRL_T; + +/** + * Memory Access and Routing Control (MARC) Aperture Base Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 11:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40MarcBaseAddr : 40; /**< Bits 51:12 - MarcBaseAddr: MARC Aperture Base Address. */ + RT_GCC_EXTENSION uint64_t u12Rsvd1 : 12; /**< Bits 63:52 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} MARC_APER_BAR_T; +AssertCompileSize(MARC_APER_BAR_T, 8); + +/** + * Memory Access and Routing Control (MARC) Relocation Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u1RelocEn : 1; /**< Bit 0 - RelocEn: Relocation Enabled. */ + RT_GCC_EXTENSION uint64_t u1ReadOnly : 1; /**< Bit 1 - ReadOnly: Whether only read-only acceses allowed. */ + RT_GCC_EXTENSION uint64_t u10Rsvd0 : 10; /**< Bits 11:2 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40MarcRelocAddr : 40; /**< Bits 51:12 - MarcRelocAddr: MARC Aperture Relocation Address. */ + RT_GCC_EXTENSION uint64_t u12Rsvd1 : 12; /**< Bits 63:52 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} MARC_APER_RELOC_T; +AssertCompileSize(MARC_APER_RELOC_T, 8); + +/** + * Memory Access and Routing Control (MARC) Length Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Rsvd0 : 12; /**< Bits 11:0 - Reserved. */ + RT_GCC_EXTENSION uint64_t u40MarcLength : 40; /**< Bits 51:12 - MarcLength: MARC Aperture Length. */ + RT_GCC_EXTENSION uint64_t u12Rsvd1 : 12; /**< Bits 63:52 - Reserved. */ + } n; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} MARC_APER_LEN_T; + +/** + * Memory Access and Routing Control (MARC) Aperture Register. + * This combines other registers to match the MMIO layout for convenient access. + */ +typedef struct +{ + MARC_APER_BAR_T Base; + MARC_APER_RELOC_T Reloc; + MARC_APER_LEN_T Length; +} MARC_APER_T; +AssertCompileSize(MARC_APER_T, 24); + +/** + * IOMMU Reserved Register (MMIO). + * In accordance with the AMD spec. + * This register is reserved for hardware use (although RW?). + */ +typedef uint64_t IOMMU_RSVD_REG_T; + +/** + * Command Buffer Head Pointer Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t off; /**< Bits 31:0 - Buffer pointer (offset; 16 byte aligned, 512 KB max). */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} CMD_BUF_HEAD_PTR_T; +AssertCompileSize(CMD_BUF_HEAD_PTR_T, 8); +#define IOMMU_CMD_BUF_HEAD_PTR_VALID_MASK UINT64_C(0x000000000007fff0) + +/** + * Command Buffer Tail Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T CMD_BUF_TAIL_PTR_T; +#define IOMMU_CMD_BUF_TAIL_PTR_VALID_MASK IOMMU_CMD_BUF_HEAD_PTR_VALID_MASK + +/** + * Event Log Head Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T EVT_LOG_HEAD_PTR_T; +#define IOMMU_EVT_LOG_HEAD_PTR_VALID_MASK IOMMU_CMD_BUF_HEAD_PTR_VALID_MASK + +/** + * Event Log Tail Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T EVT_LOG_TAIL_PTR_T; +#define IOMMU_EVT_LOG_TAIL_PTR_VALID_MASK IOMMU_CMD_BUF_HEAD_PTR_VALID_MASK + + +/** + * IOMMU Status Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u1EvtOverflow : 1; /**< Bit 0 - EventOverflow: Event log overflow. */ + uint32_t u1EvtLogIntr : 1; /**< Bit 1 - EventLogInt: Event log interrupt. */ + uint32_t u1CompWaitIntr : 1; /**< Bit 2 - ComWaitInt: Completion wait interrupt . */ + uint32_t u1EvtLogRunning : 1; /**< Bit 3 - EventLogRun: Event logging is running. */ + uint32_t u1CmdBufRunning : 1; /**< Bit 4 - CmdBufRun: Command buffer is running. */ + uint32_t u1PprOverflow : 1; /**< Bit 5 - PprOverflow: Peripheral Page Request Log (PPR) overflow. */ + uint32_t u1PprIntr : 1; /**< Bit 6 - PprInt: PPR interrupt. */ + uint32_t u1PprLogRunning : 1; /**< Bit 7 - PprLogRun: PPR logging is running. */ + uint32_t u1GstLogRunning : 1; /**< Bit 8 - GALogRun: Guest virtual-APIC logging is running. */ + uint32_t u1GstLogOverflow : 1; /**< Bit 9 - GALOverflow: Guest virtual-APIC log overflow. */ + uint32_t u1GstLogIntr : 1; /**< Bit 10 - GAInt: Guest virtual-APIC log interrupt. */ + uint32_t u1PprOverflowB : 1; /**< Bit 11 - PprOverflowB: PPR log B overflow. */ + uint32_t u1PprLogActive : 1; /**< Bit 12 - PprLogActive: PPR log A is active. */ + uint32_t u2Rsvd0 : 2; /**< Bits 14:13 - Reserved. */ + uint32_t u1EvtOverflowB : 1; /**< Bit 15 - EvtOverflowB: Event log B overflow. */ + uint32_t u1EvtLogActive : 1; /**< Bit 16 - EvtLogActive: Event log A active. */ + uint32_t u1PprOverflowEarlyB : 1; /**< Bit 17 - PprOverflowEarlyB: PPR log B overflow early warning. */ + uint32_t u1PprOverflowEarly : 1; /**< Bit 18 - PprOverflowEarly: PPR log overflow early warning. */ + uint32_t u13Rsvd0 : 13; /**< Bits 31:19 - Reserved. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved . */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} IOMMU_STATUS_T; +AssertCompileSize(IOMMU_STATUS_T, 8); +#define IOMMU_STATUS_VALID_MASK UINT64_C(0x0000000000079fff) +#define IOMMU_STATUS_RW1C_MASK UINT64_C(0x0000000000068e67) + +/** + * PPR Log Head Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T PPR_LOG_HEAD_PTR_T; + +/** + * PPR Log Tail Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T PPR_LOG_TAIL_PTR_T; + +/** + * Guest Virtual-APIC Log Head Pointer Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u2Rsvd0 : 2; /**< Bits 2:0 - Reserved. */ + uint32_t u12GALogPtr : 12; /**< Bits 15:3 - Guest Virtual-APIC Log Head or Tail Pointer. */ + uint32_t u16Rsvd0 : 16; /**< Bits 31:16 - Reserved. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} GALOG_HEAD_PTR_T; +AssertCompileSize(GALOG_HEAD_PTR_T, 8); + +/** + * Guest Virtual-APIC Log Tail Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to GALOG_HEAD_PTR_T. + */ +typedef GALOG_HEAD_PTR_T GALOG_TAIL_PTR_T; + +/** + * PPR Log B Head Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T PPR_LOG_B_HEAD_PTR_T; + +/** + * PPR Log B Tail Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T PPR_LOG_B_TAIL_PTR_T; + +/** + * Event Log B Head Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T EVT_LOG_B_HEAD_PTR_T; + +/** + * Event Log B Tail Pointer Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to CMD_BUF_HEAD_PTR_T. + */ +typedef CMD_BUF_HEAD_PTR_T EVT_LOG_B_TAIL_PTR_T; + +/** + * PPR Log Auto Response Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u4AutoRespCode : 4; /**< Bits 3:0 - PprAutoRespCode: PPR log Auto Response Code. */ + uint32_t u1AutoRespMaskGen : 1; /**< Bit 4 - PprAutoRespMaskGn: PPR log Auto Response Mask Gen. */ + uint32_t u27Rsvd0 : 27; /**< Bits 31:5 - Reserved. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved.*/ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} PPR_LOG_AUTO_RESP_T; +AssertCompileSize(PPR_LOG_AUTO_RESP_T, 8); + +/** + * PPR Log Overflow Early Indicator Register (MMIO). + * In accordance with the AMD spec. + */ +typedef union +{ + struct + { + uint32_t u15Threshold : 15; /**< Bits 14:0 - PprOvrflwEarlyThreshold: Overflow early indicator threshold. */ + uint32_t u15Rsvd0 : 15; /**< Bits 29:15 - Reserved. */ + uint32_t u1IntrEn : 1; /**< Bit 30 - PprOvrflwEarlyIntEn: Overflow early indicator interrupt enable. */ + uint32_t u1Enable : 1; /**< Bit 31 - PprOvrflwEarlyEn: Overflow early indicator enable. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved. */ + } n; + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} PPR_LOG_OVERFLOW_EARLY_T; +AssertCompileSize(PPR_LOG_OVERFLOW_EARLY_T, 8); + +/** + * PPR Log B Overflow Early Indicator Register (MMIO). + * In accordance with the AMD spec. + * Currently identical to PPR_LOG_OVERFLOW_EARLY_T. + */ +typedef PPR_LOG_OVERFLOW_EARLY_T PPR_LOG_B_OVERFLOW_EARLY_T; + +/** + * ILLEGAL_DEV_TABLE_ENTRY Event Types. + * In accordance with the AMD spec. + */ +typedef enum EVT_ILLEGAL_DTE_TYPE_T +{ + kIllegalDteType_RsvdNotZero = 0, + kIllegalDteType_RsvdIntTabLen, + kIllegalDteType_RsvdIoCtl, + kIllegalDteType_RsvdIntCtl +} EVT_ILLEGAL_DTE_TYPE_T; + +/** + * ILLEGAL_DEV_TABLE_ENTRY Event Types. + * In accordance with the AMD spec. + */ +typedef enum EVT_IO_PAGE_FAULT_TYPE_T +{ + /* Memory transaction. */ + kIoPageFaultType_DteRsvdPagingMode = 0, + kIoPageFaultType_PteInvalidPageSize, + kIoPageFaultType_PteInvalidLvlEncoding, + kIoPageFaultType_SkippedLevelIovaNotZero, + kIoPageFaultType_PteRsvdNotZero, + kIoPageFaultType_PteValidNotSet, + kIoPageFaultType_DteTranslationDisabled, + kIoPageFaultType_PasidInvalidRange, + kIoPageFaultType_PermDenied, + kIoPageFaultType_UserSupervisor, + /* Interrupt remapping */ + kIoPageFaultType_IrteAddrInvalid, + kIoPageFaultType_IrteRsvdNotZero, + kIoPageFaultType_IrteRemapEn, + kIoPageFaultType_IrteRsvdIntType, + kIoPageFaultType_IntrReqAborted, + kIoPageFaultType_IntrWithPasid, + kIoPageFaultType_SmiFilterMismatch, + /* Memory transaction or interrupt remapping. */ + kIoPageFaultType_DevId_Invalid +} EVT_IO_PAGE_FAULT_TYPE_T; + +/** + * IOTLB_INV_TIMEOUT Event Types. + * In accordance with the AMD spec. + */ +typedef enum EVT_IOTLB_INV_TIMEOUT_TYPE_T +{ + InvTimeoutType_NoResponse = 0 +} EVT_IOTLB_INV_TIMEOUT_TYPE_T; + +/** + * INVALID_DEVICE_REQUEST Event Types. + * In accordance with the AMD spec. + */ +typedef enum EVT_INVALID_DEV_REQ_TYPE_T +{ + /* Access. */ + kInvalidDevReqType_ReadOrNonPostedWrite = 0, + kInvalidDevReqType_PretranslatedTransaction, + kInvalidDevReqType_PortIo, + kInvalidDevReqType_SysMgt, + kInvalidDevReqType_IntrRange, + kInvalidDevReqType_RsvdIntrRange, + kInvalidDevReqType_SysMgtAddr, + /* Translation Request. */ + kInvalidDevReqType_TrAccessInvalid, + kInvalidDevReqType_TrDisabled, + kInvalidDevReqType_DevIdInvalid +} EVT_INVALID_DEV_REQ_TYPE_T; + +/** + * INVALID_PPR_REQUEST Event Types. + * In accordance with the AMD spec. + */ +typedef enum EVT_INVALID_PPR_REQ_TYPE_T +{ + kInvalidPprReqType_PriNotSupported, + kInvalidPprReqType_GstTranslateDisabled +} EVT_INVALID_PPR_REQ_TYPE_T; + + +/** @name IVRS format revision field. + * In accordance with the AMD spec. + * @{ */ +/** Fixed: Supports only pre-assigned device IDs and type 10h and 11h IVHD + * blocks. */ +#define ACPI_IVRS_FMT_REV_FIXED 0x1 +/** Mixed: Supports pre-assigned and ACPI HID device naming and all IVHD blocks. */ +#define ACPI_IVRS_FMT_REV_MIXED 0x2 +/** @} */ + +/** @name IVHD special device entry variety field. + * In accordance with the AMD spec. + * @{ */ +/** I/O APIC. */ +#define ACPI_IVHD_VARIETY_IOAPIC 0x1 +/** HPET. */ +#define ACPI_IVHD_VARIETY_HPET 0x2 +/** @} */ + +/** @name IVHD device entry type codes. + * In accordance with the AMD spec. + * @{ */ +/** Reserved. */ +#define ACPI_IVHD_DEVENTRY_TYPE_RSVD 0x0 +/** All: DTE setting applies to all Device IDs. */ +#define ACPI_IVHD_DEVENTRY_TYPE_ALL 0x1 +/** Select: DTE setting applies to the device specified in DevId field. */ +#define ACPI_IVHD_DEVENTRY_TYPE_SELECT 0x2 +/** Start of range: DTE setting applies to all devices from start of range specified + * by the DevId field. */ +#define ACPI_IVHD_DEVENTRY_TYPE_START_RANGE 0x3 +/** End of range: DTE setting from previous type 3 entry applies to all devices + * incl. DevId specified by this entry. */ +#define ACPI_IVHD_DEVENTRY_TYPE_END_RANGE 0x4 +/** @} */ + +/** @name IVHD DTE (Device Table Entry) Settings. + * In accordance with the AMD spec. + * @{ */ +/** INITPass: Identifies a device able to assert INIT interrupts. */ +#define ACPI_IVHD_DTE_INIT_PASS_SHIFT 0 +#define ACPI_IVHD_DTE_INIT_PASS_MASK UINT8_C(0x01) +/** EIntPass: Identifies a device able to assert ExtInt interrupts. */ +#define ACPI_IVHD_DTE_EXTINT_PASS_SHIFT 1 +#define ACPI_IVHD_DTE_EXTINT_PASS_MASK UINT8_C(0x02) +/** NMIPass: Identifies a device able to assert NMI interrupts. */ +#define ACPI_IVHD_DTE_NMI_PASS_SHIFT 2 +#define ACPI_IVHD_DTE_NMI_PASS_MASK UINT8_C(0x04) +/** Bit 3 reserved. */ +#define ACPI_IVHD_DTE_RSVD_3_SHIFT 3 +#define ACPI_IVHD_DTE_RSVD_3_MASK UINT8_C(0x08) +/** SysMgt: Identifies a device able to assert system management messages. */ +#define ACPI_IVHD_DTE_SYS_MGT_SHIFT 4 +#define ACPI_IVHD_DTE_SYS_MGT_MASK UINT8_C(0x30) +/** Lint0Pass: Identifies a device able to assert LINT0 interrupts. */ +#define ACPI_IVHD_DTE_LINT0_PASS_SHIFT 6 +#define ACPI_IVHD_DTE_LINT0_PASS_MASK UINT8_C(0x40) +/** Lint0Pass: Identifies a device able to assert LINT1 interrupts. */ +#define ACPI_IVHD_DTE_LINT1_PASS_SHIFT 7 +#define ACPI_IVHD_DTE_LINT1_PASS_MASK UINT8_C(0x80) +RT_BF_ASSERT_COMPILE_CHECKS(ACPI_IVHD_DTE_, UINT8_C(0), UINT8_MAX, + (INIT_PASS, EXTINT_PASS, NMI_PASS, RSVD_3, SYS_MGT, LINT0_PASS, LINT1_PASS)); +/** @} */ + +/** + * AMD IOMMU: IVHD (I/O Virtualization Hardware Definition) Device Entry (4-byte). + * In accordance with the AMD spec. + */ +#pragma pack(1) +typedef struct ACPIIVHDDEVENTRY4 +{ + uint8_t u8DevEntryType; /**< Device entry type. */ + uint16_t u16DevId; /**< Device ID. */ + uint8_t u8DteSetting; /**< DTE (Device Table Entry) setting. */ +} ACPIIVHDDEVENTRY4; +#pragma pack() +AssertCompileSize(ACPIIVHDDEVENTRY4, 4); + +/** + * AMD IOMMU: IVHD (I/O Virtualization Hardware Definition) Device Entry (8-byte). + * In accordance with the AMD spec. + */ +#pragma pack(1) +typedef struct ACPIIVHDDEVENTRY8 +{ + uint8_t u8DevEntryType; /**< Device entry type. */ + union + { + /** Reserved: When u8DevEntryType is 0x40, 0x41, 0x44 or 0x45 (or 0x49-0x7F). */ + struct + { + uint8_t au8Rsvd0[7]; /**< Reserved (MBZ). */ + } rsvd; + /** Alias Select: When u8DevEntryType is 0x42 or 0x43. */ + struct + { + uint16_t u16DevIdA; /**< Device ID A. */ + uint8_t u8DteSetting; /**< DTE (Device Table Entry) setting. */ + uint8_t u8Rsvd0; /**< Reserved (MBZ). */ + uint16_t u16DevIdB; /**< Device ID B. */ + uint8_t u8Rsvd1; /**< Reserved (MBZ). */ + } alias; + /** Extended Select: When u8DevEntryType is 0x46 or 0x47. */ + struct + { + uint16_t u16DevId; /**< Device ID. */ + uint8_t u8DteSetting; /**< DTE (Device Table Entry) setting. */ + uint32_t u32ExtDteSetting; /**< Extended DTE setting. */ + } ext; + /** Special Device: When u8DevEntryType is 0x48. */ + struct + { + uint16_t u16Rsvd0; /**< Reserved (MBZ). */ + uint8_t u8DteSetting; /**< DTE (Device Table Entry) setting. */ + uint8_t u8Handle; /**< Handle contains I/O APIC ID or HPET number. */ + uint16_t u16DevIdB; /**< Device ID B (I/O APIC or HPET). */ + uint8_t u8Variety; /**< Whether this is the HPET or I/O APIC. */ + } special; + } u; +} ACPIIVHDDEVENTRY8; +#pragma pack() +AssertCompileSize(ACPIIVHDDEVENTRY8, 8); + +/** @name IVHD Type 10h Flags. + * In accordance with the AMD spec. + * @{ */ +/** Peripheral page request support. */ +#define ACPI_IVHD_10H_F_PPR_SUP RT_BIT(7) +/** Prefetch IOMMU pages command support. */ +#define ACPI_IVHD_10H_F_PREF_SUP RT_BIT(6) +/** Coherent control. */ +#define ACPI_IVHD_10H_F_COHERENT RT_BIT(5) +/** Remote IOTLB support. */ +#define ACPI_IVHD_10H_F_IOTLB_SUP RT_BIT(4) +/** Isochronous control. */ +#define ACPI_IVHD_10H_F_ISOC RT_BIT(3) +/** Response Pass Posted Write. */ +#define ACPI_IVHD_10H_F_RES_PASS_PW RT_BIT(2) +/** Pass Posted Write. */ +#define ACPI_IVHD_10H_F_PASS_PW RT_BIT(1) +/** HyperTransport Tunnel. */ +#define ACPI_IVHD_10H_F_HT_TUNNEL RT_BIT(0) +/** @} */ + +/** @name IVRS IVinfo field. + * In accordance with the AMD spec. + * @{ */ +/** EFRSup: Extended Feature Support. */ +#define ACPI_IVINFO_BF_EFR_SUP_SHIFT 0 +#define ACPI_IVINFO_BF_EFR_SUP_MASK UINT32_C(0x00000001) +/** DMA Remap Sup: DMA remapping support (pre-boot DMA protection with + * mandatory remapping of device accessed memory). */ +#define ACPI_IVINFO_BF_DMA_REMAP_SUP_SHIFT 1 +#define ACPI_IVINFO_BF_DMA_REMAP_SUP_MASK UINT32_C(0x00000002) +/** Bits 4:2 reserved. */ +#define ACPI_IVINFO_BF_RSVD_2_4_SHIFT 2 +#define ACPI_IVINFO_BF_RSVD_2_4_MASK UINT32_C(0x0000001c) +/** GVASize: Guest virtual-address size. */ +#define ACPI_IVINFO_BF_GVA_SIZE_SHIFT 5 +#define ACPI_IVINFO_BF_GVA_SIZE_MASK UINT32_C(0x000000e0) +/** PASize: System physical address size. */ +#define ACPI_IVINFO_BF_PA_SIZE_SHIFT 8 +#define ACPI_IVINFO_BF_PA_SIZE_MASK UINT32_C(0x00007f00) +/** VASize: Virtual address size. */ +#define ACPI_IVINFO_BF_VA_SIZE_SHIFT 15 +#define ACPI_IVINFO_BF_VA_SIZE_MASK UINT32_C(0x003f8000) +/** HTAtsResv: HyperTransport ATS-response address translation range reserved. */ +#define ACPI_IVINFO_BF_HT_ATS_RESV_SHIFT 22 +#define ACPI_IVINFO_BF_HT_ATS_RESV_MASK UINT32_C(0x00400000) +/** Bits 31:23 reserved. */ +#define ACPI_IVINFO_BF_RSVD_23_31_SHIFT 23 +#define ACPI_IVINFO_BF_RSVD_23_31_MASK UINT32_C(0xff800000) +RT_BF_ASSERT_COMPILE_CHECKS(ACPI_IVINFO_BF_, UINT32_C(0), UINT32_MAX, + (EFR_SUP, DMA_REMAP_SUP, RSVD_2_4, GVA_SIZE, PA_SIZE, VA_SIZE, HT_ATS_RESV, RSVD_23_31)); +/** @} */ + +/** @name IVHD IOMMU info flags. + * In accordance with the AMD spec. + * @{ */ +/** MSI message number for the event log. */ +#define ACPI_IOMMU_INFO_BF_MSI_NUM_SHIFT 0 +#define ACPI_IOMMU_INFO_BF_MSI_NUM_MASK UINT16_C(0x001f) +/** Bits 7:5 reserved. */ +#define ACPI_IOMMU_INFO_BF_RSVD_5_7_SHIFT 5 +#define ACPI_IOMMU_INFO_BF_RSVD_5_7_MASK UINT16_C(0x00e0) +/** IOMMU HyperTransport Unit ID number. */ +#define ACPI_IOMMU_INFO_BF_UNIT_ID_SHIFT 8 +#define ACPI_IOMMU_INFO_BF_UNIT_ID_MASK UINT16_C(0x1f00) +/** Bits 15:13 reserved. */ +#define ACPI_IOMMU_INFO_BF_RSVD_13_15_SHIFT 13 +#define ACPI_IOMMU_INFO_BF_RSVD_13_15_MASK UINT16_C(0xe000) +RT_BF_ASSERT_COMPILE_CHECKS(ACPI_IOMMU_INFO_BF_, UINT16_C(0), UINT16_MAX, + (MSI_NUM, RSVD_5_7, UNIT_ID, RSVD_13_15)); +/** @} */ + +/** @name IVHD IOMMU feature reporting field. + * In accordance with the AMD spec. + * @{ */ +/** x2APIC supported for peripherals. */ +#define ACPI_IOMMU_FEAT_BF_XT_SUP_SHIFT 0 +#define ACPI_IOMMU_FEAT_BF_XT_SUP_MASK UINT32_C(0x00000001) +/** NX supported for I/O. */ +#define ACPI_IOMMU_FEAT_BF_NX_SUP_SHIFT 1 +#define ACPI_IOMMU_FEAT_BF_NX_SUP_MASK UINT32_C(0x00000002) +/** GT (Guest Translation) supported. */ +#define ACPI_IOMMU_FEAT_BF_GT_SUP_SHIFT 2 +#define ACPI_IOMMU_FEAT_BF_GT_SUP_MASK UINT32_C(0x00000004) +/** GLX (Number of guest CR3 tables) supported. */ +#define ACPI_IOMMU_FEAT_BF_GLX_SUP_SHIFT 3 +#define ACPI_IOMMU_FEAT_BF_GLX_SUP_MASK UINT32_C(0x00000018) +/** IA (INVALIDATE_IOMMU_ALL) command supported. */ +#define ACPI_IOMMU_FEAT_BF_IA_SUP_SHIFT 5 +#define ACPI_IOMMU_FEAT_BF_IA_SUP_MASK UINT32_C(0x00000020) +/** GA (Guest virtual APIC) supported. */ +#define ACPI_IOMMU_FEAT_BF_GA_SUP_SHIFT 6 +#define ACPI_IOMMU_FEAT_BF_GA_SUP_MASK UINT32_C(0x00000040) +/** HE (Hardware error) registers supported. */ +#define ACPI_IOMMU_FEAT_BF_HE_SUP_SHIFT 7 +#define ACPI_IOMMU_FEAT_BF_HE_SUP_MASK UINT32_C(0x00000080) +/** PASMax (maximum PASID) supported. Ignored if PPRSup=0. */ +#define ACPI_IOMMU_FEAT_BF_PAS_MAX_SHIFT 8 +#define ACPI_IOMMU_FEAT_BF_PAS_MAX_MASK UINT32_C(0x00001f00) +/** PNCounters (Number of performance counters per counter bank) supported. */ +#define ACPI_IOMMU_FEAT_BF_PN_COUNTERS_SHIFT 13 +#define ACPI_IOMMU_FEAT_BF_PN_COUNTERS_MASK UINT32_C(0x0001e000) +/** PNBanks (Number of performance counter banks) supported. */ +#define ACPI_IOMMU_FEAT_BF_PN_BANKS_SHIFT 17 +#define ACPI_IOMMU_FEAT_BF_PN_BANKS_MASK UINT32_C(0x007e0000) +/** MSINumPPR (MSI number for peripheral page requests). */ +#define ACPI_IOMMU_FEAT_BF_MSI_NUM_PPR_SHIFT 23 +#define ACPI_IOMMU_FEAT_BF_MSI_NUM_PPR_MASK UINT32_C(0x0f800000) +/** GATS (Guest address translation size). MBZ when GTSup=0. */ +#define ACPI_IOMMU_FEAT_BF_GATS_SHIFT 28 +#define ACPI_IOMMU_FEAT_BF_GATS_MASK UINT32_C(0x30000000) +/** HATS (Host address translation size). */ +#define ACPI_IOMMU_FEAT_BF_HATS_SHIFT 30 +#define ACPI_IOMMU_FEAT_BF_HATS_MASK UINT32_C(0xc0000000) +RT_BF_ASSERT_COMPILE_CHECKS(ACPI_IOMMU_FEAT_BF_, UINT32_C(0), UINT32_MAX, + (XT_SUP, NX_SUP, GT_SUP, GLX_SUP, IA_SUP, GA_SUP, HE_SUP, PAS_MAX, PN_COUNTERS, PN_BANKS, + MSI_NUM_PPR, GATS, HATS)); +/** @} */ + +/** @name IOMMU Extended Feature Register (PCI/MMIO/ACPI). + * In accordance with the AMD spec. + * @{ */ +/** PreFSup: Prefetch support (RO). */ +#define IOMMU_EXT_FEAT_BF_PREF_SUP_SHIFT 0 +#define IOMMU_EXT_FEAT_BF_PREF_SUP_MASK UINT64_C(0x0000000000000001) +/** PPRSup: Peripheral Page Request (PPR) support (RO). */ +#define IOMMU_EXT_FEAT_BF_PPR_SUP_SHIFT 1 +#define IOMMU_EXT_FEAT_BF_PPR_SUP_MASK UINT64_C(0x0000000000000002) +/** XTSup: x2APIC support (RO). */ +#define IOMMU_EXT_FEAT_BF_X2APIC_SUP_SHIFT 2 +#define IOMMU_EXT_FEAT_BF_X2APIC_SUP_MASK UINT64_C(0x0000000000000004) +/** NXSup: No Execute (PMR and PRIV) support (RO). */ +#define IOMMU_EXT_FEAT_BF_NO_EXEC_SUP_SHIFT 3 +#define IOMMU_EXT_FEAT_BF_NO_EXEC_SUP_MASK UINT64_C(0x0000000000000008) +/** GTSup: Guest Translation support (RO). */ +#define IOMMU_EXT_FEAT_BF_GT_SUP_SHIFT 4 +#define IOMMU_EXT_FEAT_BF_GT_SUP_MASK UINT64_C(0x0000000000000010) +/** Bit 5 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_5_SHIFT 5 +#define IOMMU_EXT_FEAT_BF_RSVD_5_MASK UINT64_C(0x0000000000000020) +/** IASup: INVALIDATE_IOMMU_ALL command support (RO). */ +#define IOMMU_EXT_FEAT_BF_IA_SUP_SHIFT 6 +#define IOMMU_EXT_FEAT_BF_IA_SUP_MASK UINT64_C(0x0000000000000040) +/** GASup: Guest virtual-APIC support (RO). */ +#define IOMMU_EXT_FEAT_BF_GA_SUP_SHIFT 7 +#define IOMMU_EXT_FEAT_BF_GA_SUP_MASK UINT64_C(0x0000000000000080) +/** HESup: Hardware error registers support (RO). */ +#define IOMMU_EXT_FEAT_BF_HE_SUP_SHIFT 8 +#define IOMMU_EXT_FEAT_BF_HE_SUP_MASK UINT64_C(0x0000000000000100) +/** PCSup: Performance counters support (RO). */ +#define IOMMU_EXT_FEAT_BF_PC_SUP_SHIFT 9 +#define IOMMU_EXT_FEAT_BF_PC_SUP_MASK UINT64_C(0x0000000000000200) +/** HATS: Host Address Translation Size (RO). */ +#define IOMMU_EXT_FEAT_BF_HATS_SHIFT 10 +#define IOMMU_EXT_FEAT_BF_HATS_MASK UINT64_C(0x0000000000000c00) +/** GATS: Guest Address Translation Size (RO). */ +#define IOMMU_EXT_FEAT_BF_GATS_SHIFT 12 +#define IOMMU_EXT_FEAT_BF_GATS_MASK UINT64_C(0x0000000000003000) +/** GLXSup: Guest CR3 root table level support (RO). */ +#define IOMMU_EXT_FEAT_BF_GLX_SUP_SHIFT 14 +#define IOMMU_EXT_FEAT_BF_GLX_SUP_MASK UINT64_C(0x000000000000c000) +/** SmiFSup: SMI filter register support (RO). */ +#define IOMMU_EXT_FEAT_BF_SMI_FLT_SUP_SHIFT 16 +#define IOMMU_EXT_FEAT_BF_SMI_FLT_SUP_MASK UINT64_C(0x0000000000030000) +/** SmiFRC: SMI filter register count (RO). */ +#define IOMMU_EXT_FEAT_BF_SMI_FLT_REG_CNT_SHIFT 18 +#define IOMMU_EXT_FEAT_BF_SMI_FLT_REG_CNT_MASK UINT64_C(0x00000000001c0000) +/** GAMSup: Guest virtual-APIC modes support (RO). */ +#define IOMMU_EXT_FEAT_BF_GAM_SUP_SHIFT 21 +#define IOMMU_EXT_FEAT_BF_GAM_SUP_MASK UINT64_C(0x0000000000e00000) +/** DualPprLogSup: Dual PPR Log support (RO). */ +#define IOMMU_EXT_FEAT_BF_DUAL_PPR_LOG_SUP_SHIFT 24 +#define IOMMU_EXT_FEAT_BF_DUAL_PPR_LOG_SUP_MASK UINT64_C(0x0000000003000000) +/** Bits 27:26 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_26_27_SHIFT 26 +#define IOMMU_EXT_FEAT_BF_RSVD_26_27_MASK UINT64_C(0x000000000c000000) +/** DualEventLogSup: Dual Event Log support (RO). */ +#define IOMMU_EXT_FEAT_BF_DUAL_EVT_LOG_SUP_SHIFT 28 +#define IOMMU_EXT_FEAT_BF_DUAL_EVT_LOG_SUP_MASK UINT64_C(0x0000000030000000) +/** Bits 31:30 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_30_31_SHIFT 30 +#define IOMMU_EXT_FEAT_BF_RSVD_30_31_MASK UINT64_C(0x00000000c0000000) +/** PASMax: Maximum PASID support (RO). */ +#define IOMMU_EXT_FEAT_BF_PASID_MAX_SHIFT 32 +#define IOMMU_EXT_FEAT_BF_PASID_MAX_MASK UINT64_C(0x0000001f00000000) +/** USSup: User/Supervisor support (RO). */ +#define IOMMU_EXT_FEAT_BF_US_SUP_SHIFT 37 +#define IOMMU_EXT_FEAT_BF_US_SUP_MASK UINT64_C(0x0000002000000000) +/** DevTblSegSup: Segmented Device Table support (RO). */ +#define IOMMU_EXT_FEAT_BF_DEV_TBL_SEG_SUP_SHIFT 38 +#define IOMMU_EXT_FEAT_BF_DEV_TBL_SEG_SUP_MASK UINT64_C(0x000000c000000000) +/** PprOverflwEarlySup: PPR Log Overflow Early warning support (RO). */ +#define IOMMU_EXT_FEAT_BF_PPR_OVERFLOW_EARLY_SHIFT 40 +#define IOMMU_EXT_FEAT_BF_PPR_OVERFLOW_EARLY_MASK UINT64_C(0x0000010000000000) +/** PprAutoRspSup: PPR Automatic Response support (RO). */ +#define IOMMU_EXT_FEAT_BF_PPR_AUTO_RES_SUP_SHIFT 41 +#define IOMMU_EXT_FEAT_BF_PPR_AUTO_RES_SUP_MASK UINT64_C(0x0000020000000000) +/** MarcSup: Memory Access and Routing (MARC) support (RO). */ +#define IOMMU_EXT_FEAT_BF_MARC_SUP_SHIFT 42 +#define IOMMU_EXT_FEAT_BF_MARC_SUP_MASK UINT64_C(0x00000c0000000000) +/** BlkStopMrkSup: Block StopMark message support (RO). */ +#define IOMMU_EXT_FEAT_BF_BLKSTOP_MARK_SUP_SHIFT 44 +#define IOMMU_EXT_FEAT_BF_BLKSTOP_MARK_SUP_MASK UINT64_C(0x0000100000000000) +/** PerfOptSup: IOMMU Performance Optimization support (RO). */ +#define IOMMU_EXT_FEAT_BF_PERF_OPT_SUP_SHIFT 45 +#define IOMMU_EXT_FEAT_BF_PERF_OPT_SUP_MASK UINT64_C(0x0000200000000000) +/** MsiCapMmioSup: MSI-Capability Register MMIO access support (RO). */ +#define IOMMU_EXT_FEAT_BF_MSI_CAP_MMIO_SUP_SHIFT 46 +#define IOMMU_EXT_FEAT_BF_MSI_CAP_MMIO_SUP_MASK UINT64_C(0x0000400000000000) +/** Bit 47 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_47_SHIFT 47 +#define IOMMU_EXT_FEAT_BF_RSVD_47_MASK UINT64_C(0x0000800000000000) +/** GIoSup: Guest I/O Protection support (RO). */ +#define IOMMU_EXT_FEAT_BF_GST_IO_PROT_SUP_SHIFT 48 +#define IOMMU_EXT_FEAT_BF_GST_IO_PROT_SUP_MASK UINT64_C(0x0001000000000000) +/** HASup: Host Access support (RO). */ +#define IOMMU_EXT_FEAT_BF_HST_ACCESS_SUP_SHIFT 49 +#define IOMMU_EXT_FEAT_BF_HST_ACCESS_SUP_MASK UINT64_C(0x0002000000000000) +/** EPHSup: Enhandled PPR Handling support (RO). */ +#define IOMMU_EXT_FEAT_BF_ENHANCED_PPR_SUP_SHIFT 50 +#define IOMMU_EXT_FEAT_BF_ENHANCED_PPR_SUP_MASK UINT64_C(0x0004000000000000) +/** AttrFWSup: Attribute Forward support (RO). */ +#define IOMMU_EXT_FEAT_BF_ATTR_FW_SUP_SHIFT 51 +#define IOMMU_EXT_FEAT_BF_ATTR_FW_SUP_MASK UINT64_C(0x0008000000000000) +/** HDSup: Host Dirty Support (RO). */ +#define IOMMU_EXT_FEAT_BF_HST_DIRTY_SUP_SHIFT 52 +#define IOMMU_EXT_FEAT_BF_HST_DIRTY_SUP_MASK UINT64_C(0x0010000000000000) +/** Bit 53 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_53_SHIFT 53 +#define IOMMU_EXT_FEAT_BF_RSVD_53_MASK UINT64_C(0x0020000000000000) +/** InvIotlbTypeSup: Invalidate IOTLB type support (RO). */ +#define IOMMU_EXT_FEAT_BF_INV_IOTLB_TYPE_SUP_SHIFT 54 +#define IOMMU_EXT_FEAT_BF_INV_IOTLB_TYPE_SUP_MASK UINT64_C(0x0040000000000000) +/** Bits 60:55 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_55_60_SHIFT 55 +#define IOMMU_EXT_FEAT_BF_RSVD_55_60_MASK UINT64_C(0x1f80000000000000) +/** GAUpdateDisSup: Support disabling hardware update on guest page table access + * (RO). */ +#define IOMMU_EXT_FEAT_BF_GA_UPDATE_DIS_SUP_SHIFT 61 +#define IOMMU_EXT_FEAT_BF_GA_UPDATE_DIS_SUP_MASK UINT64_C(0x2000000000000000) +/** ForcePhysDestSup: Force Physical Destination Mode for Remapped Interrupt + * support (RO). */ +#define IOMMU_EXT_FEAT_BF_FORCE_PHYS_DST_SUP_SHIFT 62 +#define IOMMU_EXT_FEAT_BF_FORCE_PHYS_DST_SUP_MASK UINT64_C(0x4000000000000000) +/** Bit 63 reserved. */ +#define IOMMU_EXT_FEAT_BF_RSVD_63_SHIFT 63 +#define IOMMU_EXT_FEAT_BF_RSVD_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_EXT_FEAT_BF_, UINT64_C(0), UINT64_MAX, + (PREF_SUP, PPR_SUP, X2APIC_SUP, NO_EXEC_SUP, GT_SUP, RSVD_5, IA_SUP, GA_SUP, HE_SUP, PC_SUP, + HATS, GATS, GLX_SUP, SMI_FLT_SUP, SMI_FLT_REG_CNT, GAM_SUP, DUAL_PPR_LOG_SUP, RSVD_26_27, + DUAL_EVT_LOG_SUP, RSVD_30_31, PASID_MAX, US_SUP, DEV_TBL_SEG_SUP, PPR_OVERFLOW_EARLY, + PPR_AUTO_RES_SUP, MARC_SUP, BLKSTOP_MARK_SUP, PERF_OPT_SUP, MSI_CAP_MMIO_SUP, RSVD_47, + GST_IO_PROT_SUP, HST_ACCESS_SUP, ENHANCED_PPR_SUP, ATTR_FW_SUP, HST_DIRTY_SUP, RSVD_53, + INV_IOTLB_TYPE_SUP, RSVD_55_60, GA_UPDATE_DIS_SUP, FORCE_PHYS_DST_SUP, RSVD_63)); +/** @} */ + +/** + * IVHD (I/O Virtualization Hardware Definition) Type 10h. + * In accordance with the AMD spec. + */ +#pragma pack(1) +typedef struct ACPIIVHDTYPE10 +{ + uint8_t u8Type; /**< Type: Must be 0x10. */ + uint8_t u8Flags; /**< Flags (see ACPI_IVHD_10H_F_XXX). */ + uint16_t u16Length; /**< Length of IVHD including IVHD device entries. */ + uint16_t u16DeviceId; /**< Device ID of the IOMMU. */ + uint16_t u16CapOffset; /**< Offset in Capability space for control fields of IOMMU. */ + uint64_t u64BaseAddress; /**< Base address of IOMMU control registers in MMIO space. */ + uint16_t u16PciSegmentGroup; /**< PCI segment group number. */ + uint16_t u16IommuInfo; /**< Interrupt number and Unit ID. */ + uint32_t u32Features; /**< IOMMU feature reporting. */ + /* IVHD device entry block follows. */ +} ACPIIVHDTYPE10; +#pragma pack() +AssertCompileSize(ACPIIVHDTYPE10, 24); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u8Type, 0); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u8Flags, 1); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u16Length, 2); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u16DeviceId, 4); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u16CapOffset, 6); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u64BaseAddress, 8); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u16PciSegmentGroup, 16); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u16IommuInfo, 18); +AssertCompileMemberOffset(ACPIIVHDTYPE10, u32Features, 20); + +/** @name IVHD Type 11h Flags. + * In accordance with the AMD spec. + * @{ */ +/** Coherent control. */ +#define ACPI_IVHD_11H_F_COHERENT RT_BIT(5) +/** Remote IOTLB support. */ +#define ACPI_IVHD_11H_F_IOTLB_SUP RT_BIT(4) +/** Isochronous control. */ +#define ACPI_IVHD_11H_F_ISOC RT_BIT(3) +/** Response Pass Posted Write. */ +#define ACPI_IVHD_11H_F_RES_PASS_PW RT_BIT(2) +/** Pass Posted Write. */ +#define ACPI_IVHD_11H_F_PASS_PW RT_BIT(1) +/** HyperTransport Tunnel. */ +#define ACPI_IVHD_11H_F_HT_TUNNEL RT_BIT(0) +/** @} */ + +/** @name IVHD IOMMU Type 11 Attributes field. + * In accordance with the AMD spec. + * @{ */ +/** Bits 12:0 reserved. */ +#define ACPI_IOMMU_ATTR_BF_RSVD_0_12_SHIFT 0 +#define ACPI_IOMMU_ATTR_BF_RSVD_0_12_MASK UINT32_C(0x00001fff) +/** PNCounters: Number of performance counters per counter bank. */ +#define ACPI_IOMMU_ATTR_BF_PN_COUNTERS_SHIFT 13 +#define ACPI_IOMMU_ATTR_BF_PN_COUNTERS_MASK UINT32_C(0x0001e000) +/** PNBanks: Number of performance counter banks. */ +#define ACPI_IOMMU_ATTR_BF_PN_BANKS_SHIFT 17 +#define ACPI_IOMMU_ATTR_BF_PN_BANKS_MASK UINT32_C(0x007e0000) +/** MSINumPPR: MSI number for peripheral page requests (PPR). */ +#define ACPI_IOMMU_ATTR_BF_MSI_NUM_PPR_SHIFT 23 +#define ACPI_IOMMU_ATTR_BF_MSI_NUM_PPR_MASK UINT32_C(0x0f800000) +/** Bits 31:28 reserved. */ +#define ACPI_IOMMU_ATTR_BF_RSVD_28_31_SHIFT 28 +#define ACPI_IOMMU_ATTR_BF_RSVD_28_31_MASK UINT32_C(0xf0000000) +RT_BF_ASSERT_COMPILE_CHECKS(ACPI_IOMMU_ATTR_BF_, UINT32_C(0), UINT32_MAX, + (RSVD_0_12, PN_COUNTERS, PN_BANKS, MSI_NUM_PPR, RSVD_28_31)); +/** @} */ + +/** + * AMD IOMMU: IVHD (I/O Virtualization Hardware Definition) Type 11h. + * In accordance with the AMD spec. + */ +#pragma pack(1) +typedef struct ACPIIVHDTYPE11 +{ + uint8_t u8Type; /**< Type: Must be 0x11. */ + uint8_t u8Flags; /**< Flags. */ + uint16_t u16Length; /**< Length: Size starting from Type fields incl. IVHD device entries. */ + uint16_t u16DeviceId; /**< Device ID of the IOMMU. */ + uint16_t u16CapOffset; /**< Offset in Capability space for control fields of IOMMU. */ + uint64_t u64BaseAddress; /**< Base address of IOMMU control registers in MMIO space. */ + uint16_t u16PciSegmentGroup; /**< PCI segment group number. */ + uint16_t u16IommuInfo; /**< Interrupt number and unit ID. */ + uint32_t u32IommuAttr; /**< IOMMU info. not reported in EFR. */ + uint64_t u64EfrRegister; /**< Extended Feature Register (must be identical to its MMIO shadow). */ + uint64_t u64Rsvd0; /**< Reserved for future. */ + /* IVHD device entry block follows. */ +} ACPIIVHDTYPE11; +#pragma pack() +AssertCompileSize(ACPIIVHDTYPE11, 40); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u8Type, 0); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u8Flags, 1); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u16Length, 2); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u16DeviceId, 4); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u16CapOffset, 6); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u64BaseAddress, 8); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u16PciSegmentGroup, 16); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u16IommuInfo, 18); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u32IommuAttr, 20); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u64EfrRegister, 24); +AssertCompileMemberOffset(ACPIIVHDTYPE11, u64Rsvd0, 32); + +/** + * AMD IOMMU: IVHD (I/O Virtualization Hardware Definition) Type 40h. + * In accordance with the AMD spec. + */ +typedef struct ACPIIVHDTYPE11 ACPIIVHDTYPE40; + +#endif /* !VBOX_INCLUDED_iommu_amd_h */ diff --git a/include/VBox/iommu-intel.h b/include/VBox/iommu-intel.h new file mode 100644 index 00000000..cbf2121c --- /dev/null +++ b/include/VBox/iommu-intel.h @@ -0,0 +1,2915 @@ +/** @file + * IOMMU - Input/Output Memory Management Unit (Intel). + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_iommu_intel_h +#define VBOX_INCLUDED_iommu_intel_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** + * @name MMIO register offsets. + * In accordance with the Intel spec. + * @{ + */ +#define VTD_MMIO_OFF_VER_REG 0x000 /**< Version. */ +#define VTD_MMIO_OFF_CAP_REG 0x008 /**< Capability. */ +#define VTD_MMIO_OFF_ECAP_REG 0x010 /**< Extended Capability. */ +#define VTD_MMIO_OFF_GCMD_REG 0x018 /**< Global Command. */ +#define VTD_MMIO_OFF_GSTS_REG 0x01c /**< Global Status. */ +#define VTD_MMIO_OFF_RTADDR_REG 0x020 /**< Root Table Address. */ +#define VTD_MMIO_OFF_CCMD_REG 0x028 /**< Context Command. */ + +#define VTD_MMIO_OFF_FSTS_REG 0x034 /**< Fault Status.*/ +#define VTD_MMIO_OFF_FECTL_REG 0x038 /**< Fault Event Control.*/ +#define VTD_MMIO_OFF_FEDATA_REG 0x03c /**< Fault Event Data. */ +#define VTD_MMIO_OFF_FEADDR_REG 0x040 /**< Fault Event Address. */ +#define VTD_MMIO_OFF_FEUADDR_REG 0x044 /**< Fault Event Upper Address. */ + +#define VTD_MMIO_OFF_AFLOG_REG 0x058 /**< Advance Fault Log. */ + +#define VTD_MMIO_OFF_PMEN_REG 0x064 /**< Protected Memory Enable (PMEN). */ +#define VTD_MMIO_OFF_PLMBASE_REG 0x068 /**< Protected Low Memory Base. */ +#define VTD_MMIO_OFF_PLMLIMIT_REG 0x06c /**< Protected Low Memory Limit. */ +#define VTD_MMIO_OFF_PHMBASE_REG 0x070 /**< Protected High Memory Base. */ +#define VTD_MMIO_OFF_PHMLIMIT_REG 0x078 /**< Protected High Memory Limit. */ + +#define VTD_MMIO_OFF_IQH_REG 0x080 /**< Invalidation Queue Head. */ +#define VTD_MMIO_OFF_IQT_REG 0x088 /**< Invalidation Queue Tail. */ +#define VTD_MMIO_OFF_IQA_REG 0x090 /**< Invalidation Queue Address. */ +#define VTD_MMIO_OFF_ICS_REG 0x09c /**< Invalidation Completion Status. */ +#define VTD_MMIO_OFF_IECTL_REG 0x0a0 /**< Invalidation Completion Event Control. */ +#define VTD_MMIO_OFF_IEDATA_REG 0x0a4 /**< Invalidation Completion Event Data. */ +#define VTD_MMIO_OFF_IEADDR_REG 0x0a8 /**< Invalidation Completion Event Address. */ +#define VTD_MMIO_OFF_IEUADDR_REG 0x0ac /**< Invalidation Completion Event Upper Address. */ +#define VTD_MMIO_OFF_IQERCD_REG 0x0b0 /**< Invalidation Queue Error Record. */ + +#define VTD_MMIO_OFF_IRTA_REG 0x0b8 /**< Interrupt Remapping Table Address. */ + +#define VTD_MMIO_OFF_PQH_REG 0x0c0 /**< Page Request Queue Head. */ +#define VTD_MMIO_OFF_PQT_REG 0x0c8 /**< Page Request Queue Tail. */ +#define VTD_MMIO_OFF_PQA_REG 0x0d0 /**< Page Request Queue Address. */ +#define VTD_MMIO_OFF_PRS_REG 0x0dc /**< Page Request Status. */ +#define VTD_MMIO_OFF_PECTL_REG 0x0e0 /**< Page Request Event Control. */ +#define VTD_MMIO_OFF_PEDATA_REG 0x0e4 /**< Page Request Event Data. */ +#define VTD_MMIO_OFF_PEADDR_REG 0x0e8 /**< Page Request Event Address. */ +#define VTD_MMIO_OFF_PEUADDR_REG 0x0ec /**< Page Request Event Upper Address. */ + +#define VTD_MMIO_OFF_MTRRCAP_REG 0x100 /**< MTRR Capabliity. */ +#define VTD_MMIO_OFF_MTRRDEF_REG 0x108 /**< MTRR Default Type. */ + +#define VTD_MMIO_OFF_MTRR_FIX64_00000_REG 0x120 /**< Fixed-range MTRR Register for 64K at 00000. */ +#define VTD_MMIO_OFF_MTRR_FIX16K_80000_REG 0x128 /**< Fixed-range MTRR Register for 16K at 80000. */ +#define VTD_MMIO_OFF_MTRR_FIX16K_A0000_REG 0x130 /**< Fixed-range MTRR Register for 16K at a0000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_C0000_REG 0x138 /**< Fixed-range MTRR Register for 4K at c0000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_C8000_REG 0x140 /**< Fixed-range MTRR Register for 4K at c8000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_D0000_REG 0x148 /**< Fixed-range MTRR Register for 4K at d0000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_D8000_REG 0x150 /**< Fixed-range MTRR Register for 4K at d8000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_E0000_REG 0x158 /**< Fixed-range MTRR Register for 4K at e0000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_E8000_REG 0x160 /**< Fixed-range MTRR Register for 4K at e8000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_F0000_REG 0x168 /**< Fixed-range MTRR Register for 4K at f0000. */ +#define VTD_MMIO_OFF_MTRR_FIX4K_F8000_REG 0x170 /**< Fixed-range MTRR Register for 4K at f8000. */ + +#define VTD_MMIO_OFF_MTRR_PHYSBASE0_REG 0x180 /**< Variable-range MTRR Base 0. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK0_REG 0x188 /**< Variable-range MTRR Mask 0. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE1_REG 0x190 /**< Variable-range MTRR Base 1. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK1_REG 0x198 /**< Variable-range MTRR Mask 1. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE2_REG 0x1a0 /**< Variable-range MTRR Base 2. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK2_REG 0x1a8 /**< Variable-range MTRR Mask 2. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE3_REG 0x1b0 /**< Variable-range MTRR Base 3. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK3_REG 0x1b8 /**< Variable-range MTRR Mask 3. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE4_REG 0x1c0 /**< Variable-range MTRR Base 4. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK4_REG 0x1c8 /**< Variable-range MTRR Mask 4. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE5_REG 0x1d0 /**< Variable-range MTRR Base 5. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK5_REG 0x1d8 /**< Variable-range MTRR Mask 5. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE6_REG 0x1e0 /**< Variable-range MTRR Base 6. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK6_REG 0x1e8 /**< Variable-range MTRR Mask 6. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE7_REG 0x1f0 /**< Variable-range MTRR Base 7. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK7_REG 0x1f8 /**< Variable-range MTRR Mask 7. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE8_REG 0x200 /**< Variable-range MTRR Base 8. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK8_REG 0x208 /**< Variable-range MTRR Mask 8. */ +#define VTD_MMIO_OFF_MTRR_PHYSBASE9_REG 0x210 /**< Variable-range MTRR Base 9. */ +#define VTD_MMIO_OFF_MTRR_PHYSMASK9_REG 0x218 /**< Variable-range MTRR Mask 9. */ + +#define VTD_MMIO_OFF_VCCAP_REG 0xe00 /**< Virtual Command Capability. */ +#define VTD_MMIO_OFF_VCMD_REG 0xe10 /**< Virtual Command. */ +#define VTD_MMIO_OFF_VCMDRSVD_REG 0xe18 /**< Reserved for future for Virtual Command. */ +#define VTD_MMIO_OFF_VCRSP_REG 0xe20 /**< Virtual Command Response. */ +#define VTD_MMIO_OFF_VCRSPRSVD_REG 0xe28 /**< Reserved for future for Virtual Command Response. */ +/** @} */ + + +/** @name Root Entry. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_0_ROOT_ENTRY_P_SHIFT 0 +#define VTD_BF_0_ROOT_ENTRY_P_MASK UINT64_C(0x0000000000000001) +/** R: Reserved (bits 11:1). */ +#define VTD_BF_0_ROOT_ENTRY_RSVD_11_1_SHIFT 1 +#define VTD_BF_0_ROOT_ENTRY_RSVD_11_1_MASK UINT64_C(0x0000000000000ffe) +/** CTP: Context-Table Pointer. */ +#define VTD_BF_0_ROOT_ENTRY_CTP_SHIFT 12 +#define VTD_BF_0_ROOT_ENTRY_CTP_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_ROOT_ENTRY_, UINT64_C(0), UINT64_MAX, + (P, RSVD_11_1, CTP)); + +/** Root Entry. */ +typedef struct VTD_ROOT_ENTRY_T +{ + /** The qwords in the root entry. */ + uint64_t au64[2]; +} VTD_ROOT_ENTRY_T; +/** Pointer to a root entry. */ +typedef VTD_ROOT_ENTRY_T *PVTD_ROOT_ENTRY_T; +/** Pointer to a const root entry. */ +typedef VTD_ROOT_ENTRY_T const *PCVTD_ROOT_ENTRY_T; + +/* Root Entry: Qword 0 valid mask. */ +#define VTD_ROOT_ENTRY_0_VALID_MASK (VTD_BF_0_ROOT_ENTRY_P_MASK | VTD_BF_0_ROOT_ENTRY_CTP_MASK) +/* Root Entry: Qword 1 valid mask. */ +#define VTD_ROOT_ENTRY_1_VALID_MASK UINT64_C(0) +/** @} */ + + +/** @name Scalable-mode Root Entry. + * In accordance with the Intel spec. + * @{ */ +/** LP: Lower Present. */ +#define VTD_BF_0_SM_ROOT_ENTRY_LP_SHIFT 0 +#define VTD_BF_0_SM_ROOT_ENTRY_LP_MASK UINT64_C(0x0000000000000001) +/** R: Reserved (bits 11:1). */ +#define VTD_BF_0_SM_ROOT_ENTRY_RSVD_11_1_SHIFT 1 +#define VTD_BF_0_SM_ROOT_ENTRY_RSVD_11_1_MASK UINT64_C(0x0000000000000ffe) +/** LCTP: Lower Context-Table Pointer */ +#define VTD_BF_0_SM_ROOT_ENTRY_LCTP_SHIFT 12 +#define VTD_BF_0_SM_ROOT_ENTRY_LCTP_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_SM_ROOT_ENTRY_, UINT64_C(0), UINT64_MAX, + (LP, RSVD_11_1, LCTP)); + +/** UP: Upper Present. */ +#define VTD_BF_1_SM_ROOT_ENTRY_UP_SHIFT 0 +#define VTD_BF_1_SM_ROOT_ENTRY_UP_MASK UINT64_C(0x0000000000000001) +/** R: Reserved (bits 11:1). */ +#define VTD_BF_1_SM_ROOT_ENTRY_RSVD_11_1_SHIFT 1 +#define VTD_BF_1_SM_ROOT_ENTRY_RSVD_11_1_MASK UINT64_C(0x0000000000000ffe) +/** UCTP: Upper Context-Table Pointer. */ +#define VTD_BF_1_SM_ROOT_ENTRY_UCTP_SHIFT 12 +#define VTD_BF_1_SM_ROOT_ENTRY_UCTP_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_SM_ROOT_ENTRY_, UINT64_C(0), UINT64_MAX, + (UP, RSVD_11_1, UCTP)); + +/** Scalable-mode root entry. */ +typedef struct VTD_SM_ROOT_ENTRY_T +{ + /** The lower scalable-mode root entry. */ + uint64_t uLower; + /** The upper scalable-mode root entry. */ + uint64_t uUpper; +} VTD_SM_ROOT_ENTRY_T; +/** Pointer to a scalable-mode root entry. */ +typedef VTD_SM_ROOT_ENTRY_T *PVTD_SM_ROOT_ENTRY_T; +/** Pointer to a const scalable-mode root entry. */ +typedef VTD_SM_ROOT_ENTRY_T const *PCVTD_SM_ROOT_ENTRY_T; +/** @} */ + + +/** @name Context Entry. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_0_CONTEXT_ENTRY_P_SHIFT 0 +#define VTD_BF_0_CONTEXT_ENTRY_P_MASK UINT64_C(0x0000000000000001) +/** FPD: Fault Processing Disable. */ +#define VTD_BF_0_CONTEXT_ENTRY_FPD_SHIFT 1 +#define VTD_BF_0_CONTEXT_ENTRY_FPD_MASK UINT64_C(0x0000000000000002) +/** TT: Translation Type. */ +#define VTD_BF_0_CONTEXT_ENTRY_TT_SHIFT 2 +#define VTD_BF_0_CONTEXT_ENTRY_TT_MASK UINT64_C(0x000000000000000c) +/** R: Reserved (bits 11:4). */ +#define VTD_BF_0_CONTEXT_ENTRY_RSVD_11_4_SHIFT 4 +#define VTD_BF_0_CONTEXT_ENTRY_RSVD_11_4_MASK UINT64_C(0x0000000000000ff0) +/** SLPTPTR: Second Level Page Translation Pointer. */ +#define VTD_BF_0_CONTEXT_ENTRY_SLPTPTR_SHIFT 12 +#define VTD_BF_0_CONTEXT_ENTRY_SLPTPTR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_CONTEXT_ENTRY_, UINT64_C(0), UINT64_MAX, + (P, FPD, TT, RSVD_11_4, SLPTPTR)); + +/** AW: Address Width. */ +#define VTD_BF_1_CONTEXT_ENTRY_AW_SHIFT 0 +#define VTD_BF_1_CONTEXT_ENTRY_AW_MASK UINT64_C(0x0000000000000007) +/** IGN: Ignored (bits 6:3). */ +#define VTD_BF_1_CONTEXT_ENTRY_IGN_6_3_SHIFT 3 +#define VTD_BF_1_CONTEXT_ENTRY_IGN_6_3_MASK UINT64_C(0x0000000000000078) +/** R: Reserved (bit 7). */ +#define VTD_BF_1_CONTEXT_ENTRY_RSVD_7_SHIFT 7 +#define VTD_BF_1_CONTEXT_ENTRY_RSVD_7_MASK UINT64_C(0x0000000000000080) +/** DID: Domain Identifier. */ +#define VTD_BF_1_CONTEXT_ENTRY_DID_SHIFT 8 +#define VTD_BF_1_CONTEXT_ENTRY_DID_MASK UINT64_C(0x0000000000ffff00) +/** R: Reserved (bits 63:24). */ +#define VTD_BF_1_CONTEXT_ENTRY_RSVD_63_24_SHIFT 24 +#define VTD_BF_1_CONTEXT_ENTRY_RSVD_63_24_MASK UINT64_C(0xffffffffff000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_CONTEXT_ENTRY_, UINT64_C(0), UINT64_MAX, + (AW, IGN_6_3, RSVD_7, DID, RSVD_63_24)); + +/** Context Entry. */ +typedef struct VTD_CONTEXT_ENTRY_T +{ + /** The qwords in the context entry. */ + uint64_t au64[2]; +} VTD_CONTEXT_ENTRY_T; +/** Pointer to a context entry. */ +typedef VTD_CONTEXT_ENTRY_T *PVTD_CONTEXT_ENTRY_T; +/** Pointer to a const context entry. */ +typedef VTD_CONTEXT_ENTRY_T const *PCVTD_CONTEXT_ENTRY_T; +AssertCompileSize(VTD_CONTEXT_ENTRY_T, 16); + +/** Context Entry: Qword 0 valid mask. */ +#define VTD_CONTEXT_ENTRY_0_VALID_MASK ( VTD_BF_0_CONTEXT_ENTRY_P_MASK \ + | VTD_BF_0_CONTEXT_ENTRY_FPD_MASK \ + | VTD_BF_0_CONTEXT_ENTRY_TT_MASK \ + | VTD_BF_0_CONTEXT_ENTRY_SLPTPTR_MASK) +/** Context Entry: Qword 1 valid mask. */ +#define VTD_CONTEXT_ENTRY_1_VALID_MASK ( VTD_BF_1_CONTEXT_ENTRY_AW_MASK \ + | VTD_BF_1_CONTEXT_ENTRY_IGN_6_3_MASK \ + | VTD_BF_1_CONTEXT_ENTRY_DID_MASK) + +/** Translation Type: Untranslated requests uses second-level paging. */ +#define VTD_TT_UNTRANSLATED_SLP 0 +/** Translation Type: Untranslated requests requires device-TLB support. */ +#define VTD_TT_UNTRANSLATED_DEV_TLB 1 +/** Translation Type: Untranslated requests are pass-through. */ +#define VTD_TT_UNTRANSLATED_PT 2 +/** Translation Type: Reserved. */ +#define VTD_TT_RSVD 3 +/** @} */ + + +/** @name Scalable-mode Context Entry. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_P_SHIFT 0 +#define VTD_BF_0_SM_CONTEXT_ENTRY_P_MASK UINT64_C(0x0000000000000001) +/** FPD: Fault Processing Disable. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_FPD_SHIFT 1 +#define VTD_BF_0_SM_CONTEXT_ENTRY_FPD_MASK UINT64_C(0x0000000000000002) +/** DTE: Device-TLB Enable. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_DTE_SHIFT 2 +#define VTD_BF_0_SM_CONTEXT_ENTRY_DTE_MASK UINT64_C(0x0000000000000004) +/** PASIDE: PASID Enable. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_PASIDE_SHIFT 3 +#define VTD_BF_0_SM_CONTEXT_ENTRY_PASIDE_MASK UINT64_C(0x0000000000000008) +/** PRE: Page Request Enable. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_PRE_SHIFT 4 +#define VTD_BF_0_SM_CONTEXT_ENTRY_PRE_MASK UINT64_C(0x0000000000000010) +/** R: Reserved (bits 8:5). */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_RSVD_8_5_SHIFT 5 +#define VTD_BF_0_SM_CONTEXT_ENTRY_RSVD_8_5_MASK UINT64_C(0x00000000000001e0) +/** PDTS: PASID Directory Size. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_PDTS_SHIFT 9 +#define VTD_BF_0_SM_CONTEXT_ENTRY_PDTS_MASK UINT64_C(0x0000000000000e00) +/** PASIDDIRPTR: PASID Directory Pointer. */ +#define VTD_BF_0_SM_CONTEXT_ENTRY_PASIDDIRPTR_SHIFT 12 +#define VTD_BF_0_SM_CONTEXT_ENTRY_PASIDDIRPTR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_SM_CONTEXT_ENTRY_, UINT64_C(0), UINT64_MAX, + (P, FPD, DTE, PASIDE, PRE, RSVD_8_5, PDTS, PASIDDIRPTR)); + +/** RID_PASID: Requested Id to PASID assignment. */ +#define VTD_BF_1_SM_CONTEXT_ENTRY_RID_PASID_SHIFT 0 +#define VTD_BF_1_SM_CONTEXT_ENTRY_RID_PASID_MASK UINT64_C(0x00000000000fffff) +/** RID_PRIV: Requested Id to PrivilegeModeRequested assignment. */ +#define VTD_BF_1_SM_CONTEXT_ENTRY_RID_PRIV_SHIFT 20 +#define VTD_BF_1_SM_CONTEXT_ENTRY_RID_PRIV_MASK UINT64_C(0x0000000000100000) +/** R: Reserved (bits 63:21). */ +#define VTD_BF_1_SM_CONTEXT_ENTRY_RSVD_63_21_SHIFT 21 +#define VTD_BF_1_SM_CONTEXT_ENTRY_RSVD_63_21_MASK UINT64_C(0xffffffffffe00000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_SM_CONTEXT_ENTRY_, UINT64_C(0), UINT64_MAX, + (RID_PASID, RID_PRIV, RSVD_63_21)); + +/** Scalable-mode Context Entry. */ +typedef struct VTD_SM_CONTEXT_ENTRY_T +{ + /** The qwords in the scalable-mode context entry. */ + uint64_t au64[4]; +} VTD_SM_CONTEXT_ENTRY_T; +/** Pointer to a scalable-mode context entry. */ +typedef VTD_SM_CONTEXT_ENTRY_T *PVTD_SM_CONTEXT_ENTRY_T; +/** Pointer to a const scalable-mode context entry. */ +typedef VTD_SM_CONTEXT_ENTRY_T const *PCVTD_SM_CONTEXT_ENTRY_T; +/** @} */ + + +/** @name Scalable-mode PASID Directory Entry. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_SM_PASID_DIR_ENTRY_P_SHIFT 0 +#define VTD_BF_SM_PASID_DIR_ENTRY_P_MASK UINT64_C(0x0000000000000001) +/** FPD: Fault Processing Disable. */ +#define VTD_BF_SM_PASID_DIR_ENTRY_FPD_SHIFT 1 +#define VTD_BF_SM_PASID_DIR_ENTRY_FPD_MASK UINT64_C(0x0000000000000002) +/** R: Reserved (bits 11:2). */ +#define VTD_BF_SM_PASID_DIR_ENTRY_RSVD_11_2_SHIFT 2 +#define VTD_BF_SM_PASID_DIR_ENTRY_RSVD_11_2_MASK UINT64_C(0x0000000000000ffc) +/** SMPTBLPTR: Scalable Mode PASID Table Pointer. */ +#define VTD_BF_SM_PASID_DIR_ENTRY_SMPTBLPTR_SHIFT 12 +#define VTD_BF_SM_PASID_DIR_ENTRY_SMPTBLPTR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SM_PASID_DIR_ENTRY_, UINT64_C(0), UINT64_MAX, + (P, FPD, RSVD_11_2, SMPTBLPTR)); + +/** Scalable-mode PASID Directory Entry. */ +typedef struct VTD_SM_PASID_DIR_ENTRY_T +{ + /** The scalable-mode PASID directory entry. */ + uint64_t u; +} VTD_SM_PASID_DIR_ENTRY_T; +/** Pointer to a scalable-mode PASID directory entry. */ +typedef VTD_SM_PASID_DIR_ENTRY_T *PVTD_SM_PASID_DIR_ENTRY_T; +/** Pointer to a const scalable-mode PASID directory entry. */ +typedef VTD_SM_PASID_DIR_ENTRY_T const *PCVTD_SM_PASID_DIR_ENTRY_T; +/** @} */ + + +/** @name Scalable-mode PASID Table Entry. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_P_SHIFT 0 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_P_MASK UINT64_C(0x0000000000000001) +/** FPD: Fault Processing Disable. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_FPD_SHIFT 1 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_FPD_MASK UINT64_C(0x0000000000000002) +/** AW: Address Width. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_AW_SHIFT 2 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_AW_MASK UINT64_C(0x000000000000001c) +/** SLEE: Second-Level Execute Enable. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_SLEE_SHIFT 5 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_SLEE_MASK UINT64_C(0x0000000000000020) +/** PGTT: PASID Granular Translation Type. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_PGTT_SHIFT 6 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_PGTT_MASK UINT64_C(0x00000000000001c0) +/** SLADE: Second-Level Address/Dirty Enable. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_SLADE_SHIFT 9 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_SLADE_MASK UINT64_C(0x0000000000000200) +/** R: Reserved (bits 11:10). */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_RSVD_11_10_SHIFT 10 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_RSVD_11_10_MASK UINT64_C(0x0000000000000c00) +/** SLPTPTR: Second-Level Page Table Pointer. */ +#define VTD_BF_0_SM_PASID_TBL_ENTRY_SLPTPTR_SHIFT 12 +#define VTD_BF_0_SM_PASID_TBL_ENTRY_SLPTPTR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_SM_PASID_TBL_ENTRY_, UINT64_C(0), UINT64_MAX, + (P, FPD, AW, SLEE, PGTT, SLADE, RSVD_11_10, SLPTPTR)); + +/** DID: Domain Identifer. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_DID_SHIFT 0 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_DID_MASK UINT64_C(0x000000000000ffff) +/** R: Reserved (bits 22:16). */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_RSVD_22_16_SHIFT 16 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_RSVD_22_16_MASK UINT64_C(0x00000000007f0000) +/** PWSNP: Page-Walk Snoop. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PWSNP_SHIFT 23 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PWSNP_MASK UINT64_C(0x0000000000800000) +/** PGSNP: Page Snoop. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PGSNP_SHIFT 24 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PGSNP_MASK UINT64_C(0x0000000001000000) +/** CD: Cache Disable. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_CD_SHIFT 25 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_CD_MASK UINT64_C(0x0000000002000000) +/** EMTE: Extended Memory Type Enable. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_EMTE_SHIFT 26 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_EMTE_MASK UINT64_C(0x0000000004000000) +/** EMT: Extended Memory Type. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_EMT_SHIFT 27 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_EMT_MASK UINT64_C(0x0000000038000000) +/** PWT: Page-Level Write Through. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PWT_SHIFT 30 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PWT_MASK UINT64_C(0x0000000040000000) +/** PCD: Page-Level Cache Disable. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PCD_SHIFT 31 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PCD_MASK UINT64_C(0x0000000080000000) +/** PAT: Page Attribute Table. */ +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PAT_SHIFT 32 +#define VTD_BF_1_SM_PASID_TBL_ENTRY_PAT_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_SM_PASID_TBL_ENTRY_, UINT64_C(0), UINT64_MAX, + (DID, RSVD_22_16, PWSNP, PGSNP, CD, EMTE, EMT, PWT, PCD, PAT)); + +/** SRE: Supervisor Request Enable. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_SRE_SHIFT 0 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_SRE_MASK UINT64_C(0x0000000000000001) +/** ERE: Execute Request Enable. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_ERE_SHIFT 1 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_ERE_MASK UINT64_C(0x0000000000000002) +/** FLPM: First Level Paging Mode. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_FLPM_SHIFT 2 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_FLPM_MASK UINT64_C(0x000000000000000c) +/** WPE: Write Protect Enable. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_WPE_SHIFT 4 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_WPE_MASK UINT64_C(0x0000000000000010) +/** NXE: No-Execute Enable. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_NXE_SHIFT 5 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_NXE_MASK UINT64_C(0x0000000000000020) +/** SMEP: Supervisor Mode Execute Prevent. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_SMPE_SHIFT 6 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_SMPE_MASK UINT64_C(0x0000000000000040) +/** EAFE: Extended Accessed Flag Enable. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_EAFE_SHIFT 7 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_EAFE_MASK UINT64_C(0x0000000000000080) +/** R: Reserved (bits 11:8). */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_RSVD_11_8_SHIFT 8 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_RSVD_11_8_MASK UINT64_C(0x0000000000000f00) +/** FLPTPTR: First Level Page Table Pointer. */ +#define VTD_BF_2_SM_PASID_TBL_ENTRY_FLPTPTR_SHIFT 12 +#define VTD_BF_2_SM_PASID_TBL_ENTRY_FLPTPTR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_2_SM_PASID_TBL_ENTRY_, UINT64_C(0), UINT64_MAX, + (SRE, ERE, FLPM, WPE, NXE, SMPE, EAFE, RSVD_11_8, FLPTPTR)); + +/** Scalable-mode PASID Table Entry. */ +typedef struct VTD_SM_PASID_TBL_ENTRY_T +{ + /** The qwords in the scalable-mode PASID table entry. */ + uint64_t au64[8]; +} VTD_SM_PASID_TBL_ENTRY_T; +/** Pointer to a scalable-mode PASID table entry. */ +typedef VTD_SM_PASID_TBL_ENTRY_T *PVTD_SM_PASID_TBL_ENTRY_T; +/** Pointer to a const scalable-mode PASID table entry. */ +typedef VTD_SM_PASID_TBL_ENTRY_T const *PCVTD_SM_PASID_TBL_ENTRY_T; +/** @} */ + + +/** @name First-Level Paging Entry. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_FLP_ENTRY_P_SHIFT 0 +#define VTD_BF_FLP_ENTRY_P_MASK UINT64_C(0x0000000000000001) +/** R/W: Read/Write. */ +#define VTD_BF_FLP_ENTRY_RW_SHIFT 1 +#define VTD_BF_FLP_ENTRY_RW_MASK UINT64_C(0x0000000000000002) +/** U/S: User/Supervisor. */ +#define VTD_BF_FLP_ENTRY_US_SHIFT 2 +#define VTD_BF_FLP_ENTRY_US_MASK UINT64_C(0x0000000000000004) +/** PWT: Page-Level Write Through. */ +#define VTD_BF_FLP_ENTRY_PWT_SHIFT 3 +#define VTD_BF_FLP_ENTRY_PWT_MASK UINT64_C(0x0000000000000008) +/** PC: Page-Level Cache Disable. */ +#define VTD_BF_FLP_ENTRY_PCD_SHIFT 4 +#define VTD_BF_FLP_ENTRY_PCD_MASK UINT64_C(0x0000000000000010) +/** A: Accessed. */ +#define VTD_BF_FLP_ENTRY_A_SHIFT 5 +#define VTD_BF_FLP_ENTRY_A_MASK UINT64_C(0x0000000000000020) +/** IGN: Ignored (bit 6). */ +#define VTD_BF_FLP_ENTRY_IGN_6_SHIFT 6 +#define VTD_BF_FLP_ENTRY_IGN_6_MASK UINT64_C(0x0000000000000040) +/** R: Reserved (bit 7). */ +#define VTD_BF_FLP_ENTRY_RSVD_7_SHIFT 7 +#define VTD_BF_FLP_ENTRY_RSVD_7_MASK UINT64_C(0x0000000000000080) +/** IGN: Ignored (bits 9:8). */ +#define VTD_BF_FLP_ENTRY_IGN_9_8_SHIFT 8 +#define VTD_BF_FLP_ENTRY_IGN_9_8_MASK UINT64_C(0x0000000000000300) +/** EA: Extended Accessed. */ +#define VTD_BF_FLP_ENTRY_EA_SHIFT 10 +#define VTD_BF_FLP_ENTRY_EA_MASK UINT64_C(0x0000000000000400) +/** IGN: Ignored (bit 11). */ +#define VTD_BF_FLP_ENTRY_IGN_11_SHIFT 11 +#define VTD_BF_FLP_ENTRY_IGN_11_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address. */ +#define VTD_BF_FLP_ENTRY_ADDR_SHIFT 12 +#define VTD_BF_FLP_ENTRY_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** IGN: Ignored (bits 62:52). */ +#define VTD_BF_FLP_ENTRY_IGN_62_52_SHIFT 52 +#define VTD_BF_FLP_ENTRY_IGN_62_52_MASK UINT64_C(0x7ff0000000000000) +/** XD: Execute Disabled. */ +#define VTD_BF_FLP_ENTRY_XD_SHIFT 63 +#define VTD_BF_FLP_ENTRY_XD_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_FLP_ENTRY_, UINT64_C(0), UINT64_MAX, + (P, RW, US, PWT, PCD, A, IGN_6, RSVD_7, IGN_9_8, EA, IGN_11, ADDR, IGN_62_52, XD)); +/** @} */ + + +/** @name Second-Level PML5E. + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PML5E_R_SHIFT 0 +#define VTD_BF_SL_PML5E_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PML5E_W_SHIFT 1 +#define VTD_BF_SL_PML5E_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PML5E_X_SHIFT 2 +#define VTD_BF_SL_PML5E_X_MASK UINT64_C(0x0000000000000004) +/** IGN: Ignored (bits 6:3). */ +#define VTD_BF_SL_PML5E_IGN_6_3_SHIFT 3 +#define VTD_BF_SL_PML5E_IGN_6_3_MASK UINT64_C(0x0000000000000078) +/** R: Reserved (bit 7). */ +#define VTD_BF_SL_PML5E_RSVD_7_SHIFT 7 +#define VTD_BF_SL_PML5E_RSVD_7_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PML5E_A_SHIFT 8 +#define VTD_BF_SL_PML5E_A_MASK UINT64_C(0x0000000000000100) +/** IGN: Ignored (bits 10:9). */ +#define VTD_BF_SL_PML5E_IGN_10_9_SHIFT 9 +#define VTD_BF_SL_PML5E_IGN_10_9_MASK UINT64_C(0x0000000000000600) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PML5E_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PML5E_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address. */ +#define VTD_BF_SL_PML5E_ADDR_SHIFT 12 +#define VTD_BF_SL_PML5E_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PML5E_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PML5E_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PML5E_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PML5E_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PML5E_IGN_63_SHIFT 63 +#define VTD_BF_SL_PML5E_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PML5E_, UINT64_C(0), UINT64_MAX, + (R, W, X, IGN_6_3, RSVD_7, A, IGN_10_9, RSVD_11, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PML5E valid mask. */ +#define VTD_SL_PML5E_VALID_MASK ( VTD_BF_SL_PML5E_R_MASK | VTD_BF_SL_PML5E_W_MASK \ + | VTD_BF_SL_PML5E_X_MASK | VTD_BF_SL_PML5E_IGN_6_3_MASK \ + | VTD_BF_SL_PML5E_A_MASK | VTD_BF_SL_PML5E_IGN_10_9_MASK \ + | VTD_BF_SL_PML5E_ADDR_MASK | VTD_BF_SL_PML5E_IGN_61_52_MASK \ + | VTD_BF_SL_PML5E_IGN_63_MASK) +/** @} */ + + +/** @name Second-Level PML4E. + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PML4E_R_SHIFT 0 +#define VTD_BF_SL_PML4E_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PML4E_W_SHIFT 1 +#define VTD_BF_SL_PML4E_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PML4E_X_SHIFT 2 +#define VTD_BF_SL_PML4E_X_MASK UINT64_C(0x0000000000000004) +/** IGN: Ignored (bits 6:3). */ +#define VTD_BF_SL_PML4E_IGN_6_3_SHIFT 3 +#define VTD_BF_SL_PML4E_IGN_6_3_MASK UINT64_C(0x0000000000000078) +/** R: Reserved (bit 7). */ +#define VTD_BF_SL_PML4E_RSVD_7_SHIFT 7 +#define VTD_BF_SL_PML4E_RSVD_7_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PML4E_A_SHIFT 8 +#define VTD_BF_SL_PML4E_A_MASK UINT64_C(0x0000000000000100) +/** IGN: Ignored (bits 10:9). */ +#define VTD_BF_SL_PML4E_IGN_10_9_SHIFT 9 +#define VTD_BF_SL_PML4E_IGN_10_9_MASK UINT64_C(0x0000000000000600) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PML4E_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PML4E_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address. */ +#define VTD_BF_SL_PML4E_ADDR_SHIFT 12 +#define VTD_BF_SL_PML4E_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PML4E_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PML4E_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PML4E_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PML4E_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PML4E_IGN_63_SHIFT 63 +#define VTD_BF_SL_PML4E_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PML4E_, UINT64_C(0), UINT64_MAX, + (R, W, X, IGN_6_3, RSVD_7, A, IGN_10_9, RSVD_11, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PML4E valid mask. */ +#define VTD_SL_PML4E_VALID_MASK VTD_SL_PML5E_VALID_MASK +/** @} */ + + +/** @name Second-Level PDPE (1GB Page). + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PDPE1G_R_SHIFT 0 +#define VTD_BF_SL_PDPE1G_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PDPE1G_W_SHIFT 1 +#define VTD_BF_SL_PDPE1G_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PDPE1G_X_SHIFT 2 +#define VTD_BF_SL_PDPE1G_X_MASK UINT64_C(0x0000000000000004) +/** EMT: Extended Memory Type. */ +#define VTD_BF_SL_PDPE1G_EMT_SHIFT 3 +#define VTD_BF_SL_PDPE1G_EMT_MASK UINT64_C(0x0000000000000038) +/** IPAT: Ignore PAT (Page Attribute Table). */ +#define VTD_BF_SL_PDPE1G_IPAT_SHIFT 6 +#define VTD_BF_SL_PDPE1G_IPAT_MASK UINT64_C(0x0000000000000040) +/** PS: Page Size (MB1). */ +#define VTD_BF_SL_PDPE1G_PS_SHIFT 7 +#define VTD_BF_SL_PDPE1G_PS_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PDPE1G_A_SHIFT 8 +#define VTD_BF_SL_PDPE1G_A_MASK UINT64_C(0x0000000000000100) +/** D: Dirty. */ +#define VTD_BF_SL_PDPE1G_D_SHIFT 9 +#define VTD_BF_SL_PDPE1G_D_MASK UINT64_C(0x0000000000000200) +/** IGN: Ignored (bit 10). */ +#define VTD_BF_SL_PDPE1G_IGN_10_SHIFT 10 +#define VTD_BF_SL_PDPE1G_IGN_10_MASK UINT64_C(0x0000000000000400) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PDPE1G_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PDPE1G_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** R: Reserved (bits 29:12). */ +#define VTD_BF_SL_PDPE1G_RSVD_29_12_SHIFT 12 +#define VTD_BF_SL_PDPE1G_RSVD_29_12_MASK UINT64_C(0x000000003ffff000) +/** ADDR: Address of 1GB page. */ +#define VTD_BF_SL_PDPE1G_ADDR_SHIFT 30 +#define VTD_BF_SL_PDPE1G_ADDR_MASK UINT64_C(0x000fffffc0000000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PDPE1G_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PDPE1G_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PDPE1G_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PDPE1G_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PDPE1G_IGN_63_SHIFT 63 +#define VTD_BF_SL_PDPE1G_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PDPE1G_, UINT64_C(0), UINT64_MAX, + (R, W, X, EMT, IPAT, PS, A, D, IGN_10, RSVD_11, RSVD_29_12, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PDPE (1GB Page) valid mask. */ +#define VTD_SL_PDPE1G_VALID_MASK ( VTD_BF_SL_PDPE1G_R_MASK | VTD_BF_SL_PDPE1G_W_MASK \ + | VTD_BF_SL_PDPE1G_X_MASK | VTD_BF_SL_PDPE1G_EMT_MASK \ + | VTD_BF_SL_PDPE1G_IPAT_MASK | VTD_BF_SL_PDPE1G_PS_MASK \ + | VTD_BF_SL_PDPE1G_A_MASK | VTD_BF_SL_PDPE1G_D_MASK \ + | VTD_BF_SL_PDPE1G_IGN_10_MASK | VTD_BF_SL_PDPE1G_ADDR_MASK \ + | VTD_BF_SL_PDPE1G_IGN_61_52_MASK | VTD_BF_SL_PDPE1G_IGN_63_MASK) +/** @} */ + + +/** @name Second-Level PDPE. + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PDPE_R_SHIFT 0 +#define VTD_BF_SL_PDPE_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PDPE_W_SHIFT 1 +#define VTD_BF_SL_PDPE_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PDPE_X_SHIFT 2 +#define VTD_BF_SL_PDPE_X_MASK UINT64_C(0x0000000000000004) +/** IGN: Ignored (bits 6:3). */ +#define VTD_BF_SL_PDPE_IGN_6_3_SHIFT 3 +#define VTD_BF_SL_PDPE_IGN_6_3_MASK UINT64_C(0x0000000000000078) +/** PS: Page Size (MBZ). */ +#define VTD_BF_SL_PDPE_PS_SHIFT 7 +#define VTD_BF_SL_PDPE_PS_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PDPE_A_SHIFT 8 +#define VTD_BF_SL_PDPE_A_MASK UINT64_C(0x0000000000000100) +/** IGN: Ignored (bits 10:9). */ +#define VTD_BF_SL_PDPE_IGN_10_9_SHIFT 9 +#define VTD_BF_SL_PDPE_IGN_10_9_MASK UINT64_C(0x0000000000000600) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PDPE_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PDPE_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address of second-level PDT. */ +#define VTD_BF_SL_PDPE_ADDR_SHIFT 12 +#define VTD_BF_SL_PDPE_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PDPE_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PDPE_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PDPE_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PDPE_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PDPE_IGN_63_SHIFT 63 +#define VTD_BF_SL_PDPE_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PDPE_, UINT64_C(0), UINT64_MAX, + (R, W, X, IGN_6_3, PS, A, IGN_10_9, RSVD_11, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PDPE valid mask. */ +#define VTD_SL_PDPE_VALID_MASK ( VTD_BF_SL_PDPE_R_MASK | VTD_BF_SL_PDPE_W_MASK \ + | VTD_BF_SL_PDPE_X_MASK | VTD_BF_SL_PDPE_IGN_6_3_MASK \ + | VTD_BF_SL_PDPE_PS_MASK | VTD_BF_SL_PDPE_A_MASK \ + | VTD_BF_SL_PDPE_IGN_10_9_MASK | VTD_BF_SL_PDPE_ADDR_MASK \ + | VTD_BF_SL_PDPE_IGN_61_52_MASK | VTD_BF_SL_PDPE_IGN_63_MASK) +/** @} */ + + +/** @name Second-Level PDE (2MB Page). + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PDE2M_R_SHIFT 0 +#define VTD_BF_SL_PDE2M_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PDE2M_W_SHIFT 1 +#define VTD_BF_SL_PDE2M_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PDE2M_X_SHIFT 2 +#define VTD_BF_SL_PDE2M_X_MASK UINT64_C(0x0000000000000004) +/** EMT: Extended Memory Type. */ +#define VTD_BF_SL_PDE2M_EMT_SHIFT 3 +#define VTD_BF_SL_PDE2M_EMT_MASK UINT64_C(0x0000000000000038) +/** IPAT: Ignore PAT (Page Attribute Table). */ +#define VTD_BF_SL_PDE2M_IPAT_SHIFT 6 +#define VTD_BF_SL_PDE2M_IPAT_MASK UINT64_C(0x0000000000000040) +/** PS: Page Size (MB1). */ +#define VTD_BF_SL_PDE2M_PS_SHIFT 7 +#define VTD_BF_SL_PDE2M_PS_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PDE2M_A_SHIFT 8 +#define VTD_BF_SL_PDE2M_A_MASK UINT64_C(0x0000000000000100) +/** D: Dirty. */ +#define VTD_BF_SL_PDE2M_D_SHIFT 9 +#define VTD_BF_SL_PDE2M_D_MASK UINT64_C(0x0000000000000200) +/** IGN: Ignored (bit 10). */ +#define VTD_BF_SL_PDE2M_IGN_10_SHIFT 10 +#define VTD_BF_SL_PDE2M_IGN_10_MASK UINT64_C(0x0000000000000400) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PDE2M_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PDE2M_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** R: Reserved (bits 20:12). */ +#define VTD_BF_SL_PDE2M_RSVD_20_12_SHIFT 12 +#define VTD_BF_SL_PDE2M_RSVD_20_12_MASK UINT64_C(0x00000000001ff000) +/** ADDR: Address of 2MB page. */ +#define VTD_BF_SL_PDE2M_ADDR_SHIFT 21 +#define VTD_BF_SL_PDE2M_ADDR_MASK UINT64_C(0x000fffffffe00000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PDE2M_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PDE2M_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PDE2M_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PDE2M_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PDE2M_IGN_63_SHIFT 63 +#define VTD_BF_SL_PDE2M_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PDE2M_, UINT64_C(0), UINT64_MAX, + (R, W, X, EMT, IPAT, PS, A, D, IGN_10, RSVD_11, RSVD_20_12, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PDE (2MB page) valid mask. */ +#define VTD_SL_PDE2M_VALID_MASK ( VTD_BF_SL_PDE2M_R_MASK | VTD_BF_SL_PDE2M_W_MASK \ + | VTD_BF_SL_PDE2M_X_MASK | VTD_BF_SL_PDE2M_EMT_MASK \ + | VTD_BF_SL_PDE2M_IPAT_MASK | VTD_BF_SL_PDE2M_PS_MASK \ + | VTD_BF_SL_PDE2M_A_MASK | VTD_BF_SL_PDE2M_D_MASK \ + | VTD_BF_SL_PDE2M_IGN_10_MASK | VTD_BF_SL_PDE2M_ADDR_MASK \ + | VTD_BF_SL_PDE2M_IGN_61_52_MASK | VTD_BF_SL_PDE2M_IGN_63_MASK) +/** @} */ + + +/** @name Second-Level PDE. + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PDE_R_SHIFT 0 +#define VTD_BF_SL_PDE_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PDE_W_SHIFT 1 +#define VTD_BF_SL_PDE_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PDE_X_SHIFT 2 +#define VTD_BF_SL_PDE_X_MASK UINT64_C(0x0000000000000004) +/** IGN: Ignored (bits 6:3). */ +#define VTD_BF_SL_PDE_IGN_6_3_SHIFT 3 +#define VTD_BF_SL_PDE_IGN_6_3_MASK UINT64_C(0x0000000000000078) +/** PS: Page Size (MBZ). */ +#define VTD_BF_SL_PDE_PS_SHIFT 7 +#define VTD_BF_SL_PDE_PS_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PDE_A_SHIFT 8 +#define VTD_BF_SL_PDE_A_MASK UINT64_C(0x0000000000000100) +/** IGN: Ignored (bits 10:9). */ +#define VTD_BF_SL_PDE_IGN_10_9_SHIFT 9 +#define VTD_BF_SL_PDE_IGN_10_9_MASK UINT64_C(0x0000000000000600) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PDE_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PDE_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address of second-level PT. */ +#define VTD_BF_SL_PDE_ADDR_SHIFT 12 +#define VTD_BF_SL_PDE_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PDE_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PDE_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PDE_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PDE_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PDE_IGN_63_SHIFT 63 +#define VTD_BF_SL_PDE_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PDE_, UINT64_C(0), UINT64_MAX, + (R, W, X, IGN_6_3, PS, A, IGN_10_9, RSVD_11, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PDE valid mask. */ +#define VTD_SL_PDE_VALID_MASK ( VTD_BF_SL_PDE_R_MASK | VTD_BF_SL_PDE_W_MASK \ + | VTD_BF_SL_PDE_X_MASK | VTD_BF_SL_PDE_IGN_6_3_MASK \ + | VTD_BF_SL_PDE_PS_MASK | VTD_BF_SL_PDE_A_MASK \ + | VTD_BF_SL_PDE_IGN_10_9_MASK | VTD_BF_SL_PDE_ADDR_MASK \ + | VTD_BF_SL_PDE_IGN_61_52_MASK | VTD_BF_SL_PDE_IGN_63_MASK) +/** @} */ + + +/** @name Second-Level PTE. + * In accordance with the Intel spec. + * @{ */ +/** R: Read. */ +#define VTD_BF_SL_PTE_R_SHIFT 0 +#define VTD_BF_SL_PTE_R_MASK UINT64_C(0x0000000000000001) +/** W: Write. */ +#define VTD_BF_SL_PTE_W_SHIFT 1 +#define VTD_BF_SL_PTE_W_MASK UINT64_C(0x0000000000000002) +/** X: Execute. */ +#define VTD_BF_SL_PTE_X_SHIFT 2 +#define VTD_BF_SL_PTE_X_MASK UINT64_C(0x0000000000000004) +/** EMT: Extended Memory Type. */ +#define VTD_BF_SL_PTE_EMT_SHIFT 3 +#define VTD_BF_SL_PTE_EMT_MASK UINT64_C(0x0000000000000038) +/** IPAT: Ignore PAT (Page Attribute Table). */ +#define VTD_BF_SL_PTE_IPAT_SHIFT 6 +#define VTD_BF_SL_PTE_IPAT_MASK UINT64_C(0x0000000000000040) +/** IGN: Ignored (bit 7). */ +#define VTD_BF_SL_PTE_IGN_7_SHIFT 7 +#define VTD_BF_SL_PTE_IGN_7_MASK UINT64_C(0x0000000000000080) +/** A: Accessed. */ +#define VTD_BF_SL_PTE_A_SHIFT 8 +#define VTD_BF_SL_PTE_A_MASK UINT64_C(0x0000000000000100) +/** D: Dirty. */ +#define VTD_BF_SL_PTE_D_SHIFT 9 +#define VTD_BF_SL_PTE_D_MASK UINT64_C(0x0000000000000200) +/** IGN: Ignored (bit 10). */ +#define VTD_BF_SL_PTE_IGN_10_SHIFT 10 +#define VTD_BF_SL_PTE_IGN_10_MASK UINT64_C(0x0000000000000400) +/** R: Reserved (bit 11). */ +#define VTD_BF_SL_PTE_RSVD_11_SHIFT 11 +#define VTD_BF_SL_PTE_RSVD_11_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address of 4K page. */ +#define VTD_BF_SL_PTE_ADDR_SHIFT 12 +#define VTD_BF_SL_PTE_ADDR_MASK UINT64_C(0x000ffffffffff000) +/** IGN: Ignored (bits 61:52). */ +#define VTD_BF_SL_PTE_IGN_61_52_SHIFT 52 +#define VTD_BF_SL_PTE_IGN_61_52_MASK UINT64_C(0x3ff0000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_SL_PTE_RSVD_62_SHIFT 62 +#define VTD_BF_SL_PTE_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IGN: Ignored (bit 63). */ +#define VTD_BF_SL_PTE_IGN_63_SHIFT 63 +#define VTD_BF_SL_PTE_IGN_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_SL_PTE_, UINT64_C(0), UINT64_MAX, + (R, W, X, EMT, IPAT, IGN_7, A, D, IGN_10, RSVD_11, ADDR, IGN_61_52, RSVD_62, IGN_63)); + +/** Second-level PTE valid mask. */ +#define VTD_SL_PTE_VALID_MASK ( VTD_BF_SL_PTE_R_MASK | VTD_BF_SL_PTE_W_MASK \ + | VTD_BF_SL_PTE_X_MASK | VTD_BF_SL_PTE_EMT_MASK \ + | VTD_BF_SL_PTE_IPAT_MASK | VTD_BF_SL_PTE_IGN_7_MASK \ + | VTD_BF_SL_PTE_A_MASK | VTD_BF_SL_PTE_D_MASK \ + | VTD_BF_SL_PTE_IGN_10_MASK | VTD_BF_SL_PTE_ADDR_MASK \ + | VTD_BF_SL_PTE_IGN_61_52_MASK | VTD_BF_SL_PTE_IGN_63_MASK) +/** @} */ + + +/** @name Fault Record. + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 11:0). */ +#define VTD_BF_0_FAULT_RECORD_RSVD_11_0_SHIFT 0 +#define VTD_BF_0_FAULT_RECORD_RSVD_11_0_MASK UINT64_C(0x0000000000000fff) +/** FI: Fault Information. */ +#define VTD_BF_0_FAULT_RECORD_FI_SHIFT 12 +#define VTD_BF_0_FAULT_RECORD_FI_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_FAULT_RECORD_, UINT64_C(0), UINT64_MAX, + (RSVD_11_0, FI)); + +/** SID: Source identifier. */ +#define VTD_BF_1_FAULT_RECORD_SID_SHIFT 0 +#define VTD_BF_1_FAULT_RECORD_SID_MASK UINT64_C(0x000000000000ffff) +/** R: Reserved (bits 28:16). */ +#define VTD_BF_1_FAULT_RECORD_RSVD_28_16_SHIFT 16 +#define VTD_BF_1_FAULT_RECORD_RSVD_28_16_MASK UINT64_C(0x000000001fff0000) +/** PRIV: Privilege Mode Requested. */ +#define VTD_BF_1_FAULT_RECORD_PRIV_SHIFT 29 +#define VTD_BF_1_FAULT_RECORD_PRIV_MASK UINT64_C(0x0000000020000000) +/** EXE: Execute Permission Requested. */ +#define VTD_BF_1_FAULT_RECORD_EXE_SHIFT 30 +#define VTD_BF_1_FAULT_RECORD_EXE_MASK UINT64_C(0x0000000040000000) +/** PP: PASID Present. */ +#define VTD_BF_1_FAULT_RECORD_PP_SHIFT 31 +#define VTD_BF_1_FAULT_RECORD_PP_MASK UINT64_C(0x0000000080000000) +/** FR: Fault Reason. */ +#define VTD_BF_1_FAULT_RECORD_FR_SHIFT 32 +#define VTD_BF_1_FAULT_RECORD_FR_MASK UINT64_C(0x000000ff00000000) +/** PV: PASID Value. */ +#define VTD_BF_1_FAULT_RECORD_PV_SHIFT 40 +#define VTD_BF_1_FAULT_RECORD_PV_MASK UINT64_C(0x0fffff0000000000) +/** AT: Address Type. */ +#define VTD_BF_1_FAULT_RECORD_AT_SHIFT 60 +#define VTD_BF_1_FAULT_RECORD_AT_MASK UINT64_C(0x3000000000000000) +/** T: Type. */ +#define VTD_BF_1_FAULT_RECORD_T_SHIFT 62 +#define VTD_BF_1_FAULT_RECORD_T_MASK UINT64_C(0x4000000000000000) +/** R: Reserved (bit 127). */ +#define VTD_BF_1_FAULT_RECORD_RSVD_63_SHIFT 63 +#define VTD_BF_1_FAULT_RECORD_RSVD_63_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_FAULT_RECORD_, UINT64_C(0), UINT64_MAX, + (SID, RSVD_28_16, PRIV, EXE, PP, FR, PV, AT, T, RSVD_63)); + +/** Fault record. */ +typedef struct VTD_FAULT_RECORD_T +{ + /** The qwords in the fault record. */ + uint64_t au64[2]; +} VTD_FAULT_RECORD_T; +/** Pointer to a fault record. */ +typedef VTD_FAULT_RECORD_T *PVTD_FAULT_RECORD_T; +/** Pointer to a const fault record. */ +typedef VTD_FAULT_RECORD_T const *PCVTD_FAULT_RECORD_T; +/** @} */ + + +/** @name Interrupt Remapping Table Entry (IRTE) for Remapped Interrupts. + * In accordance with the Intel spec. + * @{ */ +/** P: Present. */ +#define VTD_BF_0_IRTE_P_SHIFT 0 +#define VTD_BF_0_IRTE_P_MASK UINT64_C(0x0000000000000001) +/** FPD: Fault Processing Disable. */ +#define VTD_BF_0_IRTE_FPD_SHIFT 1 +#define VTD_BF_0_IRTE_FPD_MASK UINT64_C(0x0000000000000002) +/** DM: Destination Mode (0=physical, 1=logical). */ +#define VTD_BF_0_IRTE_DM_SHIFT 2 +#define VTD_BF_0_IRTE_DM_MASK UINT64_C(0x0000000000000004) +/** RH: Redirection Hint. */ +#define VTD_BF_0_IRTE_RH_SHIFT 3 +#define VTD_BF_0_IRTE_RH_MASK UINT64_C(0x0000000000000008) +/** TM: Trigger Mode. */ +#define VTD_BF_0_IRTE_TM_SHIFT 4 +#define VTD_BF_0_IRTE_TM_MASK UINT64_C(0x0000000000000010) +/** DLM: Delivery Mode. */ +#define VTD_BF_0_IRTE_DLM_SHIFT 5 +#define VTD_BF_0_IRTE_DLM_MASK UINT64_C(0x00000000000000e0) +/** AVL: Available. */ +#define VTD_BF_0_IRTE_AVAIL_SHIFT 8 +#define VTD_BF_0_IRTE_AVAIL_MASK UINT64_C(0x0000000000000f00) +/** R: Reserved (bits 14:12). */ +#define VTD_BF_0_IRTE_RSVD_14_12_SHIFT 12 +#define VTD_BF_0_IRTE_RSVD_14_12_MASK UINT64_C(0x0000000000007000) +/** IM: IRTE Mode. */ +#define VTD_BF_0_IRTE_IM_SHIFT 15 +#define VTD_BF_0_IRTE_IM_MASK UINT64_C(0x0000000000008000) +/** V: Vector. */ +#define VTD_BF_0_IRTE_V_SHIFT 16 +#define VTD_BF_0_IRTE_V_MASK UINT64_C(0x0000000000ff0000) +/** R: Reserved (bits 31:24). */ +#define VTD_BF_0_IRTE_RSVD_31_24_SHIFT 24 +#define VTD_BF_0_IRTE_RSVD_31_24_MASK UINT64_C(0x00000000ff000000) +/** DST: Desination Id. */ +#define VTD_BF_0_IRTE_DST_SHIFT 32 +#define VTD_BF_0_IRTE_DST_MASK UINT64_C(0xffffffff00000000) +/** R: Reserved (bits 39:32) when EIME=0. */ +#define VTD_BF_0_IRTE_RSVD_39_32_SHIFT 32 +#define VTD_BF_0_IRTE_RSVD_39_32_MASK UINT64_C(0x000000ff00000000) +/** DST_XAPIC: Destination Id when EIME=0. */ +#define VTD_BF_0_IRTE_DST_XAPIC_SHIFT 40 +#define VTD_BF_0_IRTE_DST_XAPIC_MASK UINT64_C(0x0000ff0000000000) +/** R: Reserved (bits 63:48) when EIME=0. */ +#define VTD_BF_0_IRTE_RSVD_63_48_SHIFT 48 +#define VTD_BF_0_IRTE_RSVD_63_48_MASK UINT64_C(0xffff000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_IRTE_, UINT64_C(0), UINT64_MAX, + (P, FPD, DM, RH, TM, DLM, AVAIL, RSVD_14_12, IM, V, RSVD_31_24, DST)); +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_IRTE_, UINT64_C(0), UINT64_MAX, + (P, FPD, DM, RH, TM, DLM, AVAIL, RSVD_14_12, IM, V, RSVD_31_24, RSVD_39_32, DST_XAPIC, RSVD_63_48)); + +/** SID: Source Identifier. */ +#define VTD_BF_1_IRTE_SID_SHIFT 0 +#define VTD_BF_1_IRTE_SID_MASK UINT64_C(0x000000000000ffff) +/** SQ: Source-Id Qualifier. */ +#define VTD_BF_1_IRTE_SQ_SHIFT 16 +#define VTD_BF_1_IRTE_SQ_MASK UINT64_C(0x0000000000030000) +/** SVT: Source Validation Type. */ +#define VTD_BF_1_IRTE_SVT_SHIFT 18 +#define VTD_BF_1_IRTE_SVT_MASK UINT64_C(0x00000000000c0000) +/** R: Reserved (bits 127:84). */ +#define VTD_BF_1_IRTE_RSVD_63_20_SHIFT 20 +#define VTD_BF_1_IRTE_RSVD_63_20_MASK UINT64_C(0xfffffffffff00000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_IRTE_, UINT64_C(0), UINT64_MAX, + (SID, SQ, SVT, RSVD_63_20)); + +/** IRTE: Qword 0 valid mask when EIME=1. */ +#define VTD_IRTE_0_X2APIC_VALID_MASK ( VTD_BF_0_IRTE_P_MASK | VTD_BF_0_IRTE_FPD_MASK \ + | VTD_BF_0_IRTE_DM_MASK | VTD_BF_0_IRTE_RH_MASK \ + | VTD_BF_0_IRTE_TM_MASK | VTD_BF_0_IRTE_DLM_MASK \ + | VTD_BF_0_IRTE_AVAIL_MASK | VTD_BF_0_IRTE_IM_MASK \ + | VTD_BF_0_IRTE_V_MASK | VTD_BF_0_IRTE_DST_MASK) +/** IRTE: Qword 0 valid mask when EIME=0. */ +#define VTD_IRTE_0_XAPIC_VALID_MASK ( VTD_BF_0_IRTE_P_MASK | VTD_BF_0_IRTE_FPD_MASK \ + | VTD_BF_0_IRTE_DM_MASK | VTD_BF_0_IRTE_RH_MASK \ + | VTD_BF_0_IRTE_TM_MASK | VTD_BF_0_IRTE_DLM_MASK \ + | VTD_BF_0_IRTE_AVAIL_MASK | VTD_BF_0_IRTE_IM_MASK \ + | VTD_BF_0_IRTE_V_MASK | VTD_BF_0_IRTE_DST_XAPIC_MASK) +/** IRTE: Qword 1 valid mask. */ +#define VTD_IRTE_1_VALID_MASK ( VTD_BF_1_IRTE_SID_MASK | VTD_BF_1_IRTE_SQ_MASK \ + | VTD_BF_1_IRTE_SVT_MASK) + +/** Interrupt Remapping Table Entry (IRTE) for remapped interrupts. */ +typedef struct VTD_IRTE_T +{ + /** The qwords in the IRTE. */ + uint64_t au64[2]; +} VTD_IRTE_T; +/** Pointer to an IRTE. */ +typedef VTD_IRTE_T *PVTD_IRTE_T; +/** Pointer to a const IRTE. */ +typedef VTD_IRTE_T const *PCVTD_IRTE_T; + +/** IRTE SVT: No validation required. */ +#define VTD_IRTE_SVT_NONE 0 +/** IRTE SVT: Validate using a mask derived from SID and SQT. */ +#define VTD_IRTE_SVT_VALIDATE_MASK 1 +/** IRTE SVT: Validate using Bus range in the SID. */ +#define VTD_IRTE_SVT_VALIDATE_BUS_RANGE 2 +/** IRTE SVT: Reserved. */ +#define VTD_IRTE_SVT_VALIDATE_RSVD 3 +/** @} */ + + +/** @name Version Register (VER_REG). + * In accordance with the Intel spec. + * @{ */ +/** Min: Minor Version Number. */ +#define VTD_BF_VER_REG_MIN_SHIFT 0 +#define VTD_BF_VER_REG_MIN_MASK UINT32_C(0x0000000f) +/** Max: Major Version Number. */ +#define VTD_BF_VER_REG_MAX_SHIFT 4 +#define VTD_BF_VER_REG_MAX_MASK UINT32_C(0x000000f0) +/** R: Reserved (bits 31:8). */ +#define VTD_BF_VER_REG_RSVD_31_8_SHIFT 8 +#define VTD_BF_VER_REG_RSVD_31_8_MASK UINT32_C(0xffffff00) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_VER_REG_, UINT32_C(0), UINT32_MAX, + (MIN, MAX, RSVD_31_8)); +/** RW: Read/write mask. */ +#define VTD_VER_REG_RW_MASK UINT32_C(0) +/** @} */ + + +/** @name Capability Register (CAP_REG). + * In accordance with the Intel spec. + * @{ */ +/** ND: Number of domains supported. */ +#define VTD_BF_CAP_REG_ND_SHIFT 0 +#define VTD_BF_CAP_REG_ND_MASK UINT64_C(0x0000000000000007) +/** AFL: Advanced Fault Logging. */ +#define VTD_BF_CAP_REG_AFL_SHIFT 3 +#define VTD_BF_CAP_REG_AFL_MASK UINT64_C(0x0000000000000008) +/** RWBF: Required Write-Buffer Flushing. */ +#define VTD_BF_CAP_REG_RWBF_SHIFT 4 +#define VTD_BF_CAP_REG_RWBF_MASK UINT64_C(0x0000000000000010) +/** PLMR: Protected Low-Memory Region. */ +#define VTD_BF_CAP_REG_PLMR_SHIFT 5 +#define VTD_BF_CAP_REG_PLMR_MASK UINT64_C(0x0000000000000020) +/** PHMR: Protected High-Memory Region. */ +#define VTD_BF_CAP_REG_PHMR_SHIFT 6 +#define VTD_BF_CAP_REG_PHMR_MASK UINT64_C(0x0000000000000040) +/** CM: Caching Mode. */ +#define VTD_BF_CAP_REG_CM_SHIFT 7 +#define VTD_BF_CAP_REG_CM_MASK UINT64_C(0x0000000000000080) +/** SAGAW: Supported Adjusted Guest Address Widths. */ +#define VTD_BF_CAP_REG_SAGAW_SHIFT 8 +#define VTD_BF_CAP_REG_SAGAW_MASK UINT64_C(0x0000000000001f00) +/** R: Reserved (bits 15:13). */ +#define VTD_BF_CAP_REG_RSVD_15_13_SHIFT 13 +#define VTD_BF_CAP_REG_RSVD_15_13_MASK UINT64_C(0x000000000000e000) +/** MGAW: Maximum Guest Address Width. */ +#define VTD_BF_CAP_REG_MGAW_SHIFT 16 +#define VTD_BF_CAP_REG_MGAW_MASK UINT64_C(0x00000000003f0000) +/** ZLR: Zero Length Read. */ +#define VTD_BF_CAP_REG_ZLR_SHIFT 22 +#define VTD_BF_CAP_REG_ZLR_MASK UINT64_C(0x0000000000400000) +/** DEP: Deprecated MBZ. Reserved (bit 23). */ +#define VTD_BF_CAP_REG_RSVD_23_SHIFT 23 +#define VTD_BF_CAP_REG_RSVD_23_MASK UINT64_C(0x0000000000800000) +/** FRO: Fault-recording Register Offset. */ +#define VTD_BF_CAP_REG_FRO_SHIFT 24 +#define VTD_BF_CAP_REG_FRO_MASK UINT64_C(0x00000003ff000000) +/** SLLPS: Second Level Large Page Support. */ +#define VTD_BF_CAP_REG_SLLPS_SHIFT 34 +#define VTD_BF_CAP_REG_SLLPS_MASK UINT64_C(0x0000003c00000000) +/** R: Reserved (bit 38). */ +#define VTD_BF_CAP_REG_RSVD_38_SHIFT 38 +#define VTD_BF_CAP_REG_RSVD_38_MASK UINT64_C(0x0000004000000000) +/** PSI: Page Selective Invalidation. */ +#define VTD_BF_CAP_REG_PSI_SHIFT 39 +#define VTD_BF_CAP_REG_PSI_MASK UINT64_C(0x0000008000000000) +/** NFR: Number of Fault-recording Registers. */ +#define VTD_BF_CAP_REG_NFR_SHIFT 40 +#define VTD_BF_CAP_REG_NFR_MASK UINT64_C(0x0000ff0000000000) +/** MAMV: Maximum Address Mask Value. */ +#define VTD_BF_CAP_REG_MAMV_SHIFT 48 +#define VTD_BF_CAP_REG_MAMV_MASK UINT64_C(0x003f000000000000) +/** DWD: Write Draining. */ +#define VTD_BF_CAP_REG_DWD_SHIFT 54 +#define VTD_BF_CAP_REG_DWD_MASK UINT64_C(0x0040000000000000) +/** DRD: Read Draining. */ +#define VTD_BF_CAP_REG_DRD_SHIFT 55 +#define VTD_BF_CAP_REG_DRD_MASK UINT64_C(0x0080000000000000) +/** FL1GP: First Level 1 GB Page Support. */ +#define VTD_BF_CAP_REG_FL1GP_SHIFT 56 +#define VTD_BF_CAP_REG_FL1GP_MASK UINT64_C(0x0100000000000000) +/** R: Reserved (bits 58:57). */ +#define VTD_BF_CAP_REG_RSVD_58_57_SHIFT 57 +#define VTD_BF_CAP_REG_RSVD_58_57_MASK UINT64_C(0x0600000000000000) +/** PI: Posted Interrupt Support. */ +#define VTD_BF_CAP_REG_PI_SHIFT 59 +#define VTD_BF_CAP_REG_PI_MASK UINT64_C(0x0800000000000000) +/** FL5LP: First Level 5-level Paging Support. */ +#define VTD_BF_CAP_REG_FL5LP_SHIFT 60 +#define VTD_BF_CAP_REG_FL5LP_MASK UINT64_C(0x1000000000000000) +/** R: Reserved (bit 61). */ +#define VTD_BF_CAP_REG_RSVD_61_SHIFT 61 +#define VTD_BF_CAP_REG_RSVD_61_MASK UINT64_C(0x2000000000000000) +/** ESIRTPS: Enhanced Set Interrupt Root Table Pointer Support. */ +#define VTD_BF_CAP_REG_ESIRTPS_SHIFT 62 +#define VTD_BF_CAP_REG_ESIRTPS_MASK UINT64_C(0x4000000000000000) +/** : Enhanced Set Root Table Pointer Support. */ +#define VTD_BF_CAP_REG_ESRTPS_SHIFT 63 +#define VTD_BF_CAP_REG_ESRTPS_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_CAP_REG_, UINT64_C(0), UINT64_MAX, + (ND, AFL, RWBF, PLMR, PHMR, CM, SAGAW, RSVD_15_13, MGAW, ZLR, RSVD_23, FRO, SLLPS, RSVD_38, PSI, NFR, + MAMV, DWD, DRD, FL1GP, RSVD_58_57, PI, FL5LP, RSVD_61, ESIRTPS, ESRTPS)); + +/** RW: Read/write mask. */ +#define VTD_CAP_REG_RW_MASK UINT64_C(0) +/** @} */ + + +/** @name Extended Capability Register (ECAP_REG). + * In accordance with the Intel spec. + * @{ */ +/** C: Page-walk Coherence. */ +#define VTD_BF_ECAP_REG_C_SHIFT 0 +#define VTD_BF_ECAP_REG_C_MASK UINT64_C(0x0000000000000001) +/** QI: Queued Invalidation Support. */ +#define VTD_BF_ECAP_REG_QI_SHIFT 1 +#define VTD_BF_ECAP_REG_QI_MASK UINT64_C(0x0000000000000002) +/** DT: Device-TLB Support. */ +#define VTD_BF_ECAP_REG_DT_SHIFT 2 +#define VTD_BF_ECAP_REG_DT_MASK UINT64_C(0x0000000000000004) +/** IR: Interrupt Remapping Support. */ +#define VTD_BF_ECAP_REG_IR_SHIFT 3 +#define VTD_BF_ECAP_REG_IR_MASK UINT64_C(0x0000000000000008) +/** EIM: Extended Interrupt Mode. */ +#define VTD_BF_ECAP_REG_EIM_SHIFT 4 +#define VTD_BF_ECAP_REG_EIM_MASK UINT64_C(0x0000000000000010) +/** DEP: Deprecated MBZ. Reserved (bit 5). */ +#define VTD_BF_ECAP_REG_RSVD_5_SHIFT 5 +#define VTD_BF_ECAP_REG_RSVD_5_MASK UINT64_C(0x0000000000000020) +/** PT: Pass Through. */ +#define VTD_BF_ECAP_REG_PT_SHIFT 6 +#define VTD_BF_ECAP_REG_PT_MASK UINT64_C(0x0000000000000040) +/** SC: Snoop Control. */ +#define VTD_BF_ECAP_REG_SC_SHIFT 7 +#define VTD_BF_ECAP_REG_SC_MASK UINT64_C(0x0000000000000080) +/** IRO: IOTLB Register Offset. */ +#define VTD_BF_ECAP_REG_IRO_SHIFT 8 +#define VTD_BF_ECAP_REG_IRO_MASK UINT64_C(0x000000000003ff00) +/** R: Reserved (bits 19:18). */ +#define VTD_BF_ECAP_REG_RSVD_19_18_SHIFT 18 +#define VTD_BF_ECAP_REG_RSVD_19_18_MASK UINT64_C(0x00000000000c0000) +/** MHMV: Maximum Handle Mask Value. */ +#define VTD_BF_ECAP_REG_MHMV_SHIFT 20 +#define VTD_BF_ECAP_REG_MHMV_MASK UINT64_C(0x0000000000f00000) +/** DEP: Deprecated MBZ. Reserved (bit 24). */ +#define VTD_BF_ECAP_REG_RSVD_24_SHIFT 24 +#define VTD_BF_ECAP_REG_RSVD_24_MASK UINT64_C(0x0000000001000000) +/** MTS: Memory Type Support. */ +#define VTD_BF_ECAP_REG_MTS_SHIFT 25 +#define VTD_BF_ECAP_REG_MTS_MASK UINT64_C(0x0000000002000000) +/** NEST: Nested Translation Support. */ +#define VTD_BF_ECAP_REG_NEST_SHIFT 26 +#define VTD_BF_ECAP_REG_NEST_MASK UINT64_C(0x0000000004000000) +/** R: Reserved (bit 27). */ +#define VTD_BF_ECAP_REG_RSVD_27_SHIFT 27 +#define VTD_BF_ECAP_REG_RSVD_27_MASK UINT64_C(0x0000000008000000) +/** DEP: Deprecated MBZ. Reserved (bit 28). */ +#define VTD_BF_ECAP_REG_RSVD_28_SHIFT 28 +#define VTD_BF_ECAP_REG_RSVD_28_MASK UINT64_C(0x0000000010000000) +/** PRS: Page Request Support. */ +#define VTD_BF_ECAP_REG_PRS_SHIFT 29 +#define VTD_BF_ECAP_REG_PRS_MASK UINT64_C(0x0000000020000000) +/** ERS: Execute Request Support. */ +#define VTD_BF_ECAP_REG_ERS_SHIFT 30 +#define VTD_BF_ECAP_REG_ERS_MASK UINT64_C(0x0000000040000000) +/** SRS: Supervisor Request Support. */ +#define VTD_BF_ECAP_REG_SRS_SHIFT 31 +#define VTD_BF_ECAP_REG_SRS_MASK UINT64_C(0x0000000080000000) +/** R: Reserved (bit 32). */ +#define VTD_BF_ECAP_REG_RSVD_32_SHIFT 32 +#define VTD_BF_ECAP_REG_RSVD_32_MASK UINT64_C(0x0000000100000000) +/** NWFS: No Write Flag Support. */ +#define VTD_BF_ECAP_REG_NWFS_SHIFT 33 +#define VTD_BF_ECAP_REG_NWFS_MASK UINT64_C(0x0000000200000000) +/** EAFS: Extended Accessed Flags Support. */ +#define VTD_BF_ECAP_REG_EAFS_SHIFT 34 +#define VTD_BF_ECAP_REG_EAFS_MASK UINT64_C(0x0000000400000000) +/** PSS: PASID Size Supported. */ +#define VTD_BF_ECAP_REG_PSS_SHIFT 35 +#define VTD_BF_ECAP_REG_PSS_MASK UINT64_C(0x000000f800000000) +/** PASID: Process Address Space ID Support. */ +#define VTD_BF_ECAP_REG_PASID_SHIFT 40 +#define VTD_BF_ECAP_REG_PASID_MASK UINT64_C(0x0000010000000000) +/** DIT: Device-TLB Invalidation Throttle. */ +#define VTD_BF_ECAP_REG_DIT_SHIFT 41 +#define VTD_BF_ECAP_REG_DIT_MASK UINT64_C(0x0000020000000000) +/** PDS: Page-request Drain Support. */ +#define VTD_BF_ECAP_REG_PDS_SHIFT 42 +#define VTD_BF_ECAP_REG_PDS_MASK UINT64_C(0x0000040000000000) +/** SMTS: Scalable-Mode Translation Support. */ +#define VTD_BF_ECAP_REG_SMTS_SHIFT 43 +#define VTD_BF_ECAP_REG_SMTS_MASK UINT64_C(0x0000080000000000) +/** VCS: Virtual Command Support. */ +#define VTD_BF_ECAP_REG_VCS_SHIFT 44 +#define VTD_BF_ECAP_REG_VCS_MASK UINT64_C(0x0000100000000000) +/** SLADS: Second-Level Accessed/Dirty Support. */ +#define VTD_BF_ECAP_REG_SLADS_SHIFT 45 +#define VTD_BF_ECAP_REG_SLADS_MASK UINT64_C(0x0000200000000000) +/** SLTS: Second-Level Translation Support. */ +#define VTD_BF_ECAP_REG_SLTS_SHIFT 46 +#define VTD_BF_ECAP_REG_SLTS_MASK UINT64_C(0x0000400000000000) +/** FLTS: First-Level Translation Support. */ +#define VTD_BF_ECAP_REG_FLTS_SHIFT 47 +#define VTD_BF_ECAP_REG_FLTS_MASK UINT64_C(0x0000800000000000) +/** SMPWCS: Scalable-Mode Page-Walk Coherency Support. */ +#define VTD_BF_ECAP_REG_SMPWCS_SHIFT 48 +#define VTD_BF_ECAP_REG_SMPWCS_MASK UINT64_C(0x0001000000000000) +/** RPS: RID-PASID Support. */ +#define VTD_BF_ECAP_REG_RPS_SHIFT 49 +#define VTD_BF_ECAP_REG_RPS_MASK UINT64_C(0x0002000000000000) +/** R: Reserved (bits 51:50). */ +#define VTD_BF_ECAP_REG_RSVD_51_50_SHIFT 50 +#define VTD_BF_ECAP_REG_RSVD_51_50_MASK UINT64_C(0x000c000000000000) +/** ADMS: Abort DMA Mode Support. */ +#define VTD_BF_ECAP_REG_ADMS_SHIFT 52 +#define VTD_BF_ECAP_REG_ADMS_MASK UINT64_C(0x0010000000000000) +/** RPRIVS: RID_PRIV Support. */ +#define VTD_BF_ECAP_REG_RPRIVS_SHIFT 53 +#define VTD_BF_ECAP_REG_RPRIVS_MASK UINT64_C(0x0020000000000000) +/** R: Reserved (bits 63:54). */ +#define VTD_BF_ECAP_REG_RSVD_63_54_SHIFT 54 +#define VTD_BF_ECAP_REG_RSVD_63_54_MASK UINT64_C(0xffc0000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_ECAP_REG_, UINT64_C(0), UINT64_MAX, + (C, QI, DT, IR, EIM, RSVD_5, PT, SC, IRO, RSVD_19_18, MHMV, RSVD_24, MTS, NEST, RSVD_27, RSVD_28, + PRS, ERS, SRS, RSVD_32, NWFS, EAFS, PSS, PASID, DIT, PDS, SMTS, VCS, SLADS, SLTS, FLTS, SMPWCS, RPS, + RSVD_51_50, ADMS, RPRIVS, RSVD_63_54)); + +/** RW: Read/write mask. */ +#define VTD_ECAP_REG_RW_MASK UINT64_C(0) +/** @} */ + + +/** @name Global Command Register (GCMD_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 22:0). */ +#define VTD_BF_GCMD_REG_RSVD_22_0_SHIFT 0 +#define VTD_BF_GCMD_REG_RSVD_22_0_MASK UINT32_C(0x007fffff) +/** CFI: Compatibility Format Interrupt. */ +#define VTD_BF_GCMD_REG_CFI_SHIFT 23 +#define VTD_BF_GCMD_REG_CFI_MASK UINT32_C(0x00800000) +/** SIRTP: Set Interrupt Table Remap Pointer. */ +#define VTD_BF_GCMD_REG_SIRTP_SHIFT 24 +#define VTD_BF_GCMD_REG_SIRTP_MASK UINT32_C(0x01000000) +/** IRE: Interrupt Remap Enable. */ +#define VTD_BF_GCMD_REG_IRE_SHIFT 25 +#define VTD_BF_GCMD_REG_IRE_MASK UINT32_C(0x02000000) +/** QIE: Queued Invalidation Enable. */ +#define VTD_BF_GCMD_REG_QIE_SHIFT 26 +#define VTD_BF_GCMD_REG_QIE_MASK UINT32_C(0x04000000) +/** WBF: Write Buffer Flush. */ +#define VTD_BF_GCMD_REG_WBF_SHIFT 27 +#define VTD_BF_GCMD_REG_WBF_MASK UINT32_C(0x08000000) +/** EAFL: Enable Advance Fault Logging. */ +#define VTD_BF_GCMD_REG_EAFL_SHIFT 28 +#define VTD_BF_GCMD_REG_EAFL_MASK UINT32_C(0x10000000) +/** SFL: Set Fault Log. */ +#define VTD_BF_GCMD_REG_SFL_SHIFT 29 +#define VTD_BF_GCMD_REG_SFL_MASK UINT32_C(0x20000000) +/** SRTP: Set Root Table Pointer. */ +#define VTD_BF_GCMD_REG_SRTP_SHIFT 30 +#define VTD_BF_GCMD_REG_SRTP_MASK UINT32_C(0x40000000) +/** TE: Translation Enable. */ +#define VTD_BF_GCMD_REG_TE_SHIFT 31 +#define VTD_BF_GCMD_REG_TE_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_GCMD_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_22_0, CFI, SIRTP, IRE, QIE, WBF, EAFL, SFL, SRTP, TE)); + +/** RW: Read/write mask. */ +#define VTD_GCMD_REG_RW_MASK ( VTD_BF_GCMD_REG_TE_MASK | VTD_BF_GCMD_REG_SRTP_MASK \ + | VTD_BF_GCMD_REG_SFL_MASK | VTD_BF_GCMD_REG_EAFL_MASK \ + | VTD_BF_GCMD_REG_WBF_MASK | VTD_BF_GCMD_REG_QIE_MASK \ + | VTD_BF_GCMD_REG_IRE_MASK | VTD_BF_GCMD_REG_SIRTP_MASK \ + | VTD_BF_GCMD_REG_CFI_MASK) +/** @} */ + + +/** @name Global Status Register (GSTS_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 22:0). */ +#define VTD_BF_GSTS_REG_RSVD_22_0_SHIFT 0 +#define VTD_BF_GSTS_REG_RSVD_22_0_MASK UINT32_C(0x007fffff) +/** CFIS: Compatibility Format Interrupt Status. */ +#define VTD_BF_GSTS_REG_CFIS_SHIFT 23 +#define VTD_BF_GSTS_REG_CFIS_MASK UINT32_C(0x00800000) +/** IRTPS: Interrupt Remapping Table Pointer Status. */ +#define VTD_BF_GSTS_REG_IRTPS_SHIFT 24 +#define VTD_BF_GSTS_REG_IRTPS_MASK UINT32_C(0x01000000) +/** IRES: Interrupt Remapping Enable Status. */ +#define VTD_BF_GSTS_REG_IRES_SHIFT 25 +#define VTD_BF_GSTS_REG_IRES_MASK UINT32_C(0x02000000) +/** QIES: Queued Invalidation Enable Status. */ +#define VTD_BF_GSTS_REG_QIES_SHIFT 26 +#define VTD_BF_GSTS_REG_QIES_MASK UINT32_C(0x04000000) +/** WBFS: Write Buffer Flush Status. */ +#define VTD_BF_GSTS_REG_WBFS_SHIFT 27 +#define VTD_BF_GSTS_REG_WBFS_MASK UINT32_C(0x08000000) +/** AFLS: Advanced Fault Logging Status. */ +#define VTD_BF_GSTS_REG_AFLS_SHIFT 28 +#define VTD_BF_GSTS_REG_AFLS_MASK UINT32_C(0x10000000) +/** FLS: Fault Log Status. */ +#define VTD_BF_GSTS_REG_FLS_SHIFT 29 +#define VTD_BF_GSTS_REG_FLS_MASK UINT32_C(0x20000000) +/** RTPS: Root Table Pointer Status. */ +#define VTD_BF_GSTS_REG_RTPS_SHIFT 30 +#define VTD_BF_GSTS_REG_RTPS_MASK UINT32_C(0x40000000) +/** TES: Translation Enable Status. */ +#define VTD_BF_GSTS_REG_TES_SHIFT 31 +#define VTD_BF_GSTS_REG_TES_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_GSTS_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_22_0, CFIS, IRTPS, IRES, QIES, WBFS, AFLS, FLS, RTPS, TES)); + +/** RW: Read/write mask. */ +#define VTD_GSTS_REG_RW_MASK UINT32_C(0) +/** @} */ + + +/** @name Root Table Address Register (RTADDR_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 9:0). */ +#define VTD_BF_RTADDR_REG_RSVD_9_0_SHIFT 0 +#define VTD_BF_RTADDR_REG_RSVD_9_0_MASK UINT64_C(0x00000000000003ff) +/** TTM: Translation Table Mode. */ +#define VTD_BF_RTADDR_REG_TTM_SHIFT 10 +#define VTD_BF_RTADDR_REG_TTM_MASK UINT64_C(0x0000000000000c00) +/** RTA: Root Table Address. */ +#define VTD_BF_RTADDR_REG_RTA_SHIFT 12 +#define VTD_BF_RTADDR_REG_RTA_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_RTADDR_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_9_0, TTM, RTA)); + +/** RW: Read/write mask. */ +#define VTD_RTADDR_REG_RW_MASK UINT64_C(0xfffffffffffffc00) + +/** RTADDR_REG.TTM: Legacy mode. */ +#define VTD_TTM_LEGACY_MODE 0 +/** RTADDR_REG.TTM: Scalable mode. */ +#define VTD_TTM_SCALABLE_MODE 1 +/** RTADDR_REG.TTM: Reserved. */ +#define VTD_TTM_RSVD 2 +/** RTADDR_REG.TTM: Abort DMA mode. */ +#define VTD_TTM_ABORT_DMA_MODE 3 +/** @} */ + + +/** @name Context Command Register (CCMD_REG). + * In accordance with the Intel spec. + * @{ */ +/** DID: Domain-ID. */ +#define VTD_BF_CCMD_REG_DID_SHIFT 0 +#define VTD_BF_CCMD_REG_DID_MASK UINT64_C(0x000000000000ffff) +/** SID: Source-ID. */ +#define VTD_BF_CCMD_REG_SID_SHIFT 16 +#define VTD_BF_CCMD_REG_SID_MASK UINT64_C(0x00000000ffff0000) +/** FM: Function Mask. */ +#define VTD_BF_CCMD_REG_FM_SHIFT 32 +#define VTD_BF_CCMD_REG_FM_MASK UINT64_C(0x0000000300000000) +/** R: Reserved (bits 58:34). */ +#define VTD_BF_CCMD_REG_RSVD_58_34_SHIFT 34 +#define VTD_BF_CCMD_REG_RSVD_58_34_MASK UINT64_C(0x07fffffc00000000) +/** CAIG: Context Actual Invalidation Granularity. */ +#define VTD_BF_CCMD_REG_CAIG_SHIFT 59 +#define VTD_BF_CCMD_REG_CAIG_MASK UINT64_C(0x1800000000000000) +/** CIRG: Context Invalidation Request Granularity. */ +#define VTD_BF_CCMD_REG_CIRG_SHIFT 61 +#define VTD_BF_CCMD_REG_CIRG_MASK UINT64_C(0x6000000000000000) +/** ICC: Invalidation Context Cache. */ +#define VTD_BF_CCMD_REG_ICC_SHIFT 63 +#define VTD_BF_CCMD_REG_ICC_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_CCMD_REG_, UINT64_C(0), UINT64_MAX, + (DID, SID, FM, RSVD_58_34, CAIG, CIRG, ICC)); + +/** RW: Read/write mask. */ +#define VTD_CCMD_REG_RW_MASK ( VTD_BF_CCMD_REG_DID_MASK | VTD_BF_CCMD_REG_SID_MASK \ + | VTD_BF_CCMD_REG_FM_MASK | VTD_BF_CCMD_REG_CIRG_MASK \ + | VTD_BF_CCMD_REG_ICC_MASK) +/** @} */ + + +/** @name IOTLB Invalidation Register (IOTLB_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 31:0). */ +#define VTD_BF_IOTLB_REG_RSVD_31_0_SHIFT 0 +#define VTD_BF_IOTLB_REG_RSVD_31_0_MASK UINT64_C(0x00000000ffffffff) +/** DID: Domain-ID. */ +#define VTD_BF_IOTLB_REG_DID_SHIFT 32 +#define VTD_BF_IOTLB_REG_DID_MASK UINT64_C(0x0000ffff00000000) +/** DW: Draining Writes. */ +#define VTD_BF_IOTLB_REG_DW_SHIFT 48 +#define VTD_BF_IOTLB_REG_DW_MASK UINT64_C(0x0001000000000000) +/** DR: Draining Reads. */ +#define VTD_BF_IOTLB_REG_DR_SHIFT 49 +#define VTD_BF_IOTLB_REG_DR_MASK UINT64_C(0x0002000000000000) +/** R: Reserved (bits 56:50). */ +#define VTD_BF_IOTLB_REG_RSVD_56_50_SHIFT 50 +#define VTD_BF_IOTLB_REG_RSVD_56_50_MASK UINT64_C(0x01fc000000000000) +/** IAIG: IOTLB Actual Invalidation Granularity. */ +#define VTD_BF_IOTLB_REG_IAIG_SHIFT 57 +#define VTD_BF_IOTLB_REG_IAIG_MASK UINT64_C(0x0600000000000000) +/** R: Reserved (bit 59). */ +#define VTD_BF_IOTLB_REG_RSVD_59_SHIFT 59 +#define VTD_BF_IOTLB_REG_RSVD_59_MASK UINT64_C(0x0800000000000000) +/** IIRG: IOTLB Invalidation Request Granularity. */ +#define VTD_BF_IOTLB_REG_IIRG_SHIFT 60 +#define VTD_BF_IOTLB_REG_IIRG_MASK UINT64_C(0x3000000000000000) +/** R: Reserved (bit 62). */ +#define VTD_BF_IOTLB_REG_RSVD_62_SHIFT 62 +#define VTD_BF_IOTLB_REG_RSVD_62_MASK UINT64_C(0x4000000000000000) +/** IVT: Invalidate IOTLB. */ +#define VTD_BF_IOTLB_REG_IVT_SHIFT 63 +#define VTD_BF_IOTLB_REG_IVT_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IOTLB_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_31_0, DID, DW, DR, RSVD_56_50, IAIG, RSVD_59, IIRG, RSVD_62, IVT)); + +/** RW: Read/write mask. */ +#define VTD_IOTLB_REG_RW_MASK ( VTD_BF_IOTLB_REG_DID_MASK | VTD_BF_IOTLB_REG_DW_MASK \ + | VTD_BF_IOTLB_REG_DR_MASK | VTD_BF_IOTLB_REG_IIRG_MASK \ + | VTD_BF_IOTLB_REG_IVT_MASK) +/** @} */ + + +/** @name Invalidate Address Register (IVA_REG). + * In accordance with the Intel spec. + * @{ */ +/** AM: Address Mask. */ +#define VTD_BF_IVA_REG_AM_SHIFT 0 +#define VTD_BF_IVA_REG_AM_MASK UINT64_C(0x000000000000003f) +/** IH: Invalidation Hint. */ +#define VTD_BF_IVA_REG_IH_SHIFT 6 +#define VTD_BF_IVA_REG_IH_MASK UINT64_C(0x0000000000000040) +/** R: Reserved (bits 11:7). */ +#define VTD_BF_IVA_REG_RSVD_11_7_SHIFT 7 +#define VTD_BF_IVA_REG_RSVD_11_7_MASK UINT64_C(0x0000000000000f80) +/** ADDR: Address. */ +#define VTD_BF_IVA_REG_ADDR_SHIFT 12 +#define VTD_BF_IVA_REG_ADDR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IVA_REG_, UINT64_C(0), UINT64_MAX, + (AM, IH, RSVD_11_7, ADDR)); + +/** RW: Read/write mask. */ +#define VTD_IVA_REG_RW_MASK ( VTD_BF_IVA_REG_AM_MASK | VTD_BF_IVA_REG_IH_MASK \ + | VTD_BF_IVA_REG_ADDR_MASK) +/** @} */ + + +/** @name Fault Status Register (FSTS_REG). + * In accordance with the Intel spec. + * @{ */ +/** PFO: Primary Fault Overflow. */ +#define VTD_BF_FSTS_REG_PFO_SHIFT 0 +#define VTD_BF_FSTS_REG_PFO_MASK UINT32_C(0x00000001) +/** PPF: Primary Pending Fault. */ +#define VTD_BF_FSTS_REG_PPF_SHIFT 1 +#define VTD_BF_FSTS_REG_PPF_MASK UINT32_C(0x00000002) +/** AFO: Advanced Fault Overflow. */ +#define VTD_BF_FSTS_REG_AFO_SHIFT 2 +#define VTD_BF_FSTS_REG_AFO_MASK UINT32_C(0x00000004) +/** APF: Advanced Pending Fault. */ +#define VTD_BF_FSTS_REG_APF_SHIFT 3 +#define VTD_BF_FSTS_REG_APF_MASK UINT32_C(0x00000008) +/** IQE: Invalidation Queue Error. */ +#define VTD_BF_FSTS_REG_IQE_SHIFT 4 +#define VTD_BF_FSTS_REG_IQE_MASK UINT32_C(0x00000010) +/** ICE: Invalidation Completion Error. */ +#define VTD_BF_FSTS_REG_ICE_SHIFT 5 +#define VTD_BF_FSTS_REG_ICE_MASK UINT32_C(0x00000020) +/** ITE: Invalidation Timeout Error. */ +#define VTD_BF_FSTS_REG_ITE_SHIFT 6 +#define VTD_BF_FSTS_REG_ITE_MASK UINT32_C(0x00000040) +/** DEP: Deprecated MBZ. Reserved (bit 7). */ +#define VTD_BF_FSTS_REG_RSVD_7_SHIFT 7 +#define VTD_BF_FSTS_REG_RSVD_7_MASK UINT32_C(0x00000080) +/** FRI: Fault Record Index. */ +#define VTD_BF_FSTS_REG_FRI_SHIFT 8 +#define VTD_BF_FSTS_REG_FRI_MASK UINT32_C(0x0000ff00) +/** R: Reserved (bits 31:16). */ +#define VTD_BF_FSTS_REG_RSVD_31_16_SHIFT 16 +#define VTD_BF_FSTS_REG_RSVD_31_16_MASK UINT32_C(0xffff0000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_FSTS_REG_, UINT32_C(0), UINT32_MAX, + (PFO, PPF, AFO, APF, IQE, ICE, ITE, RSVD_7, FRI, RSVD_31_16)); + +/** RW: Read/write mask. */ +#define VTD_FSTS_REG_RW_MASK ( VTD_BF_FSTS_REG_PFO_MASK | VTD_BF_FSTS_REG_AFO_MASK \ + | VTD_BF_FSTS_REG_APF_MASK | VTD_BF_FSTS_REG_IQE_MASK \ + | VTD_BF_FSTS_REG_ICE_MASK | VTD_BF_FSTS_REG_ITE_MASK) +/** RW1C: Read-only-status, Write-1-to-clear status mask. */ +#define VTD_FSTS_REG_RW1C_MASK ( VTD_BF_FSTS_REG_PFO_MASK | VTD_BF_FSTS_REG_AFO_MASK \ + | VTD_BF_FSTS_REG_APF_MASK | VTD_BF_FSTS_REG_IQE_MASK \ + | VTD_BF_FSTS_REG_ICE_MASK | VTD_BF_FSTS_REG_ITE_MASK) +/** @} */ + + +/** @name Fault Event Control Register (FECTL_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 29:0). */ +#define VTD_BF_FECTL_REG_RSVD_29_0_SHIFT 0 +#define VTD_BF_FECTL_REG_RSVD_29_0_MASK UINT32_C(0x3fffffff) +/** IP: Interrupt Pending. */ +#define VTD_BF_FECTL_REG_IP_SHIFT 30 +#define VTD_BF_FECTL_REG_IP_MASK UINT32_C(0x40000000) +/** IM: Interrupt Mask. */ +#define VTD_BF_FECTL_REG_IM_SHIFT 31 +#define VTD_BF_FECTL_REG_IM_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_FECTL_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_29_0, IP, IM)); + +/** RW: Read/write mask. */ +#define VTD_FECTL_REG_RW_MASK VTD_BF_FECTL_REG_IM_MASK +/** @} */ + + +/** @name Fault Event Data Register (FEDATA_REG). + * In accordance with the Intel spec. + * @{ */ +/** IMD: Interrupt Message Data. */ +#define VTD_BF_FEDATA_REG_IMD_SHIFT 0 +#define VTD_BF_FEDATA_REG_IMD_MASK UINT32_C(0x0000ffff) +/** R: Reserved (bits 31:16). VT-d specs. prior to 2021 had EIMD here. */ +#define VTD_BF_FEDATA_REG_RSVD_31_16_SHIFT 16 +#define VTD_BF_FEDATA_REG_RSVD_31_16_MASK UINT32_C(0xffff0000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_FEDATA_REG_, UINT32_C(0), UINT32_MAX, + (IMD, RSVD_31_16)); + +/** RW: Read/write mask, see 5.1.6 "Remapping Hardware Event Interrupt + * Programming". */ +#define VTD_FEDATA_REG_RW_MASK UINT32_C(0x000001ff) +/** @} */ + + +/** @name Fault Event Address Register (FEADDR_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 1:0). */ +#define VTD_BF_FEADDR_REG_RSVD_1_0_SHIFT 0 +#define VTD_BF_FEADDR_REG_RSVD_1_0_MASK UINT32_C(0x00000003) +/** MA: Message Address. */ +#define VTD_BF_FEADDR_REG_MA_SHIFT 2 +#define VTD_BF_FEADDR_REG_MA_MASK UINT32_C(0xfffffffc) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_FEADDR_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_1_0, MA)); + +/** RW: Read/write mask. */ +#define VTD_FEADDR_REG_RW_MASK VTD_BF_FEADDR_REG_MA_MASK +/** @} */ + + +/** @name Fault Event Upper Address Register (FEUADDR_REG). + * In accordance with the Intel spec. + * @{ */ +/** MUA: Message Upper Address. */ +#define VTD_BF_FEUADDR_REG_MA_SHIFT 0 +#define VTD_BF_FEUADDR_REG_MA_MASK UINT32_C(0xffffffff) + +/** RW: Read/write mask. */ +#define VTD_FEUADDR_REG_RW_MASK VTD_BF_FEUADDR_REG_MA_MASK +/** @} */ + + +/** @name Fault Recording Register (FRCD_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 11:0). */ +#define VTD_BF_0_FRCD_REG_RSVD_11_0_SHIFT 0 +#define VTD_BF_0_FRCD_REG_RSVD_11_0_MASK UINT64_C(0x0000000000000fff) +/** FI: Fault Info. */ +#define VTD_BF_0_FRCD_REG_FI_SHIFT 12 +#define VTD_BF_0_FRCD_REG_FI_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_FRCD_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_11_0, FI)); + +/** SID: Source Identifier. */ +#define VTD_BF_1_FRCD_REG_SID_SHIFT 0 +#define VTD_BF_1_FRCD_REG_SID_MASK UINT64_C(0x000000000000ffff) +/** R: Reserved (bits 27:16). */ +#define VTD_BF_1_FRCD_REG_RSVD_27_16_SHIFT 16 +#define VTD_BF_1_FRCD_REG_RSVD_27_16_MASK UINT64_C(0x000000000fff0000) +/** T2: Type bit 2. */ +#define VTD_BF_1_FRCD_REG_T2_SHIFT 28 +#define VTD_BF_1_FRCD_REG_T2_MASK UINT64_C(0x0000000010000000) +/** PRIV: Privilege Mode. */ +#define VTD_BF_1_FRCD_REG_PRIV_SHIFT 29 +#define VTD_BF_1_FRCD_REG_PRIV_MASK UINT64_C(0x0000000020000000) +/** EXE: Execute Permission Requested. */ +#define VTD_BF_1_FRCD_REG_EXE_SHIFT 30 +#define VTD_BF_1_FRCD_REG_EXE_MASK UINT64_C(0x0000000040000000) +/** PP: PASID Present. */ +#define VTD_BF_1_FRCD_REG_PP_SHIFT 31 +#define VTD_BF_1_FRCD_REG_PP_MASK UINT64_C(0x0000000080000000) +/** FR: Fault Reason. */ +#define VTD_BF_1_FRCD_REG_FR_SHIFT 32 +#define VTD_BF_1_FRCD_REG_FR_MASK UINT64_C(0x000000ff00000000) +/** PV: PASID Value. */ +#define VTD_BF_1_FRCD_REG_PV_SHIFT 40 +#define VTD_BF_1_FRCD_REG_PV_MASK UINT64_C(0x0fffff0000000000) +/** AT: Address Type. */ +#define VTD_BF_1_FRCD_REG_AT_SHIFT 60 +#define VTD_BF_1_FRCD_REG_AT_MASK UINT64_C(0x3000000000000000) +/** T1: Type bit 1. */ +#define VTD_BF_1_FRCD_REG_T1_SHIFT 62 +#define VTD_BF_1_FRCD_REG_T1_MASK UINT64_C(0x4000000000000000) +/** F: Fault. */ +#define VTD_BF_1_FRCD_REG_F_SHIFT 63 +#define VTD_BF_1_FRCD_REG_F_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_FRCD_REG_, UINT64_C(0), UINT64_MAX, + (SID, RSVD_27_16, T2, PRIV, EXE, PP, FR, PV, AT, T1, F)); + +/** RW: Read/write mask. */ +#define VTD_FRCD_REG_LO_RW_MASK UINT64_C(0) +#define VTD_FRCD_REG_HI_RW_MASK VTD_BF_1_FRCD_REG_F_MASK +/** RW1C: Read-only-status, Write-1-to-clear status mask. */ +#define VTD_FRCD_REG_LO_RW1C_MASK UINT64_C(0) +#define VTD_FRCD_REG_HI_RW1C_MASK VTD_BF_1_FRCD_REG_F_MASK +/** @} */ + + +/** + * VT-d faulted address translation request types (FRCD_REG::T2). + * In accordance with the Intel spec. + */ +typedef enum VTDREQTYPE +{ + VTDREQTYPE_WRITE = 0, /**< Memory access write request. */ + VTDREQTYPE_PAGE, /**< Page translation request. */ + VTDREQTYPE_READ, /**< Memory access read request. */ + VTDREQTYPE_ATOMIC_OP /**< Memory access atomic operation. */ +} VTDREQTYPE; +/** Pointer to a VTDREQTYPE. */ +typedef VTDREQTYPE *PVTDREQTYPE; + + +/** @name Advanced Fault Log Register (AFLOG_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 8:0). */ +#define VTD_BF_0_AFLOG_REG_RSVD_8_0_SHIFT 0 +#define VTD_BF_0_AFLOG_REG_RSVD_8_0_MASK UINT64_C(0x00000000000001ff) +/** FLS: Fault Log Size. */ +#define VTD_BF_0_AFLOG_REG_FLS_SHIFT 9 +#define VTD_BF_0_AFLOG_REG_FLS_MASK UINT64_C(0x0000000000000e00) +/** FLA: Fault Log Address. */ +#define VTD_BF_0_AFLOG_REG_FLA_SHIFT 12 +#define VTD_BF_0_AFLOG_REG_FLA_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_AFLOG_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_8_0, FLS, FLA)); + +/** RW: Read/write mask. */ +#define VTD_AFLOG_REG_RW_MASK (VTD_BF_0_AFLOG_REG_FLS_MASK | VTD_BF_0_AFLOG_REG_FLA_MASK) +/** @} */ + + +/** @name Protected Memory Enable Register (PMEN_REG). + * In accordance with the Intel spec. + * @{ */ +/** PRS: Protected Region Status. */ +#define VTD_BF_PMEN_REG_PRS_SHIFT 0 +#define VTD_BF_PMEN_REG_PRS_MASK UINT32_C(0x00000001) +/** R: Reserved (bits 30:1). */ +#define VTD_BF_PMEN_REG_RSVD_30_1_SHIFT 1 +#define VTD_BF_PMEN_REG_RSVD_30_1_MASK UINT32_C(0x7ffffffe) +/** EPM: Enable Protected Memory. */ +#define VTD_BF_PMEN_REG_EPM_SHIFT 31 +#define VTD_BF_PMEN_REG_EPM_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PMEN_REG_, UINT32_C(0), UINT32_MAX, + (PRS, RSVD_30_1, EPM)); + +/** RW: Read/write mask. */ +#define VTD_PMEN_REG_RW_MASK VTD_BF_PMEN_REG_EPM_MASK +/** @} */ + + +/** @name Invalidation Queue Head Register (IQH_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 3:0). */ +#define VTD_BF_IQH_REG_RSVD_3_0_SHIFT 0 +#define VTD_BF_IQH_REG_RSVD_3_0_MASK UINT64_C(0x000000000000000f) +/** QH: Queue Head. */ +#define VTD_BF_IQH_REG_QH_SHIFT 4 +#define VTD_BF_IQH_REG_QH_MASK UINT64_C(0x000000000007fff0) +/** R: Reserved (bits 63:19). */ +#define VTD_BF_IQH_REG_RSVD_63_19_SHIFT 19 +#define VTD_BF_IQH_REG_RSVD_63_19_MASK UINT64_C(0xfffffffffff80000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IQH_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_3_0, QH, RSVD_63_19)); + +/** RW: Read/write mask. */ +#define VTD_IQH_REG_RW_MASK UINT64_C(0x0) +/** @} */ + + +/** @name Invalidation Queue Tail Register (IQT_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 3:0). */ +#define VTD_BF_IQT_REG_RSVD_3_0_SHIFT 0 +#define VTD_BF_IQT_REG_RSVD_3_0_MASK UINT64_C(0x000000000000000f) +/** QH: Queue Tail. */ +#define VTD_BF_IQT_REG_QT_SHIFT 4 +#define VTD_BF_IQT_REG_QT_MASK UINT64_C(0x000000000007fff0) +/** R: Reserved (bits 63:19). */ +#define VTD_BF_IQT_REG_RSVD_63_19_SHIFT 19 +#define VTD_BF_IQT_REG_RSVD_63_19_MASK UINT64_C(0xfffffffffff80000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IQT_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_3_0, QT, RSVD_63_19)); + +/** RW: Read/write mask. */ +#define VTD_IQT_REG_RW_MASK VTD_BF_IQT_REG_QT_MASK +/** @} */ + + +/** @name Invalidation Queue Address Register (IQA_REG). + * In accordance with the Intel spec. + * @{ */ +/** QS: Queue Size. */ +#define VTD_BF_IQA_REG_QS_SHIFT 0 +#define VTD_BF_IQA_REG_QS_MASK UINT64_C(0x0000000000000007) +/** R: Reserved (bits 10:3). */ +#define VTD_BF_IQA_REG_RSVD_10_3_SHIFT 3 +#define VTD_BF_IQA_REG_RSVD_10_3_MASK UINT64_C(0x00000000000007f8) +/** DW: Descriptor Width. */ +#define VTD_BF_IQA_REG_DW_SHIFT 11 +#define VTD_BF_IQA_REG_DW_MASK UINT64_C(0x0000000000000800) +/** IQA: Invalidation Queue Base Address. */ +#define VTD_BF_IQA_REG_IQA_SHIFT 12 +#define VTD_BF_IQA_REG_IQA_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IQA_REG_, UINT64_C(0), UINT64_MAX, + (QS, RSVD_10_3, DW, IQA)); + +/** RW: Read/write mask. */ +#define VTD_IQA_REG_RW_MASK ( VTD_BF_IQA_REG_QS_MASK | VTD_BF_IQA_REG_DW_MASK \ + | VTD_BF_IQA_REG_IQA_MASK) +/** DW: 128-bit descriptor. */ +#define VTD_IQA_REG_DW_128_BIT 0 +/** DW: 256-bit descriptor. */ +#define VTD_IQA_REG_DW_256_BIT 1 +/** @} */ + + +/** @name Invalidation Completion Status Register (ICS_REG). + * In accordance with the Intel spec. + * @{ */ +/** IWC: Invalidation Wait Descriptor Complete. */ +#define VTD_BF_ICS_REG_IWC_SHIFT 0 +#define VTD_BF_ICS_REG_IWC_MASK UINT32_C(0x00000001) +/** R: Reserved (bits 31:1). */ +#define VTD_BF_ICS_REG_RSVD_31_1_SHIFT 1 +#define VTD_BF_ICS_REG_RSVD_31_1_MASK UINT32_C(0xfffffffe) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_ICS_REG_, UINT32_C(0), UINT32_MAX, + (IWC, RSVD_31_1)); + +/** RW: Read/write mask. */ +#define VTD_ICS_REG_RW_MASK VTD_BF_ICS_REG_IWC_MASK +/** RW1C: Read-only-status, Write-1-to-clear status mask. */ +#define VTD_ICS_REG_RW1C_MASK VTD_BF_ICS_REG_IWC_MASK +/** @} */ + + +/** @name Invalidation Event Control Register (IECTL_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 29:0). */ +#define VTD_BF_IECTL_REG_RSVD_29_0_SHIFT 0 +#define VTD_BF_IECTL_REG_RSVD_29_0_MASK UINT32_C(0x3fffffff) +/** IP: Interrupt Pending. */ +#define VTD_BF_IECTL_REG_IP_SHIFT 30 +#define VTD_BF_IECTL_REG_IP_MASK UINT32_C(0x40000000) +/** IM: Interrupt Mask. */ +#define VTD_BF_IECTL_REG_IM_SHIFT 31 +#define VTD_BF_IECTL_REG_IM_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IECTL_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_29_0, IP, IM)); + +/** RW: Read/write mask. */ +#define VTD_IECTL_REG_RW_MASK VTD_BF_IECTL_REG_IM_MASK +/** @} */ + + +/** @name Invalidation Event Data Register (IEDATA_REG). + * In accordance with the Intel spec. + * @{ */ +/** IMD: Interrupt Message Data. */ +#define VTD_BF_IEDATA_REG_IMD_SHIFT 0 +#define VTD_BF_IEDATA_REG_IMD_MASK UINT32_C(0x0000ffff) +/** R: Reserved (bits 31:16). VT-d specs. prior to 2021 had EIMD here. */ +#define VTD_BF_IEDATA_REG_RSVD_31_16_SHIFT 16 +#define VTD_BF_IEDATA_REG_RSVD_31_16_MASK UINT32_C(0xffff0000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IEDATA_REG_, UINT32_C(0), UINT32_MAX, + (IMD, RSVD_31_16)); + +/** RW: Read/write mask, see 5.1.6 "Remapping Hardware Event Interrupt + * Programming". */ +#define VTD_IEDATA_REG_RW_MASK UINT32_C(0x000001ff) +/** @} */ + + +/** @name Invalidation Event Address Register (IEADDR_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 1:0). */ +#define VTD_BF_IEADDR_REG_RSVD_1_0_SHIFT 0 +#define VTD_BF_IEADDR_REG_RSVD_1_0_MASK UINT32_C(0x00000003) +/** MA: Message Address. */ +#define VTD_BF_IEADDR_REG_MA_SHIFT 2 +#define VTD_BF_IEADDR_REG_MA_MASK UINT32_C(0xfffffffc) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IEADDR_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_1_0, MA)); + +/** RW: Read/write mask. */ +#define VTD_IEADDR_REG_RW_MASK VTD_BF_IEADDR_REG_MA_MASK +/** @} */ + + +/** @name Invalidation Event Upper Address Register (IEUADDR_REG). + * @{ */ +/** MUA: Message Upper Address. */ +#define VTD_BF_IEUADDR_REG_MUA_SHIFT 0 +#define VTD_BF_IEUADDR_REG_MUA_MASK UINT32_C(0xffffffff) + +/** RW: Read/write mask. */ +#define VTD_IEUADDR_REG_RW_MASK VTD_BF_IEUADDR_REG_MUA_MASK +/** @} */ + + +/** @name Invalidation Queue Error Record Register (IQERCD_REG). + * In accordance with the Intel spec. + * @{ */ +/** IQEI: Invalidation Queue Error Info. */ +#define VTD_BF_IQERCD_REG_IQEI_SHIFT 0 +#define VTD_BF_IQERCD_REG_IQEI_MASK UINT64_C(0x000000000000000f) +/** R: Reserved (bits 31:4). */ +#define VTD_BF_IQERCD_REG_RSVD_31_4_SHIFT 4 +#define VTD_BF_IQERCD_REG_RSVD_31_4_MASK UINT64_C(0x00000000fffffff0) +/** ITESID: Invalidation Timeout Error Source Identifier. */ +#define VTD_BF_IQERCD_REG_ITESID_SHIFT 32 +#define VTD_BF_IQERCD_REG_ITESID_MASK UINT64_C(0x0000ffff00000000) +/** ICESID: Invalidation Completion Error Source Identifier. */ +#define VTD_BF_IQERCD_REG_ICESID_SHIFT 48 +#define VTD_BF_IQERCD_REG_ICESID_MASK UINT64_C(0xffff000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IQERCD_REG_, UINT64_C(0), UINT64_MAX, + (IQEI, RSVD_31_4, ITESID, ICESID)); + +/** RW: Read/write mask. */ +#define VTD_IQERCD_REG_RW_MASK UINT64_C(0) + +/** Invalidation Queue Error Information. */ +typedef enum VTDIQEI +{ + VTDIQEI_INFO_NOT_AVAILABLE, + VTDIQEI_INVALID_TAIL_PTR, + VTDIQEI_FETCH_DESCRIPTOR_ERR, + VTDIQEI_INVALID_DESCRIPTOR_TYPE, + VTDIQEI_RSVD_FIELD_VIOLATION, + VTDIQEI_INVALID_DESCRIPTOR_WIDTH, + VTDIQEI_QUEUE_TAIL_MISALIGNED, + VTDIQEI_INVALID_TTM +} VTDIQEI; +/** @} */ + + +/** @name Interrupt Remapping Table Address Register (IRTA_REG). + * In accordance with the Intel spec. + * @{ */ +/** S: Size. */ +#define VTD_BF_IRTA_REG_S_SHIFT 0 +#define VTD_BF_IRTA_REG_S_MASK UINT64_C(0x000000000000000f) +/** R: Reserved (bits 10:4). */ +#define VTD_BF_IRTA_REG_RSVD_10_4_SHIFT 4 +#define VTD_BF_IRTA_REG_RSVD_10_4_MASK UINT64_C(0x00000000000007f0) +/** EIME: Extended Interrupt Mode Enable. */ +#define VTD_BF_IRTA_REG_EIME_SHIFT 11 +#define VTD_BF_IRTA_REG_EIME_MASK UINT64_C(0x0000000000000800) +/** IRTA: Interrupt Remapping Table Address. */ +#define VTD_BF_IRTA_REG_IRTA_SHIFT 12 +#define VTD_BF_IRTA_REG_IRTA_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_IRTA_REG_, UINT64_C(0), UINT64_MAX, + (S, RSVD_10_4, EIME, IRTA)); + +/** RW: Read/write mask. */ +#define VTD_IRTA_REG_RW_MASK ( VTD_BF_IRTA_REG_S_MASK | VTD_BF_IRTA_REG_EIME_MASK \ + | VTD_BF_IRTA_REG_IRTA_MASK) +/** IRTA_REG: Get number of interrupt entries. */ +#define VTD_IRTA_REG_GET_ENTRY_COUNT(a) (UINT32_C(1) << (1 + ((a) & VTD_BF_IRTA_REG_S_MASK))) +/** @} */ + + +/** @name Page Request Queue Head Register (PQH_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 4:0). */ +#define VTD_BF_PQH_REG_RSVD_4_0_SHIFT 0 +#define VTD_BF_PQH_REG_RSVD_4_0_MASK UINT64_C(0x000000000000001f) +/** PQH: Page Queue Head. */ +#define VTD_BF_PQH_REG_PQH_SHIFT 5 +#define VTD_BF_PQH_REG_PQH_MASK UINT64_C(0x000000000007ffe0) +/** R: Reserved (bits 63:19). */ +#define VTD_BF_PQH_REG_RSVD_63_19_SHIFT 19 +#define VTD_BF_PQH_REG_RSVD_63_19_MASK UINT64_C(0xfffffffffff80000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PQH_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_4_0, PQH, RSVD_63_19)); + +/** RW: Read/write mask. */ +#define VTD_PQH_REG_RW_MASK VTD_BF_PQH_REG_PQH_MASK +/** @} */ + + +/** @name Page Request Queue Tail Register (PQT_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 4:0). */ +#define VTD_BF_PQT_REG_RSVD_4_0_SHIFT 0 +#define VTD_BF_PQT_REG_RSVD_4_0_MASK UINT64_C(0x000000000000001f) +/** PQT: Page Queue Tail. */ +#define VTD_BF_PQT_REG_PQT_SHIFT 5 +#define VTD_BF_PQT_REG_PQT_MASK UINT64_C(0x000000000007ffe0) +/** R: Reserved (bits 63:19). */ +#define VTD_BF_PQT_REG_RSVD_63_19_SHIFT 19 +#define VTD_BF_PQT_REG_RSVD_63_19_MASK UINT64_C(0xfffffffffff80000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PQT_REG_, UINT64_C(0), UINT64_MAX, + (RSVD_4_0, PQT, RSVD_63_19)); + +/** RW: Read/write mask. */ +#define VTD_PQT_REG_RW_MASK VTD_BF_PQT_REG_PQT_MASK +/** @} */ + + +/** @name Page Request Queue Address Register (PQA_REG). + * In accordance with the Intel spec. + * @{ */ +/** PQS: Page Queue Size. */ +#define VTD_BF_PQA_REG_PQS_SHIFT 0 +#define VTD_BF_PQA_REG_PQS_MASK UINT64_C(0x0000000000000007) +/** R: Reserved bits (11:3). */ +#define VTD_BF_PQA_REG_RSVD_11_3_SHIFT 3 +#define VTD_BF_PQA_REG_RSVD_11_3_MASK UINT64_C(0x0000000000000ff8) +/** PQA: Page Request Queue Base Address. */ +#define VTD_BF_PQA_REG_PQA_SHIFT 12 +#define VTD_BF_PQA_REG_PQA_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PQA_REG_, UINT64_C(0), UINT64_MAX, + (PQS, RSVD_11_3, PQA)); + +/** RW: Read/write mask. */ +#define VTD_PQA_REG_RW_MASK (VTD_BF_PQA_REG_PQS_MASK | VTD_BF_PQA_REG_PQA_MASK) +/** @} */ + + +/** @name Page Request Status Register (PRS_REG). + * In accordance with the Intel spec. + * @{ */ +/** PPR: Pending Page Request. */ +#define VTD_BF_PRS_REG_PPR_SHIFT 0 +#define VTD_BF_PRS_REG_PPR_MASK UINT64_C(0x00000001) +/** PRO: Page Request Overflow. */ +#define VTD_BF_PRS_REG_PRO_SHIFT 1 +#define VTD_BF_PRS_REG_PRO_MASK UINT64_C(0x00000002) +/** R: Reserved (bits 31:2). */ +#define VTD_BF_PRS_REG_RSVD_31_2_SHIFT 2 +#define VTD_BF_PRS_REG_RSVD_31_2_MASK UINT64_C(0xfffffffc) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PRS_REG_, UINT32_C(0), UINT32_MAX, + (PPR, PRO, RSVD_31_2)); + +/** RW: Read/write mask. */ +#define VTD_PRS_REG_RW_MASK (VTD_BF_PRS_REG_PPR_MASK | VTD_BF_PRS_REG_PRO_MASK) +/** RW1C: Read-only-status, Write-1-to-clear status mask. */ +#define VTD_PRS_REG_RW1C_MASK (VTD_BF_PRS_REG_PPR_MASK | VTD_BF_PRS_REG_PRO_MASK) +/** @} */ + + +/** @name Page Request Event Control Register (PECTL_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 29:0). */ +#define VTD_BF_PECTL_REG_RSVD_29_0_SHIFT 0 +#define VTD_BF_PECTL_REG_RSVD_29_0_MASK UINT32_C(0x3fffffff) +/** IP: Interrupt Pending. */ +#define VTD_BF_PECTL_REG_IP_SHIFT 30 +#define VTD_BF_PECTL_REG_IP_MASK UINT32_C(0x40000000) +/** IM: Interrupt Mask. */ +#define VTD_BF_PECTL_REG_IM_SHIFT 31 +#define VTD_BF_PECTL_REG_IM_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PECTL_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_29_0, IP, IM)); + +/** RW: Read/write mask. */ +#define VTD_PECTL_REG_RW_MASK VTD_BF_PECTL_REG_IM_MASK +/** @} */ + + +/** @name Page Request Event Data Register (PEDATA_REG). + * In accordance with the Intel spec. + * @{ */ +/** IMD: Interrupt Message Data. */ +#define VTD_BF_PEDATA_REG_IMD_SHIFT 0 +#define VTD_BF_PEDATA_REG_IMD_MASK UINT32_C(0x0000ffff) +/** R: Reserved (bits 31:16). VT-d specs. prior to 2021 had EIMD here. */ +#define VTD_BF_PEDATA_REG_RSVD_31_16_SHIFT 16 +#define VTD_BF_PEDATA_REG_RSVD_31_16_MASK UINT32_C(0xffff0000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PEDATA_REG_, UINT32_C(0), UINT32_MAX, + (IMD, RSVD_31_16)); + +/** RW: Read/write mask, see 5.1.6 "Remapping Hardware Event Interrupt + * Programming". */ +#define VTD_PEDATA_REG_RW_MASK UINT32_C(0x000001ff) +/** @} */ + + +/** @name Page Request Event Address Register (PEADDR_REG). + * In accordance with the Intel spec. + * @{ */ +/** R: Reserved (bits 1:0). */ +#define VTD_BF_PEADDR_REG_RSVD_1_0_SHIFT 0 +#define VTD_BF_PEADDR_REG_RSVD_1_0_MASK UINT32_C(0x00000003) +/** MA: Message Address. */ +#define VTD_BF_PEADDR_REG_MA_SHIFT 2 +#define VTD_BF_PEADDR_REG_MA_MASK UINT32_C(0xfffffffc) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_PEADDR_REG_, UINT32_C(0), UINT32_MAX, + (RSVD_1_0, MA)); + +/** RW: Read/write mask. */ +#define VTD_PEADDR_REG_RW_MASK VTD_BF_PEADDR_REG_MA_MASK +/** @} */ + + + +/** @name Page Request Event Upper Address Register (PEUADDR_REG). + * In accordance with the Intel spec. + * @{ */ +/** MA: Message Address. */ +#define VTD_BF_PEUADDR_REG_MUA_SHIFT 0 +#define VTD_BF_PEUADDR_REG_MUA_MASK UINT32_C(0xffffffff) + +/** RW: Read/write mask. */ +#define VTD_PEUADDR_REG_RW_MASK VTD_BF_PEUADDR_REG_MUA_MASK +/** @} */ + + +/** @name MTRR Capability Register (MTRRCAP_REG). + * In accordance with the Intel spec. + * @{ */ +/** VCNT: Variable MTRR Count. */ +#define VTD_BF_MTRRCAP_REG_VCNT_SHIFT 0 +#define VTD_BF_MTRRCAP_REG_VCNT_MASK UINT64_C(0x00000000000000ff) +/** FIX: Fixed range MTRRs Supported. */ +#define VTD_BF_MTRRCAP_REG_FIX_SHIFT 8 +#define VTD_BF_MTRRCAP_REG_FIX_MASK UINT64_C(0x0000000000000100) +/** R: Reserved (bit 9). */ +#define VTD_BF_MTRRCAP_REG_RSVD_9_SHIFT 9 +#define VTD_BF_MTRRCAP_REG_RSVD_9_MASK UINT64_C(0x0000000000000200) +/** WC: Write Combining. */ +#define VTD_BF_MTRRCAP_REG_WC_SHIFT 10 +#define VTD_BF_MTRRCAP_REG_WC_MASK UINT64_C(0x0000000000000400) +/** R: Reserved (bits 63:11). */ +#define VTD_BF_MTRRCAP_REG_RSVD_63_11_SHIFT 11 +#define VTD_BF_MTRRCAP_REG_RSVD_63_11_MASK UINT64_C(0xfffffffffffff800) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_MTRRCAP_REG_, UINT64_C(0), UINT64_MAX, + (VCNT, FIX, RSVD_9, WC, RSVD_63_11)); + +/** RW: Read/write mask. */ +#define VTD_MTRRCAP_REG_RW_MASK UINT64_C(0) +/** @} */ + + +/** @name MTRR Default Type Register (MTRRDEF_REG). + * In accordance with the Intel spec. + * @{ */ +/** TYPE: Default Memory Type. */ +#define VTD_BF_MTRRDEF_REG_TYPE_SHIFT 0 +#define VTD_BF_MTRRDEF_REG_TYPE_MASK UINT64_C(0x00000000000000ff) +/** R: Reserved (bits 9:8). */ +#define VTD_BF_MTRRDEF_REG_RSVD_9_8_SHIFT 8 +#define VTD_BF_MTRRDEF_REG_RSVD_9_8_MASK UINT64_C(0x0000000000000300) +/** FE: Fixed Range MTRR Enable. */ +#define VTD_BF_MTRRDEF_REG_FE_SHIFT 10 +#define VTD_BF_MTRRDEF_REG_FE_MASK UINT64_C(0x0000000000000400) +/** E: MTRR Enable. */ +#define VTD_BF_MTRRDEF_REG_E_SHIFT 11 +#define VTD_BF_MTRRDEF_REG_E_MASK UINT64_C(0x0000000000000800) +/** R: Reserved (bits 63:12). */ +#define VTD_BF_MTRRDEF_REG_RSVD_63_12_SHIFT 12 +#define VTD_BF_MTRRDEF_REG_RSVD_63_12_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_MTRRDEF_REG_, UINT64_C(0), UINT64_MAX, + (TYPE, RSVD_9_8, FE, E, RSVD_63_12)); + +/** RW: Read/write mask. */ +#define VTD_MTRRDEF_REG_RW_MASK ( VTD_BF_MTRRDEF_REG_TYPE_MASK | VTD_BF_MTRRDEF_REG_FE_MASK \ + | VTD_BF_MTRRDEF_REG_E_MASK) +/** @} */ + + +/** @name Virtual Command Capability Register (VCCAP_REG). + * In accordance with the Intel spec. + * @{ */ +/** PAS: PASID Support. */ +#define VTD_BF_VCCAP_REG_PAS_SHIFT 0 +#define VTD_BF_VCCAP_REG_PAS_MASK UINT64_C(0x0000000000000001) +/** R: Reserved (bits 63:1). */ +#define VTD_BF_VCCAP_REG_RSVD_63_1_SHIFT 1 +#define VTD_BF_VCCAP_REG_RSVD_63_1_MASK UINT64_C(0xfffffffffffffffe) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_VCCAP_REG_, UINT64_C(0), UINT64_MAX, + (PAS, RSVD_63_1)); + +/** RW: Read/write mask. */ +#define VTD_VCCAP_REG_RW_MASK UINT64_C(0) +/** @} */ + + +/** @name Virtual Command Extended Operand Register (VCMD_EO_REG). + * In accordance with the Intel spec. + * @{ */ +/** OB: Operand B. */ +#define VTD_BF_VCMD_EO_REG_OB_SHIFT 0 +#define VTD_BF_VCMD_EO_REG_OB_MASK UINT32_C(0xffffffffffffffff) + +/** RW: Read/write mask. */ +#define VTD_VCMD_EO_REG_RW_MASK VTD_BF_VCMD_EO_REG_OB_MASK +/** @} */ + + +/** @name Virtual Command Register (VCMD_REG). + * In accordance with the Intel spec. + * @{ */ +/** CMD: Command. */ +#define VTD_BF_VCMD_REG_CMD_SHIFT 0 +#define VTD_BF_VCMD_REG_CMD_MASK UINT64_C(0x00000000000000ff) +/** OP: Operand. */ +#define VTD_BF_VCMD_REG_OP_SHIFT 8 +#define VTD_BF_VCMD_REG_OP_MASK UINT64_C(0xffffffffffffff00) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_VCMD_REG_, UINT64_C(0), UINT64_MAX, + (CMD, OP)); + +/** RW: Read/write mask. */ +#define VTD_VCMD_REG_RW_MASK (VTD_BF_VCMD_REG_CMD_MASK | VTD_BF_VCMD_REG_OP_MASK) +/** @} */ + + +/** @name Virtual Command Response Register (VCRSP_REG). + * In accordance with the Intel spec. + * @{ */ +/** IP: In Progress. */ +#define VTD_BF_VCRSP_REG_IP_SHIFT 0 +#define VTD_BF_VCRSP_REG_IP_MASK UINT64_C(0x0000000000000001) +/** SC: Status Code. */ +#define VTD_BF_VCRSP_REG_SC_SHIFT 1 +#define VTD_BF_VCRSP_REG_SC_MASK UINT64_C(0x0000000000000006) +/** R: Reserved (bits 7:3). */ +#define VTD_BF_VCRSP_REG_RSVD_7_3_SHIFT 3 +#define VTD_BF_VCRSP_REG_RSVD_7_3_MASK UINT64_C(0x00000000000000f8) +/** RSLT: Result. */ +#define VTD_BF_VCRSP_REG_RSLT_SHIFT 8 +#define VTD_BF_VCRSP_REG_RSLT_MASK UINT64_C(0xffffffffffffff00) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_VCRSP_REG_, UINT64_C(0), UINT64_MAX, + (IP, SC, RSVD_7_3, RSLT)); + +/** RW: Read/write mask. */ +#define VTD_VCRSP_REG_RW_MASK UINT64_C(0) +/** @} */ + + +/** @name Generic Invalidation Descriptor. + * In accordance with the Intel spec. + * Non-reserved fields here are common to all invalidation descriptors. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_GENERIC_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_GENERIC_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** R: Reserved (bits 8:4). */ +#define VTD_BF_0_GENERIC_INV_DSC_RSVD_8_4_SHIFT 4 +#define VTD_BF_0_GENERIC_INV_DSC_RSVD_8_4_MASK UINT64_C(0x00000000000001f0) +/** Type (Hi). */ +#define VTD_BF_0_GENERIC_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_GENERIC_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 63:12). */ +#define VTD_BF_0_GENERIC_INV_DSC_RSVD_63_12_SHIFT 12 +#define VTD_BF_0_GENERIC_INV_DSC_RSVD_63_12_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_GENERIC_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, RSVD_8_4, TYPE_HI, RSVD_63_12)); + +/** GENERIC_INV_DSC: Type. */ +#define VTD_GENERIC_INV_DSC_GET_TYPE(a) ((((a) & VTD_BF_0_GENERIC_INV_DSC_TYPE_HI_MASK) >> 5) \ + | ((a) & VTD_BF_0_GENERIC_INV_DSC_TYPE_LO_MASK)) +/** @} */ + + +/** @name Context-Cache Invalidation Descriptor (cc_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_CC_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_CC_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** G: Granularity. */ +#define VTD_BF_0_CC_INV_DSC_G_SHIFT 4 +#define VTD_BF_0_CC_INV_DSC_G_MASK UINT64_C(0x0000000000000030) +/** R: Reserved (bits 8:6). */ +#define VTD_BF_0_CC_INV_DSC_RSVD_8_6_SHIFT 6 +#define VTD_BF_0_CC_INV_DSC_RSVD_8_6_MASK UINT64_C(0x00000000000001c0) +/** Type (Hi). */ +#define VTD_BF_0_CC_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_CC_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 15:12). */ +#define VTD_BF_0_CC_INV_DSC_RSVD_15_12_SHIFT 12 +#define VTD_BF_0_CC_INV_DSC_RSVD_15_12_MASK UINT64_C(0x000000000000f000) +/** DID: Domain Id. */ +#define VTD_BF_0_CC_INV_DSC_DID_SHIFT 16 +#define VTD_BF_0_CC_INV_DSC_DID_MASK UINT64_C(0x00000000ffff0000) +/** SID: Source Id. */ +#define VTD_BF_0_CC_INV_DSC_SID_SHIFT 32 +#define VTD_BF_0_CC_INV_DSC_SID_MASK UINT64_C(0x0000ffff00000000) +/** FM: Function Mask. */ +#define VTD_BF_0_CC_INV_DSC_FM_SHIFT 48 +#define VTD_BF_0_CC_INV_DSC_FM_MASK UINT64_C(0x0003000000000000) +/** R: Reserved (bits 63:50). */ +#define VTD_BF_0_CC_INV_DSC_RSVD_63_50_SHIFT 50 +#define VTD_BF_0_CC_INV_DSC_RSVD_63_50_MASK UINT64_C(0xfffc000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_CC_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, G, RSVD_8_6, TYPE_HI, RSVD_15_12, DID, SID, FM, RSVD_63_50)); +/** @} */ + + +/** @name PASID-Cache Invalidation Descriptor (pc_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_PC_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_PC_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** G: Granularity. */ +#define VTD_BF_0_PC_INV_DSC_G_SHIFT 4 +#define VTD_BF_0_PC_INV_DSC_G_MASK UINT64_C(0x0000000000000030) +/** R: Reserved (bits 8:6). */ +#define VTD_BF_0_PC_INV_DSC_RSVD_8_6_SHIFT 6 +#define VTD_BF_0_PC_INV_DSC_RSVD_8_6_MASK UINT64_C(0x00000000000001c0) +/** Type (Hi). */ +#define VTD_BF_0_PC_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_PC_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 15:12). */ +#define VTD_BF_0_PC_INV_DSC_RSVD_15_12_SHIFT 12 +#define VTD_BF_0_PC_INV_DSC_RSVD_15_12_MASK UINT64_C(0x000000000000f000) +/** DID: Domain Id. */ +#define VTD_BF_0_PC_INV_DSC_DID_SHIFT 16 +#define VTD_BF_0_PC_INV_DSC_DID_MASK UINT64_C(0x00000000ffff0000) +/** PASID: Process Address-Space Id. */ +#define VTD_BF_0_PC_INV_DSC_PASID_SHIFT 32 +#define VTD_BF_0_PC_INV_DSC_PASID_MASK UINT64_C(0x000fffff00000000) +/** R: Reserved (bits 63:52). */ +#define VTD_BF_0_PC_INV_DSC_RSVD_63_52_SHIFT 52 +#define VTD_BF_0_PC_INV_DSC_RSVD_63_52_MASK UINT64_C(0xfff0000000000000) + +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_PC_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, G, RSVD_8_6, TYPE_HI, RSVD_15_12, DID, PASID, RSVD_63_52)); +/** @} */ + + +/** @name IOTLB Invalidate Descriptor (iotlb_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_IOTLB_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_IOTLB_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** G: Granularity. */ +#define VTD_BF_0_IOTLB_INV_DSC_G_SHIFT 4 +#define VTD_BF_0_IOTLB_INV_DSC_G_MASK UINT64_C(0x0000000000000030) +/** DW: Drain Writes. */ +#define VTD_BF_0_IOTLB_INV_DSC_DW_SHIFT 6 +#define VTD_BF_0_IOTLB_INV_DSC_DW_MASK UINT64_C(0x0000000000000040) +/** DR: Drain Reads. */ +#define VTD_BF_0_IOTLB_INV_DSC_DR_SHIFT 7 +#define VTD_BF_0_IOTLB_INV_DSC_DR_MASK UINT64_C(0x0000000000000080) +/** R: Reserved (bit 8). */ +#define VTD_BF_0_IOTLB_INV_DSC_RSVD_8_SHIFT 8 +#define VTD_BF_0_IOTLB_INV_DSC_RSVD_8_MASK UINT64_C(0x0000000000000100) +/** Type (Hi). */ +#define VTD_BF_0_IOTLB_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_IOTLB_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 15:12). */ +#define VTD_BF_0_IOTLB_INV_DSC_RSVD_15_12_SHIFT 12 +#define VTD_BF_0_IOTLB_INV_DSC_RSVD_15_12_MASK UINT64_C(0x000000000000f000) +/** DID: Domain Id. */ +#define VTD_BF_0_IOTLB_INV_DSC_DID_SHIFT 16 +#define VTD_BF_0_IOTLB_INV_DSC_DID_MASK UINT64_C(0x00000000ffff0000) +/** R: Reserved (bits 63:32). */ +#define VTD_BF_0_IOTLB_INV_DSC_RSVD_63_32_SHIFT 32 +#define VTD_BF_0_IOTLB_INV_DSC_RSVD_63_32_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_IOTLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, G, DW, DR, RSVD_8, TYPE_HI, RSVD_15_12, DID, RSVD_63_32)); + +/** AM: Address Mask. */ +#define VTD_BF_1_IOTLB_INV_DSC_AM_SHIFT 0 +#define VTD_BF_1_IOTLB_INV_DSC_AM_MASK UINT64_C(0x000000000000003f) +/** IH: Invalidation Hint. */ +#define VTD_BF_1_IOTLB_INV_DSC_IH_SHIFT 6 +#define VTD_BF_1_IOTLB_INV_DSC_IH_MASK UINT64_C(0x0000000000000040) +/** R: Reserved (bits 11:7). */ +#define VTD_BF_1_IOTLB_INV_DSC_RSVD_11_7_SHIFT 7 +#define VTD_BF_1_IOTLB_INV_DSC_RSVD_11_7_MASK UINT64_C(0x0000000000000f80) +/** ADDR: Address. */ +#define VTD_BF_1_IOTLB_INV_DSC_ADDR_SHIFT 12 +#define VTD_BF_1_IOTLB_INV_DSC_ADDR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_IOTLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (AM, IH, RSVD_11_7, ADDR)); +/** @} */ + + +/** @name PASID-based IOTLB Invalidate Descriptor (p_iotlb_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_P_IOTLB_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_P_IOTLB_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** G: Granularity. */ +#define VTD_BF_0_P_IOTLB_INV_DSC_G_SHIFT 4 +#define VTD_BF_0_P_IOTLB_INV_DSC_G_MASK UINT64_C(0x0000000000000030) +/** R: Reserved (bits 8:6). */ +#define VTD_BF_0_P_IOTLB_INV_DSC_RSVD_8_6_SHIFT 6 +#define VTD_BF_0_P_IOTLB_INV_DSC_RSVD_8_6_MASK UINT64_C(0x00000000000001c0) +/** Type (Hi). */ +#define VTD_BF_0_P_IOTLB_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_P_IOTLB_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 15:12). */ +#define VTD_BF_0_P_IOTLB_INV_DSC_RSVD_15_12_SHIFT 12 +#define VTD_BF_0_P_IOTLB_INV_DSC_RSVD_15_12_MASK UINT64_C(0x000000000000f000) +/** DID: Domain Id. */ +#define VTD_BF_0_P_IOTLB_INV_DSC_DID_SHIFT 16 +#define VTD_BF_0_P_IOTLB_INV_DSC_DID_MASK UINT64_C(0x00000000ffff0000) +/** PASID: Process Address-Space Id. */ +#define VTD_BF_0_P_IOTLB_INV_DSC_PASID_SHIFT 32 +#define VTD_BF_0_P_IOTLB_INV_DSC_PASID_MASK UINT64_C(0x000fffff00000000) +/** R: Reserved (bits 63:52). */ +#define VTD_BF_0_P_IOTLB_INV_DSC_RSVD_63_52_SHIFT 52 +#define VTD_BF_0_P_IOTLB_INV_DSC_RSVD_63_52_MASK UINT64_C(0xfff0000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_P_IOTLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, G, RSVD_8_6, TYPE_HI, RSVD_15_12, DID, PASID, RSVD_63_52)); + + +/** AM: Address Mask. */ +#define VTD_BF_1_P_IOTLB_INV_DSC_AM_SHIFT 0 +#define VTD_BF_1_P_IOTLB_INV_DSC_AM_MASK UINT64_C(0x000000000000003f) +/** IH: Invalidation Hint. */ +#define VTD_BF_1_P_IOTLB_INV_DSC_IH_SHIFT 6 +#define VTD_BF_1_P_IOTLB_INV_DSC_IH_MASK UINT64_C(0x0000000000000040) +/** R: Reserved (bits 11:7). */ +#define VTD_BF_1_P_IOTLB_INV_DSC_RSVD_11_7_SHIFT 7 +#define VTD_BF_1_P_IOTLB_INV_DSC_RSVD_11_7_MASK UINT64_C(0x0000000000000f80) +/** ADDR: Address. */ +#define VTD_BF_1_P_IOTLB_INV_DSC_ADDR_SHIFT 12 +#define VTD_BF_1_P_IOTLB_INV_DSC_ADDR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_P_IOTLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (AM, IH, RSVD_11_7, ADDR)); +/** @} */ + + +/** @name Device-TLB Invalidate Descriptor (dev_tlb_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_DEV_TLB_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** R: Reserved (bits 8:4). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_RSVD_8_4_SHIFT 4 +#define VTD_BF_0_DEV_TLB_INV_DSC_RSVD_8_4_MASK UINT64_C(0x00000000000001f0) +/** Type (Hi). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_DEV_TLB_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** PFSID: Physical-Function Source Id (Lo). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_PFSID_LO_SHIFT 12 +#define VTD_BF_0_DEV_TLB_INV_DSC_PFSID_LO_MASK UINT64_C(0x000000000000f000) +/** MIP: Max Invalidations Pending. */ +#define VTD_BF_0_DEV_TLB_INV_DSC_MIP_SHIFT 16 +#define VTD_BF_0_DEV_TLB_INV_DSC_MIP_MASK UINT64_C(0x00000000001f0000) +/** R: Reserved (bits 31:21). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_RSVD_31_21_SHIFT 21 +#define VTD_BF_0_DEV_TLB_INV_DSC_RSVD_31_21_MASK UINT64_C(0x00000000ffe00000) +/** SID: Source Id. */ +#define VTD_BF_0_DEV_TLB_INV_DSC_SID_SHIFT 32 +#define VTD_BF_0_DEV_TLB_INV_DSC_SID_MASK UINT64_C(0x0000ffff00000000) +/** R: Reserved (bits 51:48). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_RSVD_51_48_SHIFT 48 +#define VTD_BF_0_DEV_TLB_INV_DSC_RSVD_51_48_MASK UINT64_C(0x000f000000000000) +/** PFSID: Physical-Function Source Id (Hi). */ +#define VTD_BF_0_DEV_TLB_INV_DSC_PFSID_HI_SHIFT 52 +#define VTD_BF_0_DEV_TLB_INV_DSC_PFSID_HI_MASK UINT64_C(0xfff0000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_DEV_TLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, RSVD_8_4, TYPE_HI, PFSID_LO, MIP, RSVD_31_21, SID, RSVD_51_48, PFSID_HI)); + +/** S: Size. */ +#define VTD_BF_1_DEV_TLB_INV_DSC_S_SHIFT 0 +#define VTD_BF_1_DEV_TLB_INV_DSC_S_MASK UINT64_C(0x0000000000000001) +/** R: Reserved (bits 11:1). */ +#define VTD_BF_1_DEV_TLB_INV_DSC_RSVD_11_1_SHIFT 1 +#define VTD_BF_1_DEV_TLB_INV_DSC_RSVD_11_1_MASK UINT64_C(0x0000000000000ffe) +/** ADDR: Address. */ +#define VTD_BF_1_DEV_TLB_INV_DSC_ADDR_SHIFT 12 +#define VTD_BF_1_DEV_TLB_INV_DSC_ADDR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_DEV_TLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (S, RSVD_11_1, ADDR)); +/** @} */ + + +/** @name PASID-based-device-TLB Invalidate Descriptor (p_dev_tlb_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** MIP: Max Invalidations Pending. */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_MIP_SHIFT 4 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_MIP_MASK UINT64_C(0x00000000000001f0) +/** Type (Hi). */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** PFSID: Physical-Function Source Id (Lo). */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_PFSID_LO_SHIFT 12 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_PFSID_LO_MASK UINT64_C(0x000000000000f000) +/** SID: Source Id. */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_SID_SHIFT 16 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_SID_MASK UINT64_C(0x00000000ffff0000) +/** PASID: Process Address-Space Id. */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_PASID_SHIFT 32 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_PASID_MASK UINT64_C(0x000fffff00000000) +/** PFSID: Physical-Function Source Id (Hi). */ +#define VTD_BF_0_P_DEV_TLB_INV_DSC_PFSID_HI_SHIFT 52 +#define VTD_BF_0_P_DEV_TLB_INV_DSC_PFSID_HI_MASK UINT64_C(0xfff0000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_P_DEV_TLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, MIP, TYPE_HI, PFSID_LO, SID, PASID, PFSID_HI)); + +/** G: Granularity. */ +#define VTD_BF_1_P_DEV_TLB_INV_DSC_G_SHIFT 0 +#define VTD_BF_1_P_DEV_TLB_INV_DSC_G_MASK UINT64_C(0x0000000000000001) +/** R: Reserved (bits 10:1). */ +#define VTD_BF_1_P_DEV_TLB_INV_DSC_RSVD_10_1_SHIFT 1 +#define VTD_BF_1_P_DEV_TLB_INV_DSC_RSVD_10_1_MASK UINT64_C(0x00000000000007fe) +/** S: Size. */ +#define VTD_BF_1_P_DEV_TLB_INV_DSC_S_SHIFT 11 +#define VTD_BF_1_P_DEV_TLB_INV_DSC_S_MASK UINT64_C(0x0000000000000800) +/** ADDR: Address. */ +#define VTD_BF_1_P_DEV_TLB_INV_DSC_ADDR_SHIFT 12 +#define VTD_BF_1_P_DEV_TLB_INV_DSC_ADDR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_P_DEV_TLB_INV_DSC_, UINT64_C(0), UINT64_MAX, + (G, RSVD_10_1, S, ADDR)); +/** @} */ + + +/** @name Interrupt Entry Cache Invalidate Descriptor (iec_inv_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_IEC_INV_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_IEC_INV_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** G: Granularity. */ +#define VTD_BF_0_IEC_INV_DSC_G_SHIFT 4 +#define VTD_BF_0_IEC_INV_DSC_G_MASK UINT64_C(0x0000000000000010) +/** R: Reserved (bits 8:5). */ +#define VTD_BF_0_IEC_INV_DSC_RSVD_8_5_SHIFT 5 +#define VTD_BF_0_IEC_INV_DSC_RSVD_8_5_MASK UINT64_C(0x00000000000001e0) +/** Type (Hi). */ +#define VTD_BF_0_IEC_INV_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_IEC_INV_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 26:12). */ +#define VTD_BF_0_IEC_INV_DSC_RSVD_26_12_SHIFT 12 +#define VTD_BF_0_IEC_INV_DSC_RSVD_26_12_MASK UINT64_C(0x0000000007fff000) +/** IM: Index Mask. */ +#define VTD_BF_0_IEC_INV_DSC_IM_SHIFT 27 +#define VTD_BF_0_IEC_INV_DSC_IM_MASK UINT64_C(0x00000000f8000000) +/** IIDX: Interrupt Index. */ +#define VTD_BF_0_IEC_INV_DSC_IIDX_SHIFT 32 +#define VTD_BF_0_IEC_INV_DSC_IIDX_MASK UINT64_C(0x0000ffff00000000) +/** R: Reserved (bits 63:48). */ +#define VTD_BF_0_IEC_INV_DSC_RSVD_63_48_SHIFT 48 +#define VTD_BF_0_IEC_INV_DSC_RSVD_63_48_MASK UINT64_C(0xffff000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_IEC_INV_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, G, RSVD_8_5, TYPE_HI, RSVD_26_12, IM, IIDX, RSVD_63_48)); +/** @} */ + + +/** @name Invalidation Wait Descriptor (inv_wait_dsc). + * In accordance with the Intel spec. + * @{ */ +/** Type (Lo). */ +#define VTD_BF_0_INV_WAIT_DSC_TYPE_LO_SHIFT 0 +#define VTD_BF_0_INV_WAIT_DSC_TYPE_LO_MASK UINT64_C(0x000000000000000f) +/** IF: Interrupt Flag. */ +#define VTD_BF_0_INV_WAIT_DSC_IF_SHIFT 4 +#define VTD_BF_0_INV_WAIT_DSC_IF_MASK UINT64_C(0x0000000000000010) +/** SW: Status Write. */ +#define VTD_BF_0_INV_WAIT_DSC_SW_SHIFT 5 +#define VTD_BF_0_INV_WAIT_DSC_SW_MASK UINT64_C(0x0000000000000020) +/** FN: Fence Flag. */ +#define VTD_BF_0_INV_WAIT_DSC_FN_SHIFT 6 +#define VTD_BF_0_INV_WAIT_DSC_FN_MASK UINT64_C(0x0000000000000040) +/** PD: Page-Request Drain. */ +#define VTD_BF_0_INV_WAIT_DSC_PD_SHIFT 7 +#define VTD_BF_0_INV_WAIT_DSC_PD_MASK UINT64_C(0x0000000000000080) +/** R: Reserved (bit 8). */ +#define VTD_BF_0_INV_WAIT_DSC_RSVD_8_SHIFT 8 +#define VTD_BF_0_INV_WAIT_DSC_RSVD_8_MASK UINT64_C(0x0000000000000100) +/** Type (Hi). */ +#define VTD_BF_0_INV_WAIT_DSC_TYPE_HI_SHIFT 9 +#define VTD_BF_0_INV_WAIT_DSC_TYPE_HI_MASK UINT64_C(0x0000000000000e00) +/** R: Reserved (bits 31:12). */ +#define VTD_BF_0_INV_WAIT_DSC_RSVD_31_12_SHIFT 12 +#define VTD_BF_0_INV_WAIT_DSC_RSVD_31_12_MASK UINT64_C(0x00000000fffff000) +/** STDATA: Status Data. */ +#define VTD_BF_0_INV_WAIT_DSC_STDATA_SHIFT 32 +#define VTD_BF_0_INV_WAIT_DSC_STDATA_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_0_INV_WAIT_DSC_, UINT64_C(0), UINT64_MAX, + (TYPE_LO, IF, SW, FN, PD, RSVD_8, TYPE_HI, RSVD_31_12, STDATA)); + +/** R: Reserved (bits 1:0). */ +#define VTD_BF_1_INV_WAIT_DSC_RSVD_1_0_SHIFT 0 +#define VTD_BF_1_INV_WAIT_DSC_RSVD_1_0_MASK UINT64_C(0x0000000000000003) +/** STADDR: Status Address. */ +#define VTD_BF_1_INV_WAIT_DSC_STADDR_SHIFT 2 +#define VTD_BF_1_INV_WAIT_DSC_STADDR_MASK UINT64_C(0xfffffffffffffffc) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_1_INV_WAIT_DSC_, UINT64_C(0), UINT64_MAX, + (RSVD_1_0, STADDR)); + +/* INV_WAIT_DSC: Qword 0 valid mask. */ +#define VTD_INV_WAIT_DSC_0_VALID_MASK ( VTD_BF_0_INV_WAIT_DSC_TYPE_LO_MASK \ + | VTD_BF_0_INV_WAIT_DSC_IF_MASK \ + | VTD_BF_0_INV_WAIT_DSC_SW_MASK \ + | VTD_BF_0_INV_WAIT_DSC_FN_MASK \ + | VTD_BF_0_INV_WAIT_DSC_PD_MASK \ + | VTD_BF_0_INV_WAIT_DSC_TYPE_HI_MASK \ + | VTD_BF_0_INV_WAIT_DSC_STDATA_MASK) +/* INV_WAIT_DSC: Qword 1 valid mask. */ +#define VTD_INV_WAIT_DSC_1_VALID_MASK VTD_BF_1_INV_WAIT_DSC_STADDR_MASK +/** @} */ + + +/** @name Invalidation descriptor types. + * In accordance with the Intel spec. + * @{ */ +#define VTD_CC_INV_DSC_TYPE 1 +#define VTD_IOTLB_INV_DSC_TYPE 2 +#define VTD_DEV_TLB_INV_DSC_TYPE 3 +#define VTD_IEC_INV_DSC_TYPE 4 +#define VTD_INV_WAIT_DSC_TYPE 5 +#define VTD_P_IOTLB_INV_DSC_TYPE 6 +#define VTD_PC_INV_DSC_TYPE 7 +#define VTD_P_DEV_TLB_INV_DSC_TYPE 8 +/** @} */ + + +/** @name Remappable Format Interrupt Request. + * In accordance with the Intel spec. + * @{ */ +/** IGN: Ignored (bits 1:0). */ +#define VTD_BF_REMAPPABLE_MSI_ADDR_IGN_1_0_SHIFT 0 +#define VTD_BF_REMAPPABLE_MSI_ADDR_IGN_1_0_MASK UINT32_C(0x00000003) +/** Handle (Hi). */ +#define VTD_BF_REMAPPABLE_MSI_ADDR_HANDLE_HI_SHIFT 2 +#define VTD_BF_REMAPPABLE_MSI_ADDR_HANDLE_HI_MASK UINT32_C(0x00000004) +/** SHV: Subhandle Valid. */ +#define VTD_BF_REMAPPABLE_MSI_ADDR_SHV_SHIFT 3 +#define VTD_BF_REMAPPABLE_MSI_ADDR_SHV_MASK UINT32_C(0x00000008) +/** Interrupt format. */ +#define VTD_BF_REMAPPABLE_MSI_ADDR_INTR_FMT_SHIFT 4 +#define VTD_BF_REMAPPABLE_MSI_ADDR_INTR_FMT_MASK UINT32_C(0x00000010) +/** Handle (Lo). */ +#define VTD_BF_REMAPPABLE_MSI_ADDR_HANDLE_LO_SHIFT 5 +#define VTD_BF_REMAPPABLE_MSI_ADDR_HANDLE_LO_MASK UINT32_C(0x000fffe0) +/** Address. */ +#define VTD_BF_REMAPPABLE_MSI_ADDR_ADDR_SHIFT 20 +#define VTD_BF_REMAPPABLE_MSI_ADDR_ADDR_MASK UINT32_C(0xfff00000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_REMAPPABLE_MSI_ADDR_, UINT32_C(0), UINT32_MAX, + (IGN_1_0, HANDLE_HI, SHV, INTR_FMT, HANDLE_LO, ADDR)); + +/** Subhandle. */ +#define VTD_BF_REMAPPABLE_MSI_DATA_SUBHANDLE_SHIFT 0 +#define VTD_BF_REMAPPABLE_MSI_DATA_SUBHANDLE_MASK UINT32_C(0x0000ffff) +/** R: Reserved (bits 31:16). */ +#define VTD_BF_REMAPPABLE_MSI_DATA_RSVD_31_16_SHIFT 16 +#define VTD_BF_REMAPPABLE_MSI_DATA_RSVD_31_16_MASK UINT32_C(0xffff0000) +RT_BF_ASSERT_COMPILE_CHECKS(VTD_BF_REMAPPABLE_MSI_DATA_, UINT32_C(0), UINT32_MAX, + (SUBHANDLE, RSVD_31_16)); + +/** Remappable MSI Address: Valid mask. */ +#define VTD_REMAPPABLE_MSI_ADDR_VALID_MASK UINT32_MAX +/** Remappable MSI Data: Valid mask. */ +#define VTD_REMAPPABLE_MSI_DATA_VALID_MASK VTD_BF_REMAPPABLE_MSI_DATA_SUBHANDLE_MASK + +/** Interrupt format: Compatibility. */ +#define VTD_INTR_FORMAT_COMPAT 0 +/** Interrupt format: Remappable. */ +#define VTD_INTR_FORMAT_REMAPPABLE 1 +/** @} */ + + +/** @name Interrupt Remapping Fault Conditions. + * In accordance with the Intel spec. + * @{ */ +typedef enum VTDIRFAULT +{ + /** Reserved bits invalid in remappable interrupt. */ + VTDIRFAULT_REMAPPABLE_INTR_RSVD = 0x20, + + /** Interrupt index for remappable interrupt exceeds table size or referenced + * address above host address width (HAW) */ + VTDIRFAULT_INTR_INDEX_INVALID = 0x21, + + /** The IRTE is not present. */ + VTDIRFAULT_IRTE_NOT_PRESENT = 0x22, + /** Reading IRTE from memory failed. */ + VTDIRFAULT_IRTE_READ_FAILED = 0x23, + /** IRTE reserved bits invalid for an IRTE with Present bit set. */ + VTDIRFAULT_IRTE_PRESENT_RSVD = 0x24, + + /** Compatibility format interrupt (CFI) blocked due to EIME being enabled or CFIs + * were disabled. */ + VTDIRFAULT_CFI_BLOCKED = 0x25, + + /** IRTE SID, SVT, SQ bits invalid for an IRTE with Present bit set. */ + VTDIRFAULT_IRTE_PRESENT_INVALID = 0x26, + + /** Reading posted interrupt descriptor (PID) failed. */ + VTDIRFAULT_PID_READ_FAILED = 0x27, + /** PID reserved bits invalid. */ + VTDIRFAULT_PID_RSVD = 0x28, + + /** Untranslated interrupt requested (without PASID) is invalid. */ + VTDIRFAULT_IR_WITHOUT_PASID_INVALID = 0x29 +} VTDIRFAULT; +AssertCompileSize(VTDIRFAULT, 4); +/** @} */ + + +/** @name Address Translation Fault Conditions. + * In accordance with the Intel spec. + * @{ */ +typedef enum VTDATFAULT +{ + /* Legacy root table faults (LRT). */ + VTDATFAULT_LRT_1 = 0x8, + VTDATFAULT_LRT_2 = 0x1, + VTDATFAULT_LRT_3 = 0xa, + + /* Legacy Context-Table Faults (LCT). */ + VTDATFAULT_LCT_1 = 0x9, + VTDATFAULT_LCT_2 = 0x2, + VTDATFAULT_LCT_3 = 0xb, + VTDATFAULT_LCT_4_1 = 0x3, + VTDATFAULT_LCT_4_2 = 0x3, + VTDATFAULT_LCT_4_3 = 0x3, + VTDATFAULT_LCT_5 = 0xd, + + /* Legacy Second-Level Table Faults (LSL). */ + VTDATFAULT_LSL_1 = 0x7, + VTDATFAULT_LSL_2 = 0xc, + + /* Legacy General Faults (LGN). */ + VTDATFAULT_LGN_1_1 = 0x4, + VTDATFAULT_LGN_1_2 = 0x4, + VTDATFAULT_LGN_1_3 = 0x4, + VTDATFAULT_LGN_2 = 0x5, + VTDATFAULT_LGN_3 = 0x6, + VTDATFAULT_LGN_4 = 0xe, + + /* Root-Table Address Register Faults (RTA). */ + VTDATFAULT_RTA_1_1 = 0x30, + VTDATFAULT_RTA_1_2 = 0x30, + VTDATFAULT_RTA_1_3 = 0x30, + VTDATFAULT_RTA_2 = 0x31, + VTDATFAULT_RTA_3 = 0x32, + VTDATFAULT_RTA_4 = 0x33, + + /* Scalable-Mode Root-Table Faults (SRT). */ + VTDATFAULT_SRT_1 = 0x38, + VTDATFAULT_SRT_2 = 0x39, + VTDATFAULT_SRT_3 = 0x3a, + + /* Scalable-Mode Context-Table Faults (SCT). */ + VTDATFAULT_SCT_1 = 0x40, + VTDATFAULT_SCT_2 = 0x41, + VTDATFAULT_SCT_3 = 0x42, + VTDATFAULT_SCT_4_1 = 0x43, + VTDATFAULT_SCT_4_2 = 0x43, + VTDATFAULT_SCT_5 = 0x44, + VTDATFAULT_SCT_6 = 0x45, + VTDATFAULT_SCT_7 = 0x46, + VTDATFAULT_SCT_8 = 0x47, + VTDATFAULT_SCT_9 = 0x48, + + /* Scalable-Mode PASID-Directory Faults (SPD). */ + VTDATFAULT_SPD_1 = 0x50, + VTDATFAULT_SPD_2 = 0x51, + VTDATFAULT_SPD_3 = 0x52, + + /* Scalable-Mode PASID-Table Faults (SPT). */ + VTDATFAULT_SPT_1 = 0x58, + VTDATFAULT_SPT_2 = 0x59, + VTDATFAULT_SPT_3 = 0x5a, + VTDATFAULT_SPT_4_1 = 0x5b, + VTDATFAULT_SPT_4_2 = 0x5b, + VTDATFAULT_SPT_4_3 = 0x5b, + VTDATFAULT_SPT_4_4 = 0x5b, + VTDATFAULT_SPT_5 = 0x5c, + VTDATFAULT_SPT_6 = 0x5d, + + /* Scalable-Mode First-Level Table Faults (SFL). */ + VTDATFAULT_SFL_1 = 0x70, + VTDATFAULT_SFL_2 = 0x71, + VTDATFAULT_SFL_3 = 0x72, + VTDATFAULT_SFL_4 = 0x73, + VTDATFAULT_SFL_5 = 0x74, + VTDATFAULT_SFL_6 = 0x75, + VTDATFAULT_SFL_7 = 0x76, + VTDATFAULT_SFL_8 = 0x77, + VTDATFAULT_SFL_9 = 0x90, + VTDATFAULT_SFL_10 = 0x91, + + /* Scalable-Mode Second-Level Table Faults (SSL). */ + VTDATFAULT_SSL_1 = 0x78, + VTDATFAULT_SSL_2 = 0x79, + VTDATFAULT_SSL_3 = 0x7a, + VTDATFAULT_SSL_4 = 0x7b, + VTDATFAULT_SSL_5 = 0x7c, + VTDATFAULT_SSL_6 = 0x7d, + + /* Scalable-Mode General Faults (SGN). */ + VTDATFAULT_SGN_1 = 0x80, + VTDATFAULT_SGN_2 = 0x81, + VTDATFAULT_SGN_3 = 0x82, + VTDATFAULT_SGN_4_1 = 0x83, + VTDATFAULT_SGN_4_2 = 0x83, + VTDATFAULT_SGN_5 = 0x84, + VTDATFAULT_SGN_6 = 0x85, + VTDATFAULT_SGN_7 = 0x86, + VTDATFAULT_SGN_8 = 0x87, + VTDATFAULT_SGN_9 = 0x88, + VTDATFAULT_SGN_10 = 0x89 +} VTDATFAULT; +AssertCompileSize(VTDATFAULT, 4); +/** @} */ + + +/** @name ACPI_DMAR_F_XXX: DMA Remapping Reporting Structure Flags. + * In accordance with the Intel spec. + * @{ */ +/** INTR_REMAP: Interrupt remapping supported. */ +#define ACPI_DMAR_F_INTR_REMAP RT_BIT(0) +/** X2APIC_OPT_OUT: Request system software to opt-out of enabling x2APIC. */ +#define ACPI_DMAR_F_X2APIC_OPT_OUT RT_BIT(1) +/** DMA_CTRL_PLATFORM_OPT_IN_FLAG: Firmware initiated DMA restricted to reserved + * memory regions (RMRR). */ +#define ACPI_DMAR_F_DMA_CTRL_PLATFORM_OPT_IN RT_BIT(2) +/** @} */ + + +/** @name ACPI_DRHD_F_XXX: DMA-Remapping Hardware Unit Definition Flags. + * In accordance with the Intel spec. + * @{ */ +/** INCLUDE_PCI_ALL: All PCI devices under scope. */ +#define ACPI_DRHD_F_INCLUDE_PCI_ALL RT_BIT(0) +/** @} */ + + +/** + * DRHD: DMA-Remapping Hardware Unit Definition. + * In accordance with the Intel spec. + */ +#pragma pack(1) +typedef struct ACPIDRHD +{ + /** Type (must be 0=DRHD). */ + uint16_t uType; + /** Length (must be 16 + size of device scope structure). */ + uint16_t cbLength; + /** Flags, see ACPI_DRHD_F_XXX. */ + uint8_t fFlags; + /** Reserved (MBZ). */ + uint8_t bRsvd; + /** PCI segment number. */ + uint16_t uPciSegment; + /** Register Base Address (MMIO). */ + uint64_t uRegBaseAddr; + /* Device Scope[] Structures follow. */ +} ACPIDRHD; +#pragma pack() +AssertCompileSize(ACPIDRHD, 16); +AssertCompileMemberOffset(ACPIDRHD, cbLength, 2); +AssertCompileMemberOffset(ACPIDRHD, fFlags, 4); +AssertCompileMemberOffset(ACPIDRHD, uPciSegment, 6); +AssertCompileMemberOffset(ACPIDRHD, uRegBaseAddr, 8); + + +/** @name ACPIDMARDEVSCOPE_TYPE_XXX: Device Type. + * In accordance with the Intel spec. + * @{ */ +#define ACPIDMARDEVSCOPE_TYPE_PCI_ENDPOINT 1 +#define ACPIDMARDEVSCOPE_TYPE_PCI_SUB_HIERARCHY 2 +#define ACPIDMARDEVSCOPE_TYPE_IOAPIC 3 +#define ACPIDMARDEVSCOPE_TYPE_MSI_CAP_HPET 4 +#define ACPIDMARDEVSCOPE_TYPE_ACPI_NAMESPACE_DEV 5 +/** @} */ + + +/** + * ACPI Device Scope Structure - PCI device path. + * In accordance with the Intel spec. + */ +typedef struct ACPIDEVSCOPEPATH +{ + /** PCI device number. */ + uint8_t uDevice; + /** PCI function number. */ + uint8_t uFunction; +} ACPIDEVSCOPEPATH; +AssertCompileSize(ACPIDEVSCOPEPATH, 2); + + +/** + * Device Scope Structure. + * In accordance with the Intel spec. + */ +#pragma pack(1) +typedef struct ACPIDMARDEVSCOPE +{ + /** Type, see ACPIDMARDEVSCOPE_TYPE_XXX. */ + uint8_t uType; + /** Length (must be 6 + size of auPath field). */ + uint8_t cbLength; + /** Reserved (MBZ). */ + uint8_t abRsvd[2]; + /** Enumeration ID (for I/O APIC, HPET and ACPI namespace devices). */ + uint8_t idEnum; + /** First bus number for this device. */ + uint8_t uStartBusNum; + /** Hierarchical path from the Host Bridge to the device. */ + ACPIDEVSCOPEPATH Path; +} ACPIDMARDEVSCOPE; +#pragma pack() +AssertCompileMemberOffset(ACPIDMARDEVSCOPE, cbLength, 1); +AssertCompileMemberOffset(ACPIDMARDEVSCOPE, idEnum, 4); +AssertCompileMemberOffset(ACPIDMARDEVSCOPE, uStartBusNum, 5); +AssertCompileMemberOffset(ACPIDMARDEVSCOPE, Path, 6); + +/** ACPI DMAR revision (not the OEM revision field). + * In accordance with the Intel spec. */ +#define ACPI_DMAR_REVISION 1 + + +#endif /* !VBOX_INCLUDED_iommu_intel_h */ + diff --git a/include/VBox/log.h b/include/VBox/log.h new file mode 100644 index 00000000..9a2fe937 --- /dev/null +++ b/include/VBox/log.h @@ -0,0 +1,1239 @@ +/** @file + * VirtualBox - Logging. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_log_h +#define VBOX_INCLUDED_log_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* + * Set the default loggroup. + */ +#ifndef LOG_GROUP +# define LOG_GROUP LOG_GROUP_DEFAULT +#endif + +#include + + +/** @defgroup grp_rt_vbox_log VBox Logging + * @ingroup grp_rt_vbox + * @{ + */ + +/** PC port for debug output */ +#define RTLOG_DEBUG_PORT 0x504 + +/** + * VirtualBox Logging Groups. + * (Remember to update LOGGROUP_NAMES!) + * + * @remark It should be pretty obvious, but just to have + * mentioned it, the values are sorted alphabetically (using the + * english alphabet) except for _DEFAULT which is always first. + * + * If anyone might be wondering what the alphabet looks like: + * A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ + */ +typedef enum VBOXLOGGROUP +{ + /** The default VBox group. */ + LOG_GROUP_DEFAULT = RTLOGGROUP_FIRST_USER, + /** Audio mixer group. */ + LOG_GROUP_AUDIO_MIXER, + /** Audio mixer buffer group. */ + LOG_GROUP_AUDIO_MIXER_BUFFER, + /** Audio test group. */ + LOG_GROUP_AUDIO_TEST, + /** Auto-logon group. */ + LOG_GROUP_AUTOLOGON, + /** CFGM group. */ + LOG_GROUP_CFGM, + /** CPUM group. */ + LOG_GROUP_CPUM, + /** CSAM group. */ + LOG_GROUP_CSAM, + /** Debug Console group. */ + LOG_GROUP_DBGC, + /** DBGF group. */ + LOG_GROUP_DBGF, + /** DBGF info group. */ + LOG_GROUP_DBGF_INFO, + /** The debugger gui. */ + LOG_GROUP_DBGG, + /** Generic Device group. */ + LOG_GROUP_DEV, + /** AC97 Device group. */ + LOG_GROUP_DEV_AC97, + /** ACPI Device group. */ + LOG_GROUP_DEV_ACPI, + /** AHCI Device group. */ + LOG_GROUP_DEV_AHCI, + /** APIC Device group. */ + LOG_GROUP_DEV_APIC, + /** BusLogic SCSI host adapter group. */ + LOG_GROUP_DEV_BUSLOGIC, + /** DMA Controller group. */ + LOG_GROUP_DEV_DMA, + /** NS DP8390 Ethernet Device group. */ + LOG_GROUP_DEV_DP8390, + /** Gigabit Ethernet Device group. */ + LOG_GROUP_DEV_E1000, + /** Extensible Firmware Interface Device group. */ + LOG_GROUP_DEV_EFI, + /** USB EHCI Device group. */ + LOG_GROUP_DEV_EHCI, + /** 3C501 Ethernet Device group. */ + LOG_GROUP_DEV_ELNK, + /** Floppy Controller Device group. */ + LOG_GROUP_DEV_FDC, + /** Flash Device group. */ + LOG_GROUP_DEV_FLASH, + /** Guest Interface Manager Device group. */ + LOG_GROUP_DEV_GIM, + /** HDA Device group. */ + LOG_GROUP_DEV_HDA, + /** HDA Codec Device group. */ + LOG_GROUP_DEV_HDA_CODEC, + /** High Precision Event Timer Device group. */ + LOG_GROUP_DEV_HPET, + /** IDE Device group. */ + LOG_GROUP_DEV_IDE, + /** The internal networking IP stack Device group. */ + LOG_GROUP_DEV_INIP, + /** I/O APIC Device group. */ + LOG_GROUP_DEV_IOAPIC, + /** IOMMU Device group. */ + LOG_GROUP_DEV_IOMMU, + /** KeyBoard Controller Device group. */ + LOG_GROUP_DEV_KBD, + /** Low Pin Count Device group. */ + LOG_GROUP_DEV_LPC, + /** LsiLogic SCSI controller Device group. */ + LOG_GROUP_DEV_LSILOGICSCSI, + /** NVMe Device group. */ + LOG_GROUP_DEV_NVME, + /** USB OHCI Device group. */ + LOG_GROUP_DEV_OHCI, + /** Parallel Device group */ + LOG_GROUP_DEV_PARALLEL, + /** PC Device group. */ + LOG_GROUP_DEV_PC, + /** PC Architecture Device group. */ + LOG_GROUP_DEV_PC_ARCH, + /** PC BIOS Device group. */ + LOG_GROUP_DEV_PC_BIOS, + /** PCI Device group. */ + LOG_GROUP_DEV_PCI, + /** PCI Raw Device group. */ + LOG_GROUP_DEV_PCI_RAW, + /** PCNet Device group. */ + LOG_GROUP_DEV_PCNET, + /** PIC Device group. */ + LOG_GROUP_DEV_PIC, + /** PIT Device group. */ + LOG_GROUP_DEV_PIT, + /** QEMU firmware config Device group. */ + LOG_GROUP_DEV_QEMUFWCFG, + /** RTC Device group. */ + LOG_GROUP_DEV_RTC, + /** SB16 Device group. */ + LOG_GROUP_DEV_SB16, + /** Serial Device group */ + LOG_GROUP_DEV_SERIAL, + /** System Management Controller Device group. */ + LOG_GROUP_DEV_SMC, + /** Trusted Platform Module Device group. */ + LOG_GROUP_DEV_TPM, + /** VGA Device group. */ + LOG_GROUP_DEV_VGA, + /** Virtio PCI Device group. */ + LOG_GROUP_DEV_VIRTIO, + /** Virtio Network Device group. */ + LOG_GROUP_DEV_VIRTIO_NET, + /** VMM Device group. */ + LOG_GROUP_DEV_VMM, + /** VMM Device group for backdoor logging. */ + LOG_GROUP_DEV_VMM_BACKDOOR, + /** VMM Device group for logging guest backdoor logging to stderr. */ + LOG_GROUP_DEV_VMM_STDERR, + /** VMSVGA Device group. */ + LOG_GROUP_DEV_VMSVGA, + /** USB xHCI Device group. */ + LOG_GROUP_DEV_XHCI, + /** Disassembler group. */ + LOG_GROUP_DIS, + /** Generic driver group. */ + LOG_GROUP_DRV, + /** ACPI driver group */ + LOG_GROUP_DRV_ACPI, + /** Audio driver group */ + LOG_GROUP_DRV_AUDIO, + /** Block driver group. */ + LOG_GROUP_DRV_BLOCK, + /** Char driver group. */ + LOG_GROUP_DRV_CHAR, + /** Cloud tunnel driver group. */ + LOG_GROUP_DRV_CTUN, + /** Disk integrity driver group. */ + LOG_GROUP_DRV_DISK_INTEGRITY, + /** Video Display driver group. */ + LOG_GROUP_DRV_DISPLAY, + /** Floppy media driver group. */ + LOG_GROUP_DRV_FLOPPY, + /** Host Audio driver group. */ + LOG_GROUP_DRV_HOST_AUDIO, + /** Host Base block driver group. */ + LOG_GROUP_DRV_HOST_BASE, + /** Host DVD block driver group. */ + LOG_GROUP_DRV_HOST_DVD, + /** Host floppy block driver group. */ + LOG_GROUP_DRV_HOST_FLOPPY, + /** Host Parallel Driver group */ + LOG_GROUP_DRV_HOST_PARALLEL, + /** Host Serial Driver Group */ + LOG_GROUP_DRV_HOST_SERIAL, + /** The internal networking transport driver group. */ + LOG_GROUP_DRV_INTNET, + /** ISO (CD/DVD) media driver group. */ + LOG_GROUP_DRV_ISO, + /** Keyboard Queue driver group. */ + LOG_GROUP_DRV_KBD_QUEUE, + /** lwIP IP stack driver group. */ + LOG_GROUP_DRV_LWIP, + /** Video Miniport driver group. */ + LOG_GROUP_DRV_MINIPORT, + /** Mouse driver group. */ + LOG_GROUP_DRV_MOUSE, + /** Mouse Queue driver group. */ + LOG_GROUP_DRV_MOUSE_QUEUE, + /** Named Pipe stream driver group. */ + LOG_GROUP_DRV_NAMEDPIPE, + /** NAT network transport driver group */ + LOG_GROUP_DRV_NAT, + /** Raw image driver group */ + LOG_GROUP_DRV_RAW_IMAGE, + /** SCSI driver group. */ + LOG_GROUP_DRV_SCSI, + /** Host SCSI driver group. */ + LOG_GROUP_DRV_SCSIHOST, + /** TCP socket stream driver group. */ + LOG_GROUP_DRV_TCP, + /** Trusted Platform Module Emulation driver group. */ + LOG_GROUP_DRV_TPM_EMU, + /** Trusted Platform Module Host driver group. */ + LOG_GROUP_DRV_TPM_HOST, + /** Async transport driver group */ + LOG_GROUP_DRV_TRANSPORT_ASYNC, + /** TUN network transport driver group */ + LOG_GROUP_DRV_TUN, + /** UDP socket stream driver group. */ + LOG_GROUP_DRV_UDP, + /** UDP tunnet network transport driver group. */ + LOG_GROUP_DRV_UDPTUNNEL, + /** USB Proxy driver group. */ + LOG_GROUP_DRV_USBPROXY, + /** VBoxHDD media driver group. */ + LOG_GROUP_DRV_VBOXHDD, + /** VBox HDD container media driver group. */ + LOG_GROUP_DRV_VD, + /** The VMNET networking driver group. */ + LOG_GROUP_DRV_VMNET, + /** VRDE audio driver group. */ + LOG_GROUP_DRV_VRDE_AUDIO, + /** Virtual Switch transport driver group */ + LOG_GROUP_DRV_VSWITCH, + /** VUSB driver group */ + LOG_GROUP_DRV_VUSB, + /** EM group. */ + LOG_GROUP_EM, + /** FTM group. */ + LOG_GROUP_FTM, + /** GIM group. */ + LOG_GROUP_GIM, + /** GMM group. */ + LOG_GROUP_GMM, + /** Guest control. */ + LOG_GROUP_GUEST_CONTROL, + /** Guest drag'n drop. */ + LOG_GROUP_GUEST_DND, + /** GUI group. */ + LOG_GROUP_GUI, + /** GVMM group. */ + LOG_GROUP_GVMM, + /** HGCM group */ + LOG_GROUP_HGCM, + /** HGSMI group */ + LOG_GROUP_HGSMI, + /** HM group. */ + LOG_GROUP_HM, + /** IEM group. */ + LOG_GROUP_IEM, + /** IEM AMD-V group. */ + LOG_GROUP_IEM_SVM, + /** IEM VT-x group. */ + LOG_GROUP_IEM_VMX, + /** I/O buffer management group. */ + LOG_GROUP_IOBUFMGMT, + /** IOM group. */ + LOG_GROUP_IOM, + /** IOM group, I/O port part. */ + LOG_GROUP_IOM_IOPORT, + /** IOM group, MMIO part. */ + LOG_GROUP_IOM_MMIO, + /** XPCOM IPC group. */ + LOG_GROUP_IPC, + /** lwIP group. */ + LOG_GROUP_LWIP, + /** lwIP group, api_lib.c API_LIB_DEBUG */ + LOG_GROUP_LWIP_API_LIB, + /** lwIP group, api_msg.c API_MSG_DEBUG */ + LOG_GROUP_LWIP_API_MSG, + /** lwIP group, etharp.c ETHARP_DEBUG */ + LOG_GROUP_LWIP_ETHARP, + /** lwIP group, icmp.c ICMP_DEBUG */ + LOG_GROUP_LWIP_ICMP, + /** lwIP group, igmp.c IGMP_DEBUG */ + LOG_GROUP_LWIP_IGMP, + /** lwIP group, inet.c INET_DEBUG */ + LOG_GROUP_LWIP_INET, + /** lwIP group, IP_DEBUG (sic!) */ + LOG_GROUP_LWIP_IP4, + /** lwIP group, ip_frag.c IP_REASS_DEBUG (sic!) */ + LOG_GROUP_LWIP_IP4_REASS, + /** lwIP group, IP6_DEBUG */ + LOG_GROUP_LWIP_IP6, + /** lwIP group, mem.c MEM_DEBUG */ + LOG_GROUP_LWIP_MEM, + /** lwIP group, memp.c MEMP_DEBUG */ + LOG_GROUP_LWIP_MEMP, + /** lwIP group, netif.c NETIF_DEBUG */ + LOG_GROUP_LWIP_NETIF, + /** lwIP group, pbuf.c PBUF_DEBUG */ + LOG_GROUP_LWIP_PBUF, + /** lwIP group, raw.c RAW_DEBUG */ + LOG_GROUP_LWIP_RAW, + /** lwIP group, sockets.c SOCKETS_DEBUG */ + LOG_GROUP_LWIP_SOCKETS, + /** lwIP group, SYS_DEBUG */ + LOG_GROUP_LWIP_SYS, + /** lwIP group, TCP_DEBUG */ + LOG_GROUP_LWIP_TCP, + /** lwIP group, TCP_CWND_DEBUG (congestion window) */ + LOG_GROUP_LWIP_TCP_CWND, + /** lwIP group, tcp_in.c TCP_FR_DEBUG (fast retransmit) */ + LOG_GROUP_LWIP_TCP_FR, + /** lwIP group, tcp_in.c TCP_INPUT_DEBUG */ + LOG_GROUP_LWIP_TCP_INPUT, + /** lwIP group, tcp_out.c TCP_OUTPUT_DEBUG */ + LOG_GROUP_LWIP_TCP_OUTPUT, + /** lwIP group, TCP_QLEN_DEBUG */ + LOG_GROUP_LWIP_TCP_QLEN, + /** lwIP group, TCP_RST_DEBUG */ + LOG_GROUP_LWIP_TCP_RST, + /** lwIP group, TCP_RTO_DEBUG (retransmit) */ + LOG_GROUP_LWIP_TCP_RTO, + /** lwIP group, tcp_in.c TCP_WND_DEBUG (window updates) */ + LOG_GROUP_LWIP_TCP_WND, + /** lwIP group, tcpip.c TCPIP_DEBUG */ + LOG_GROUP_LWIP_TCPIP, + /** lwIP group, timers.c TIMERS_DEBUG */ + LOG_GROUP_LWIP_TIMERS, + /** lwIP group, udp.c UDP_DEBUG */ + LOG_GROUP_LWIP_UDP, + /** Main group. */ + LOG_GROUP_MAIN, + /** Main group, IAdditionsFacility. */ + LOG_GROUP_MAIN_ADDITIONSFACILITY, + /** Main group, IAppliance. */ + LOG_GROUP_MAIN_APPLIANCE, + /** Main group, IAudioAdapter. */ + LOG_GROUP_MAIN_AUDIOADAPTER, + /** Main group, IAudioDevice. */ + LOG_GROUP_MAIN_AUDIODEVICE, + /** Main group, IAudioSettings. */ + LOG_GROUP_MAIN_AUDIOSETTINGS, + /** Main group, IBandwidthControl. */ + LOG_GROUP_MAIN_BANDWIDTHCONTROL, + /** Main group, IBandwidthGroup. */ + LOG_GROUP_MAIN_BANDWIDTHGROUP, + /** Main group, IBIOSSettings. */ + LOG_GROUP_MAIN_BIOSSETTINGS, + /** Main group, IBooleanFormValue. */ + LOG_GROUP_MAIN_BOOLEANFORMVALUE, + /** Main group, ICertificate. */ + LOG_GROUP_MAIN_CERTIFICATE, + /** Main group, IChoiceFormValue. */ + LOG_GROUP_MAIN_CHOICEFORMVALUE, + /** Main group, ICloudClient. */ + LOG_GROUP_MAIN_CLOUDCLIENT, + /** Main group, ICloudMachine. */ + LOG_GROUP_MAIN_CLOUDMACHINE, + /** Main group, ICloudNetwork. */ + LOG_GROUP_MAIN_CLOUDNETWORK, + /** Main group, ICloudNetworkEnvironmentInfo */ + LOG_GROUP_MAIN_CLOUDNETWORKENVIRONMENTINFO, + /** Main group, ICloudNetworkGatewayInfo */ + LOG_GROUP_MAIN_CLOUDNETWORKGATEWAYINFO, + /** Main group, ICloudProfile. */ + LOG_GROUP_MAIN_CLOUDPROFILE, + /** Main group, ICloudProfileChangedEvent. */ + LOG_GROUP_MAIN_CLOUDPROFILECHANGEDEVENT, + /** Main group, ICloudProfileRegisteredEvent. */ + LOG_GROUP_MAIN_CLOUDPROFILEREGISTEREDEVENT, + /** Main group, ICloudProvider. */ + LOG_GROUP_MAIN_CLOUDPROVIDER, + /** Main group, ICloudProviderManager. */ + LOG_GROUP_MAIN_CLOUDPROVIDERMANAGER, + /** Main group, IConsole. */ + LOG_GROUP_MAIN_CONSOLE, + /** Main group, ICPUProfile. */ + LOG_GROUP_MAIN_CPUPROFILE, + /** Main group, IDataModel. */ + LOG_GROUP_MAIN_DATAMODEL, + /** Main group, IDataStream. */ + LOG_GROUP_MAIN_DATASTREAM, + /** Main group, IDHCPConfig. */ + LOG_GROUP_MAIN_DHCPCONFIG, + /** Main group, IDHCPGlobalConfig. */ + LOG_GROUP_MAIN_DHCPGLOBALCONFIG, + /** Main group, IDHCPGroupCondition. */ + LOG_GROUP_MAIN_DHCPGROUPCONDITION, + /** Main group, IDHCPGroupConfig. */ + LOG_GROUP_MAIN_DHCPGROUPCONFIG, + /** Main group, IDHCPIndividualConfig. */ + LOG_GROUP_MAIN_DHCPINDIVIDUALCONFIG, + /** Main group, IDHCPServer. */ + LOG_GROUP_MAIN_DHCPSERVER, + /** Main group, IDirectory. */ + LOG_GROUP_MAIN_DIRECTORY, + /** Main group, IDisplay. */ + LOG_GROUP_MAIN_DISPLAY, + /** Main group, IDisplaySourceBitmap. */ + LOG_GROUP_MAIN_DISPLAYSOURCEBITMAP, + /** Main group, IDnDBase. */ + LOG_GROUP_MAIN_DNDBASE, + /** Main group, IDnDSource. */ + LOG_GROUP_MAIN_DNDSOURCE, + /** Main group, IDnDTarget. */ + LOG_GROUP_MAIN_DNDTARGET, + /** Main group, IEmulatedUSB. */ + LOG_GROUP_MAIN_EMULATEDUSB, + /** Main group, IEvent. */ + LOG_GROUP_MAIN_EVENT, + /** Main group, IEventListener. */ + LOG_GROUP_MAIN_EVENTLISTENER, + /** Main group, IEventSource. */ + LOG_GROUP_MAIN_EVENTSOURCE, + /** Main group, IExtPack. */ + LOG_GROUP_MAIN_EXTPACK, + /** Main group, IExtPackBase. */ + LOG_GROUP_MAIN_EXTPACKBASE, + /** Main group, IExtPackFile. */ + LOG_GROUP_MAIN_EXTPACKFILE, + /** Main group, IExtPackManager. */ + LOG_GROUP_MAIN_EXTPACKMANAGER, + /** Main group, IExtPackPlugIn. */ + LOG_GROUP_MAIN_EXTPACKPLUGIN, + /** Main group, IFile. */ + LOG_GROUP_MAIN_FILE, + /** Main group, IForm. */ + LOG_GROUP_MAIN_FORM, + /** Main group, IFormValue. */ + LOG_GROUP_MAIN_FORMVALUE, + /** Main group, IFramebuffer. */ + LOG_GROUP_MAIN_FRAMEBUFFER, + /** Main group, IFramebufferOverlay. */ + LOG_GROUP_MAIN_FRAMEBUFFEROVERLAY, + /** Main group, IFsInfo. */ + LOG_GROUP_MAIN_FSINFO, + /** Main group, IFsObjInfo. */ + LOG_GROUP_MAIN_FSOBJINFO, + /** Main group, IGraphicsAdapter. */ + LOG_GROUP_MAIN_GRAPHICSADAPTER, + /** Main group, IGuest. */ + LOG_GROUP_MAIN_GUEST, + /** Main group, IGuestDebugControl. */ + LOG_GROUP_MAIN_GUESTDEBUGCONTROL, + /** Main group, IGuestDirectory. */ + LOG_GROUP_MAIN_GUESTDIRECTORY, + /** Main group, IGuestDnDSource. */ + LOG_GROUP_MAIN_GUESTDNDSOURCE, + /** Main group, IGuestDnDTarget. */ + LOG_GROUP_MAIN_GUESTDNDTARGET, + /** Main group, IGuestErrorInfo. */ + LOG_GROUP_MAIN_GUESTERRORINFO, + /** Main group, IGuestFile. */ + LOG_GROUP_MAIN_GUESTFILE, + /** Main group, IGuestFileEvent. */ + LOG_GROUP_MAIN_GUESTFILEEVENT, + /** Main group, IGuestFileIOEvent. */ + LOG_GROUP_MAIN_GUESTFILEIOEVENT, + /** Main group, IGuestFsInfo. */ + LOG_GROUP_MAIN_GUESTFSINFO, + /** Main group, IGuestFsObjInfo. */ + LOG_GROUP_MAIN_GUESTFSOBJINFO, + /** Main group, IGuestOSType. */ + LOG_GROUP_MAIN_GUESTOSTYPE, + /** Main group, IGuestProcess. */ + LOG_GROUP_MAIN_GUESTPROCESS, + /** Main group, IGuestProcessEvent. */ + LOG_GROUP_MAIN_GUESTPROCESSEVENT, + /** Main group, IGuestProcessIOEvent. */ + LOG_GROUP_MAIN_GUESTPROCESSIOEVENT, + /** Main group, IGuestScreenInfo. */ + LOG_GROUP_MAIN_GUESTSCREENINFO, + /** Main group, IGuestSession. */ + LOG_GROUP_MAIN_GUESTSESSION, + /** Main group, IGuestSessionEvent. */ + LOG_GROUP_MAIN_GUESTSESSIONEVENT, + /** Main group, IHost. */ + LOG_GROUP_MAIN_HOST, + /** Main group, IHostAudioDevice. */ + LOG_GROUP_MAIN_HOSTAUDIODEVICE, + /** Main group, IHostDrive. */ + LOG_GROUP_MAIN_HOSTDRIVE, + /** Main group, IHostDriveList. */ + LOG_GROUP_MAIN_HOSTDRIVELIST, + /** Main group, IHostDrivePartition. */ + LOG_GROUP_MAIN_HOSTDRIVEPARTITION, + /** Main group, IHostNetworkInterface. */ + LOG_GROUP_MAIN_HOSTNETWORKINTERFACE, + /** Main group, IHostOnlyNetwork. */ + LOG_GROUP_MAIN_HOSTONLYNETWORK, + /** Main group, IHostUpdateAgent. */ + LOG_GROUP_MAIN_HOSTUPDATEAGENT, + /** Main group, IHostUSBDevice. */ + LOG_GROUP_MAIN_HOSTUSBDEVICE, + /** Main group, IHostUSBDeviceFilter. */ + LOG_GROUP_MAIN_HOSTUSBDEVICEFILTER, + /** Main group, IHostVideoInputDevice. */ + LOG_GROUP_MAIN_HOSTVIDEOINPUTDEVICE, + /** Main group, IInternalMachineControl. */ + LOG_GROUP_MAIN_INTERNALMACHINECONTROL, + /** Main group, IInternalSessionControl. */ + LOG_GROUP_MAIN_INTERNALSESSIONCONTROL, + /** Main group, IKeyboard. */ + LOG_GROUP_MAIN_KEYBOARD, + /** Main group, IMachine. */ + LOG_GROUP_MAIN_MACHINE, + /** Main group, IMachineDebugger. */ + LOG_GROUP_MAIN_MACHINEDEBUGGER, + /** Main group, IMachineEvent. */ + LOG_GROUP_MAIN_MACHINEEVENT, + /** Main group, IMedium. */ + LOG_GROUP_MAIN_MEDIUM, + /** Main group, IMediumAttachment. */ + LOG_GROUP_MAIN_MEDIUMATTACHMENT, + /** Main group, IMediumFormat. */ + LOG_GROUP_MAIN_MEDIUMFORMAT, + /** Main group, IMediumIO. */ + LOG_GROUP_MAIN_MEDIUMIO, + /** Main group, IMouse. */ + LOG_GROUP_MAIN_MOUSE, + /** Main group, IMousePointerShape. */ + LOG_GROUP_MAIN_MOUSEPOINTERSHAPE, + /** Main group, INATEngine. */ + LOG_GROUP_MAIN_NATENGINE, + /** Main group, INATNetwork. */ + LOG_GROUP_MAIN_NATNETWORK, + /** Main group, INetworkAdapter. */ + LOG_GROUP_MAIN_NETWORKADAPTER, + /** Main group, INvramStore. */ + LOG_GROUP_MAIN_NVRAMSTORE, + /** Main group, IParallelPort. */ + LOG_GROUP_MAIN_PARALLELPORT, + /** Main group, IPCIAddress. */ + LOG_GROUP_MAIN_PCIADDRESS, + /** Main group, IPCIDeviceAttachment. */ + LOG_GROUP_MAIN_PCIDEVICEATTACHMENT, + /** Main group, IPerformanceCollector. */ + LOG_GROUP_MAIN_PERFORMANCECOLLECTOR, + /** Main group, IPerformanceMetric. */ + LOG_GROUP_MAIN_PERFORMANCEMETRIC, + /** Main group, IProcess. */ + LOG_GROUP_MAIN_PROCESS, + /** Main group, IProgress. */ + LOG_GROUP_MAIN_PROGRESS, + /** Main group, IProgressCreatedEvent. */ + LOG_GROUP_MAIN_PROGRESSCREATEDEVENT, + /** Main group, IProgressEvent. */ + LOG_GROUP_MAIN_PROGRESSEVENT, + /** Main group, IRangedIntegerFormValue. */ + LOG_GROUP_MAIN_RANGEDINTEGERFORMVALUE, + /** Main group, IRecordingScreenSettings. */ + LOG_GROUP_MAIN_RECORDINGSCREENSETTINGS, + /** Main group, IRecordingSettings. */ + LOG_GROUP_MAIN_RECORDINGSETTINGS, + /** Main group, IReusableEvent. */ + LOG_GROUP_MAIN_REUSABLEEVENT, + /** Main group, ISerialPort. */ + LOG_GROUP_MAIN_SERIALPORT, + /** Main group, ISession. */ + LOG_GROUP_MAIN_SESSION, + /** Main group, ISharedFolder. */ + LOG_GROUP_MAIN_SHAREDFOLDER, + /** Main group, ISnapshot. */ + LOG_GROUP_MAIN_SNAPSHOT, + /** Main group, ISnapshotEvent. */ + LOG_GROUP_MAIN_SNAPSHOTEVENT, + /** Main group, IStorageController. */ + LOG_GROUP_MAIN_STORAGECONTROLLER, + /** Main group, IStringArray. */ + LOG_GROUP_MAIN_STRINGARRAY, + /** Main group, IStringFormValue. */ + LOG_GROUP_MAIN_STRINGFORMVALUE, + /** Main group, ISystemProperties. */ + LOG_GROUP_MAIN_SYSTEMPROPERTIES, + /** Main group, threaded tasks. */ + LOG_GROUP_MAIN_THREAD_TASK, + /** Main group, IToken. */ + LOG_GROUP_MAIN_TOKEN, + /** Main group, ITrustedPlatformModule. */ + LOG_GROUP_MAIN_TRUSTEDPLATFORMMODULE, + /** Main group, IUefiVariableStore. */ + LOG_GROUP_MAIN_UEFIVARIABLESTORE, + /** Main group, IUnattended. */ + LOG_GROUP_MAIN_UNATTENDED, + /** Main group, IUpdateAgent. */ + LOG_GROUP_MAIN_UPDATEAGENT, + /** Main group, IUpdateAgentAvailableEvent. */ + LOG_GROUP_MAIN_UPDATEAGENTAVAILABLEEVENT, + /** Main group, IUpdateAgentErrorEvent. */ + LOG_GROUP_MAIN_UPDATEAGENTERROREVENT, + /** Main group, IUpdateAgentEvent. */ + LOG_GROUP_MAIN_UPDATEAGENTEVENT, + /** Main group, IUpdateAgentSettingsChangedEvent. */ + LOG_GROUP_MAIN_UPDATEAGENTSETTINGSCHANGEDEVENT, + /** Main group, IUpdateAgentStateChangedEvent. */ + LOG_GROUP_MAIN_UPDATEAGENTSTATECHANGEDEVENT, + /** Main group, IUSBController. */ + LOG_GROUP_MAIN_USBCONTROLLER, + /** Main group, IUSBDevice. */ + LOG_GROUP_MAIN_USBDEVICE, + /** Main group, IUSBDeviceFilter. */ + LOG_GROUP_MAIN_USBDEVICEFILTER, + /** Main group, IUSBDeviceFilters. */ + LOG_GROUP_MAIN_USBDEVICEFILTERS, + /** Main group, IUSBProxyBackend. */ + LOG_GROUP_MAIN_USBPROXYBACKEND, + /** Main group, IVBoxSVC. */ + LOG_GROUP_MAIN_VBOXSVC, + /** Main group, IVetoEvent. */ + LOG_GROUP_MAIN_VETOEVENT, + /** Main group, IVFSExplorer. */ + LOG_GROUP_MAIN_VFSEXPLORER, + /** Main group, IVirtualBox. */ + LOG_GROUP_MAIN_VIRTUALBOX, + /** Main group, IVirtualBoxClient. */ + LOG_GROUP_MAIN_VIRTUALBOXCLIENT, + /** Main group, IVirtualBoxSDS. */ + LOG_GROUP_MAIN_VIRTUALBOXSDS, + /** Main group, IVirtualSystemDescription. */ + LOG_GROUP_MAIN_VIRTUALSYSTEMDESCRIPTION, + /** Main group, IVirtualSystemDescriptionForm. */ + LOG_GROUP_MAIN_VIRTUALSYSTEMDESCRIPTIONFORM, + /** Main group, VMM device interfaces. */ + LOG_GROUP_MAIN_VMMDEVINTERFACES, + /** Main group, IVRDEServer. */ + LOG_GROUP_MAIN_VRDESERVER, + /** Main group, IVRDEServerInfo. */ + LOG_GROUP_MAIN_VRDESERVERINFO, + /** Misc. group intended for external use only. */ + LOG_GROUP_MISC, + /** MM group. */ + LOG_GROUP_MM, + /** MM group. */ + LOG_GROUP_MM_HEAP, + /** MM group. */ + LOG_GROUP_MM_HYPER, + /** MM Hypervisor Heap group. */ + LOG_GROUP_MM_HYPER_HEAP, + /** MM Physical/Ram group. */ + LOG_GROUP_MM_PHYS, + /** MM Page pool group. */ + LOG_GROUP_MM_POOL, + /** The NAT service group */ + LOG_GROUP_NAT_SERVICE, + /** NEM group. */ + LOG_GROUP_NEM, + /** The network adaptor driver group. */ + LOG_GROUP_NET_ADP_DRV, + /** The DHCP network service deamon. */ + LOG_GROUP_NET_DHCPD, + /** The network filter driver group. */ + LOG_GROUP_NET_FLT_DRV, + /** The common network service group */ + LOG_GROUP_NET_SERVICE, + /** Network traffic shaper driver group. */ + LOG_GROUP_NET_SHAPER, + /** PATM group. */ + LOG_GROUP_PATM, + /** PDM group. */ + LOG_GROUP_PDM, + /** PDM Async completion group. */ + LOG_GROUP_PDM_ASYNC_COMPLETION, + /** PDM Block cache group. */ + LOG_GROUP_PDM_BLK_CACHE, + /** PDM critical section group. */ + LOG_GROUP_PDM_CRITSECT, + /** PDM read/write critical section group. */ + LOG_GROUP_PDM_CRITSECTRW, + /** PDM Device group. */ + LOG_GROUP_PDM_DEVICE, + /** PDM Driver group. */ + LOG_GROUP_PDM_DRIVER, + /** PDM Loader group. */ + LOG_GROUP_PDM_LDR, + /** PDM Queue group. */ + LOG_GROUP_PDM_QUEUE, + /** PDM Task group. */ + LOG_GROUP_PDM_TASK, + /** PDM Thread group. */ + LOG_GROUP_PDM_THREAD, + /** PGM group. */ + LOG_GROUP_PGM, + /** PGM dynamic mapping group. */ + LOG_GROUP_PGM_DYNMAP, + /** PGM physical group. */ + LOG_GROUP_PGM_PHYS, + /** PGM physical access group. */ + LOG_GROUP_PGM_PHYS_ACCESS, + /** PGM shadow page pool group. */ + LOG_GROUP_PGM_POOL, + /** PGM shared paging group. */ + LOG_GROUP_PGM_SHARED, + /** Audio + video recording. */ + LOG_GROUP_RECORDING, + /** REM group. */ + LOG_GROUP_REM, + /** REM disassembly handler group. */ + LOG_GROUP_REM_DISAS, + /** REM access handler group. */ + LOG_GROUP_REM_HANDLER, + /** REM I/O port access group. */ + LOG_GROUP_REM_IOPORT, + /** REM MMIO access group. */ + LOG_GROUP_REM_MMIO, + /** REM Printf. */ + LOG_GROUP_REM_PRINTF, + /** REM running group. */ + LOG_GROUP_REM_RUN, + /** SELM group. */ + LOG_GROUP_SELM, + /** Shared clipboard host service group. */ + LOG_GROUP_SHARED_CLIPBOARD, + /** Chromium OpenGL host service group. */ + LOG_GROUP_SHARED_CROPENGL, + /** Shared folders host service group. */ + LOG_GROUP_SHARED_FOLDERS, + /** OpenGL host service group. */ + LOG_GROUP_SHARED_OPENGL, + /** The internal networking service group. */ + LOG_GROUP_SRV_INTNET, + /** SSM group. */ + LOG_GROUP_SSM, + /** STAM group. */ + LOG_GROUP_STAM, + /** SUP group. */ + LOG_GROUP_SUP, + /** SUPport driver group. */ + LOG_GROUP_SUP_DRV, + /** TM group. */ + LOG_GROUP_TM, + /** TRPM group. */ + LOG_GROUP_TRPM, + /** USB cardreader group. */ + LOG_GROUP_USB_CARDREADER, + /** USB driver group. */ + LOG_GROUP_USB_DRV, + /** USBFilter group. */ + LOG_GROUP_USB_FILTER, + /** USB keyboard device group. */ + LOG_GROUP_USB_KBD, + /** USB mouse/tablet device group. */ + LOG_GROUP_USB_MOUSE, + /** MSD USB device group. */ + LOG_GROUP_USB_MSD, + /** USB remote support. */ + LOG_GROUP_USB_REMOTE, + /** USB webcam. */ + LOG_GROUP_USB_WEBCAM, + /** VBox Guest Additions Library. */ + LOG_GROUP_VBGL, + /** Generic virtual disk layer. */ + LOG_GROUP_VD, + /** CUE/BIN virtual disk backend. */ + LOG_GROUP_VD_CUE, + /** DMG virtual disk backend. */ + LOG_GROUP_VD_DMG, + /** iSCSI virtual disk backend. */ + LOG_GROUP_VD_ISCSI, + /** Parallels HDD virtual disk backend. */ + LOG_GROUP_VD_PARALLELS, + /** QCOW virtual disk backend. */ + LOG_GROUP_VD_QCOW, + /** QED virtual disk backend. */ + LOG_GROUP_VD_QED, + /** Raw virtual disk backend. */ + LOG_GROUP_VD_RAW, + /** VDI virtual disk backend. */ + LOG_GROUP_VD_VDI, + /** VHD virtual disk backend. */ + LOG_GROUP_VD_VHD, + /** VHDX virtual disk backend. */ + LOG_GROUP_VD_VHDX, + /** VMDK virtual disk backend. */ + LOG_GROUP_VD_VMDK, + /** VBox Guest Additions Driver (VBoxGuest). */ + LOG_GROUP_VGDRV, + /** VM group. */ + LOG_GROUP_VM, + /** VMM group. */ + LOG_GROUP_VMM, + /** VRDE group */ + LOG_GROUP_VRDE, + /** VRDP group */ + LOG_GROUP_VRDP, + /** VSCSI group */ + LOG_GROUP_VSCSI, + /** Webservice group. */ + LOG_GROUP_WEBSERVICE + /* !!!ALPHABETICALLY!!! */ +} VBOXLOGGROUP; + + +/** @def VBOX_LOGGROUP_NAMES + * VirtualBox Logging group names. + * + * Must correspond 100% to LOGGROUP! + * Don't forget commas! + * + * @remark It should be pretty obvious, but just to have + * mentioned it, the values are sorted alphabetically (using the + * english alphabet) except for _DEFAULT which is always first. + * + * If anyone might be wondering what the alphabet looks like: + * a b c d e f g h i j k l m n o p q r s t u v w x y z + */ +#define VBOX_LOGGROUP_NAMES \ +{ \ + RT_LOGGROUP_NAMES, \ + "DEFAULT", \ + "AUDIO_MIXER", \ + "AUDIO_MIXER_BUFFER", \ + "AUDIO_TEST", \ + "AUTOLOGON", \ + "CFGM", \ + "CPUM", \ + "CSAM", \ + "DBGC", \ + "DBGF", \ + "DBGF_INFO", \ + "DBGG", \ + "DEV", \ + "DEV_AC97", \ + "DEV_ACPI", \ + "DEV_AHCI", \ + "DEV_APIC", \ + "DEV_BUSLOGIC", \ + "DEV_DMA", \ + "DEV_DP8390", \ + "DEV_E1000", \ + "DEV_EFI", \ + "DEV_EHCI", \ + "DEV_ELNK", \ + "DEV_FDC", \ + "DEV_FLASH", \ + "DEV_GIM", \ + "DEV_HDA", \ + "DEV_HDA_CODEC", \ + "DEV_HPET", \ + "DEV_IDE", \ + "DEV_INIP", \ + "DEV_IOAPIC", \ + "DEV_IOMMU", \ + "DEV_KBD", \ + "DEV_LPC", \ + "DEV_LSILOGICSCSI", \ + "DEV_NVME", \ + "DEV_OHCI", \ + "DEV_PARALLEL", \ + "DEV_PC", \ + "DEV_PC_ARCH", \ + "DEV_PC_BIOS", \ + "DEV_PCI", \ + "DEV_PCI_RAW", \ + "DEV_PCNET", \ + "DEV_PIC", \ + "DEV_PIT", \ + "DEV_QEMUFWCFG", \ + "DEV_RTC", \ + "DEV_SB16", \ + "DEV_SERIAL", \ + "DEV_SMC", \ + "DEV_TPM", \ + "DEV_VGA", \ + "DEV_VIRTIO", \ + "DEV_VIRTIO_NET", \ + "DEV_VMM", \ + "DEV_VMM_BACKDOOR", \ + "DEV_VMM_STDERR", \ + "DEV_VMSVGA", \ + "DEV_XHCI", \ + "DIS", \ + "DRV", \ + "DRV_ACPI", \ + "DRV_AUDIO", \ + "DRV_BLOCK", \ + "DRV_CHAR", \ + "DRV_CTUN", \ + "DRV_DISK_INTEGRITY", \ + "DRV_DISPLAY", \ + "DRV_FLOPPY", \ + "DRV_HOST_AUDIO", \ + "DRV_HOST_BASE", \ + "DRV_HOST_DVD", \ + "DRV_HOST_FLOPPY", \ + "DRV_HOST_PARALLEL", \ + "DRV_HOST_SERIAL", \ + "DRV_INTNET", \ + "DRV_ISO", \ + "DRV_KBD_QUEUE", \ + "DRV_LWIP", \ + "DRV_MINIPORT", \ + "DRV_MOUSE", \ + "DRV_MOUSE_QUEUE", \ + "DRV_NAMEDPIPE", \ + "DRV_NAT", \ + "DRV_RAW_IMAGE", \ + "DRV_SCSI", \ + "DRV_SCSIHOST", \ + "DRV_TCP", \ + "DRV_TPM_EMU", \ + "DRV_TPM_HOST", \ + "DRV_TRANSPORT_ASYNC", \ + "DRV_TUN", \ + "DRV_UDP", \ + "DRV_UDPTUNNEL", \ + "DRV_USBPROXY", \ + "DRV_VBOXHDD", \ + "DRV_VD", \ + "DRV_VMNET", \ + "DRV_VRDE_AUDIO", \ + "DRV_VSWITCH", \ + "DRV_VUSB", \ + "EM", \ + "FTM", \ + "GIM", \ + "GMM", \ + "GUEST_CONTROL", \ + "GUEST_DND", \ + "GUI", \ + "GVMM", \ + "HGCM", \ + "HGSMI", \ + "HM", \ + "IEM", \ + "IEM_SVM", \ + "IEM_VMX", \ + "IOBUFMGMT", \ + "IOM", \ + "IOM_IOPORT", \ + "IOM_MMIO", \ + "IPC", \ + "LWIP", \ + "LWIP_API_LIB", \ + "LWIP_API_MSG", \ + "LWIP_ETHARP", \ + "LWIP_ICMP", \ + "LWIP_IGMP", \ + "LWIP_INET", \ + "LWIP_IP4", \ + "LWIP_IP4_REASS", \ + "LWIP_IP6", \ + "LWIP_MEM", \ + "LWIP_MEMP", \ + "LWIP_NETIF", \ + "LWIP_PBUF", \ + "LWIP_RAW", \ + "LWIP_SOCKETS", \ + "LWIP_SYS", \ + "LWIP_TCP", \ + "LWIP_TCP_CWND", \ + "LWIP_TCP_FR", \ + "LWIP_TCP_INPUT", \ + "LWIP_TCP_OUTPUT", \ + "LWIP_TCP_QLEN", \ + "LWIP_TCP_RST", \ + "LWIP_TCP_RTO", \ + "LWIP_TCP_WND", \ + "LWIP_TCPIP", \ + "LWIP_TIMERS", \ + "LWIP_UDP", \ + "MAIN", \ + "MAIN_ADDITIONSFACILITY", \ + "MAIN_APPLIANCE", \ + "MAIN_AUDIOADAPTER", \ + "MAIN_AUDIODEVICE", \ + "MAIN_AUDIOSETTINGS", \ + "MAIN_BANDWIDTHCONTROL", \ + "MAIN_BANDWIDTHGROUP", \ + "MAIN_BIOSSETTINGS", \ + "MAIN_BOOLEANFORMVALUE", \ + "MAIN_CERTIFICATE", \ + "MAIN_CHOICEFORMVALUE", \ + "MAIN_CLOUDCLIENT", \ + "MAIN_CLOUDMACHINE", \ + "MAIN_CLOUDNETWORK", \ + "MAIN_CLOUDNETWORKENVIRONMENTINFO", \ + "MAIN_CLOUDNETWORKGATEWAYINFO", \ + "MAIN_CLOUDPROFILE", \ + "MAIN_CLOUDPROFILECHANGEDEVENT", \ + "MAIN_CLOUDPROFILEREGISTEREDEVENT", \ + "MAIN_CLOUDPROVIDER", \ + "MAIN_CLOUDPROVIDERMANAGER", \ + "MAIN_CONSOLE", \ + "MAIN_CPUPROFILE", \ + "MAIN_DATAMODEL", \ + "MAIN_DATASTREAM", \ + "MAIN_DHCPCONFIG", \ + "MAIN_DHCPGLOBALCONFIG", \ + "MAIN_DHCPGROUPCONDITION", \ + "MAIN_DHCPGROUPCONFIG", \ + "MAIN_DHCPINDIVIDUALCONFIG", \ + "MAIN_DHCPSERVER", \ + "MAIN_DIRECTORY", \ + "MAIN_DISPLAY", \ + "MAIN_DISPLAYSOURCEBITMAP", \ + "MAIN_DNDBASE", \ + "MAIN_DNDSOURCE", \ + "MAIN_DNDTARGET", \ + "MAIN_EMULATEDUSB", \ + "MAIN_EVENT", \ + "MAIN_EVENTLISTENER", \ + "MAIN_EVENTSOURCE", \ + "MAIN_EXTPACK", \ + "MAIN_EXTPACKBASE", \ + "MAIN_EXTPACKFILE", \ + "MAIN_EXTPACKMANAGER", \ + "MAIN_EXTPACKPLUGIN", \ + "MAIN_FILE", \ + "MAIN_FORM", \ + "MAIN_FORMVALUE", \ + "MAIN_FRAMEBUFFER", \ + "MAIN_FRAMEBUFFEROVERLAY", \ + "MAIN_FSINFO", \ + "MAIN_FSOBJINFO", \ + "MAIN_GRAPHICSADAPTER", \ + "MAIN_GUEST", \ + "MAIN_GUESTDEBUGCONTROL", \ + "MAIN_GUESTDIRECTORY", \ + "MAIN_GUESTDNDSOURCE", \ + "MAIN_GUESTDNDTARGET", \ + "MAIN_GUESTERRORINFO", \ + "MAIN_GUESTFILE", \ + "MAIN_GUESTFILEEVENT", \ + "MAIN_GUESTFILEIOEVENT", \ + "MAIN_GUESTFSINFO", \ + "MAIN_GUESTFSOBJINFO", \ + "MAIN_GUESTOSTYPE", \ + "MAIN_GUESTPROCESS", \ + "MAIN_GUESTPROCESSEVENT", \ + "MAIN_GUESTPROCESSIOEVENT", \ + "MAIN_GUESTSCREENINFO", \ + "MAIN_GUESTSESSION", \ + "MAIN_GUESTSESSIONEVENT", \ + "MAIN_HOST", \ + "MAIN_HOSTAUDIODEVICE", \ + "MAIN_HOSTDRIVE", \ + "MAIN_HOSTDRIVELIST", \ + "MAIN_HOSTDRIVEPARTITION", \ + "MAIN_HOSTNETWORKINTERFACE", \ + "MAIN_HOSTONLYNETWORK", \ + "MAIN_HOSTUPDATEAGENT", \ + "MAIN_HOSTUSBDEVICE", \ + "MAIN_HOSTUSBDEVICEFILTER", \ + "MAIN_HOSTVIDEOINPUTDEVICE", \ + "MAIN_INTERNALMACHINECONTROL", \ + "MAIN_INTERNALSESSIONCONTROL", \ + "MAIN_KEYBOARD", \ + "MAIN_MACHINE", \ + "MAIN_MACHINEDEBUGGER", \ + "MAIN_MACHINEEVENT", \ + "MAIN_MEDIUM", \ + "MAIN_MEDIUMATTACHMENT", \ + "MAIN_MEDIUMFORMAT", \ + "MAIN_MEDIUMIO", \ + "MAIN_MOUSE", \ + "MAIN_MOUSEPOINTERSHAPE", \ + "MAIN_NATENGINE", \ + "MAIN_NATNETWORK", \ + "MAIN_NETWORKADAPTER", \ + "MAIN_NVRAMSTORE", \ + "MAIN_PARALLELPORT", \ + "MAIN_PCIADDRESS", \ + "MAIN_PCIDEVICEATTACHMENT", \ + "MAIN_PERFORMANCECOLLECTOR", \ + "MAIN_PERFORMANCEMETRIC", \ + "MAIN_PROCESS", \ + "MAIN_PROGRESS", \ + "MAIN_PROGRESSCREATEDEVENT", \ + "MAIN_PROGRESSEVENT", \ + "MAIN_RANGEDINTEGERFORMVALUE", \ + "MAIN_RECORDINGSCREENSETTINGS", \ + "MAIN_RECORDINGSETTINGS", \ + "MAIN_REUSABLEEVENT", \ + "MAIN_SERIALPORT", \ + "MAIN_SESSION", \ + "MAIN_SHAREDFOLDER", \ + "MAIN_SNAPSHOT", \ + "MAIN_SNAPSHOTEVENT", \ + "MAIN_STORAGECONTROLLER", \ + "MAIN_STRINGARRAY", \ + "MAIN_STRINGFORMVALUE", \ + "MAIN_SYSTEMPROPERTIES", \ + "MAIN_THREAD_TASK", \ + "MAIN_TOKEN", \ + "MAIN_TRUSTEDPLATFORMMODULE", \ + "MAIN_UEFIVARIABLESTORE", \ + "MAIN_UNATTENDED", \ + "MAIN_UPDATEAGENT", \ + "MAIN_UPDATEAGENTAVAILABLEEVENT", \ + "MAIN_UPDATEAGENTERROREVENT", \ + "MAIN_UPDATEAGENTEVENT", \ + "MAIN_UPDATEAGENTSETTINGSCHANGEDEVENT", \ + "MAIN_UPDATEAGENTSTATECHANGEDEVENT", \ + "MAIN_USBCONTROLLER", \ + "MAIN_USBDEVICE", \ + "MAIN_USBDEVICEFILTER", \ + "MAIN_USBDEVICEFILTERS", \ + "MAIN_USBPROXYBACKEND", \ + "MAIN_VBOXSVC", \ + "MAIN_VETOEVENT", \ + "MAIN_VFSEXPLORER", \ + "MAIN_VIRTUALBOX", \ + "MAIN_VIRTUALBOXCLIENT", \ + "MAIN_VIRTUALBOXSDS", \ + "MAIN_VIRTUALSYSTEMDESCRIPTION", \ + "MAIN_VIRTUALSYSTEMDESCRIPTIONFORM", \ + "MAIN_VMMDEVINTERFACES", \ + "MAIN_VRDESERVER", \ + "MAIN_VRDESERVERINFO", \ + "MISC", \ + "MM", \ + "MM_HEAP", \ + "MM_HYPER", \ + "MM_HYPER_HEAP", \ + "MM_PHYS", \ + "MM_POOL", \ + "NAT_SERVICE", \ + "NEM", \ + "NET_ADP_DRV", \ + "NET_DHCPD", \ + "NET_FLT_DRV", \ + "NET_SERVICE", \ + "NET_SHAPER", \ + "PATM", \ + "PDM", \ + "PDM_ASYNC_COMPLETION", \ + "PDM_BLK_CACHE", \ + "PDM_CRITSECT", \ + "PDM_CRITSECTRW", \ + "PDM_DEVICE", \ + "PDM_DRIVER", \ + "PDM_LDR", \ + "PDM_QUEUE", \ + "PDM_TASK", \ + "PDM_THREAD", \ + "PGM", \ + "PGM_DYNMAP", \ + "PGM_PHYS", \ + "PGM_PHYS_ACCESS", \ + "PGM_POOL", \ + "PGM_SHARED", \ + "RECORDING", \ + "REM", \ + "REM_DISAS", \ + "REM_HANDLER", \ + "REM_IOPORT", \ + "REM_MMIO", \ + "REM_PRINTF", \ + "REM_RUN", \ + "SELM", \ + "SHARED_CLIPBOARD", \ + "SHARED_CROPENGL", \ + "SHARED_FOLDERS", \ + "SHARED_OPENGL", \ + "SRV_INTNET", \ + "SSM", \ + "STAM", \ + "SUP", \ + "SUP_DRV", \ + "TM", \ + "TRPM", \ + "USB_CARDREADER", \ + "USB_DRV", \ + "USB_FILTER", \ + "USB_KBD", \ + "USB_MOUSE", \ + "USB_MSD", \ + "USB_REMOTE", \ + "USB_WEBCAM", \ + "VBGL", \ + "VD", \ + "VD_CUE", \ + "VD_DMG", \ + "VD_ISCSI", \ + "VD_PARALLELS", \ + "VD_QCOW", \ + "VD_QED", \ + "VD_RAW", \ + "VD_VDI", \ + "VD_VHD", \ + "VD_VHDX", \ + "VD_VMDK", \ + "VGDRV", \ + "VM", \ + "VMM", \ + "VRDE", \ + "VRDP", \ + "VSCSI", \ + "WEBSERVICE", \ +} + +/** @} */ +#endif /* !VBOX_INCLUDED_log_h */ diff --git a/include/VBox/msi.h b/include/VBox/msi.h new file mode 100644 index 00000000..34aae831 --- /dev/null +++ b/include/VBox/msi.h @@ -0,0 +1,287 @@ +/** @file + * MSI - Message signalled interrupts support. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_msi_h +#define VBOX_INCLUDED_msi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +#include + +/* Constants for Intel APIC MSI messages */ +#define VBOX_MSI_DATA_VECTOR_SHIFT 0 +#define VBOX_MSI_DATA_VECTOR_MASK 0x000000ff +#define VBOX_MSI_DATA_VECTOR(v) (((v) << VBOX_MSI_DATA_VECTOR_SHIFT) & \ + VBOX_MSI_DATA_VECTOR_MASK) +#define VBOX_MSI_DATA_DELIVERY_MODE_SHIFT 8 +#define VBOX_MSI_DATA_DELIVERY_FIXED (0 << VBOX_MSI_DATA_DELIVERY_MODE_SHIFT) +#define VBOX_MSI_DATA_DELIVERY_LOWPRI (1 << VBOX_MSI_DATA_DELIVERY_MODE_SHIFT) + +#define VBOX_MSI_DATA_LEVEL_SHIFT 14 +#define VBOX_MSI_DATA_LEVEL_DEASSERT (0 << VBOX_MSI_DATA_LEVEL_SHIFT) +#define VBOX_MSI_DATA_LEVEL_ASSERT (1 << VBOX_MSI_DATA_LEVEL_SHIFT) + +#define VBOX_MSI_DATA_TRIGGER_SHIFT 15 +#define VBOX_MSI_DATA_TRIGGER_EDGE (0 << VBOX_MSI_DATA_TRIGGER_SHIFT) +#define VBOX_MSI_DATA_TRIGGER_LEVEL (1 << VBOX_MSI_DATA_TRIGGER_SHIFT) + +/** + * MSI Interrupt Delivery modes. + * In accordance with the Intel spec. + * See Intel spec. "10.11.2 Message Data Register Format". + */ +#define VBOX_MSI_DELIVERY_MODE_FIXED (0) +#define VBOX_MSI_DELIVERY_MODE_LOWEST_PRIO (1) +#define VBOX_MSI_DELIVERY_MODE_SMI (2) +#define VBOX_MSI_DELIVERY_MODE_NMI (4) +#define VBOX_MSI_DELIVERY_MODE_INIT (5) +#define VBOX_MSI_DELIVERY_MODE_EXT_INT (7) + +/** + * MSI region, actually same as LAPIC MMIO region, but listens on bus, + * not CPU, accesses. + */ +#define VBOX_MSI_ADDR_BASE 0xfee00000 +#define VBOX_MSI_ADDR_SIZE 0x100000 + +#define VBOX_MSI_ADDR_SHIFT 20 + +#define VBOX_MSI_ADDR_DEST_MODE_SHIFT 2 +#define VBOX_MSI_ADDR_DEST_MODE_PHYSICAL (0 << VBOX_MSI_ADDR_DEST_MODE_SHIFT) +#define VBOX_MSI_ADDR_DEST_MODE_LOGICAL (1 << VBOX_MSI_ADDR_DEST_MODE_SHIFT) + +#define VBOX_MSI_ADDR_REDIRECTION_SHIFT 3 +#define VBOX_MSI_ADDR_REDIRECTION_CPU (0 << VBOX_MSI_ADDR_REDIRECTION_SHIFT) + /* dedicated cpu */ +#define VBOX_MSI_ADDR_REDIRECTION_LOWPRI (1 << VBOX_MSI_ADDR_REDIRECTION_SHIFT) + /* lowest priority */ + +#define VBOX_MSI_ADDR_DEST_ID_SHIFT 12 +#define VBOX_MSI_ADDR_DEST_ID_MASK 0x00ffff0 +#define VBOX_MSI_ADDR_DEST_ID(dest) (((dest) << VBOX_MSI_ADDR_DEST_ID_SHIFT) & \ + VBOX_MSI_ADDR_DEST_ID_MASK) +#define VBOX_MSI_ADDR_EXT_DEST_ID(dest) ((dest) & 0xffffff00) + +#define VBOX_MSI_ADDR_IR_EXT_INT (1 << 4) +#define VBOX_MSI_ADDR_IR_SHV (1 << 3) +#define VBOX_MSI_ADDR_IR_INDEX1(index) ((index & 0x8000) >> 13) +#define VBOX_MSI_ADDR_IR_INDEX2(index) ((index & 0x7fff) << 5) + +/* Maximum number of vectors, per device/function */ +#define VBOX_MSI_MAX_ENTRIES 32 + +/* Offsets in MSI PCI capability structure (VBOX_PCI_CAP_ID_MSI) */ +#define VBOX_MSI_CAP_MESSAGE_CONTROL 0x02 +#define VBOX_MSI_CAP_MESSAGE_ADDRESS_32 0x04 +#define VBOX_MSI_CAP_MESSAGE_ADDRESS_LO 0x04 +#define VBOX_MSI_CAP_MESSAGE_ADDRESS_HI 0x08 +#define VBOX_MSI_CAP_MESSAGE_DATA_32 0x08 +#define VBOX_MSI_CAP_MESSAGE_DATA_64 0x0c +#define VBOX_MSI_CAP_MASK_BITS_32 0x0c +#define VBOX_MSI_CAP_PENDING_BITS_32 0x10 +#define VBOX_MSI_CAP_MASK_BITS_64 0x10 +#define VBOX_MSI_CAP_PENDING_BITS_64 0x14 + +/* We implement MSI with per-vector masking */ +#define VBOX_MSI_CAP_SIZE_32 0x14 +#define VBOX_MSI_CAP_SIZE_64 0x18 + +/** + * MSI-X differs from MSI by the fact that a dedicated physical page (in device + * memory) is assigned for MSI-X table, and Pending Bit Array (PBA), which is + * recommended to be separated from the main table by at least 2K. + * + * @{ + */ +/** Size of a MSI-X page */ +#define VBOX_MSIX_PAGE_SIZE 0x1000 +/** Pending interrupts (PBA) */ +#define VBOX_MSIX_PAGE_PENDING (VBOX_MSIX_PAGE_SIZE / 2) +/** Maximum number of vectors, per device/function */ +#define VBOX_MSIX_MAX_ENTRIES 2048 +/** Size of MSI-X PCI capability */ +#define VBOX_MSIX_CAP_SIZE 12 +/** Offsets in MSI-X PCI capability structure (VBOX_PCI_CAP_ID_MSIX) */ +#define VBOX_MSIX_CAP_MESSAGE_CONTROL 0x02 +#define VBOX_MSIX_TABLE_BIROFFSET 0x04 +#define VBOX_MSIX_PBA_BIROFFSET 0x08 +/** Size of single MSI-X table entry */ +#define VBOX_MSIX_ENTRY_SIZE 16 +/** @} */ + +/** + * MSI Address Register. + */ +typedef union MSIADDR +{ + /* + * Intel and AMD xAPIC format. + * See Intel spec. 10.11.1 "Message Address Register Format". + * This also conforms to the AMD IOMMU spec. which omits specifying + * individual fields but specifies reserved bits. + */ + struct + { + uint32_t u2Ign0 : 2; /**< Bits 1:0 - Ignored (read as 0, writes ignored). */ + uint32_t u1DestMode : 1; /**< Bit 2 - DM: Destination Mode. */ + uint32_t u1RedirHint : 1; /**< Bit 3 - RH: Redirection Hint. */ + uint32_t u8Rsvd0 : 8; /**< Bits 11:4 - Reserved. */ + uint32_t u8DestId : 8; /**< Bits 19:12 - Destination Id. */ + uint32_t u12Addr : 12; /**< Bits 31:20 - Address. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved. */ + } n; + + /* + * Intel x2APIC Format. + * See Intel VT-d spec. 5.1.6.2 "Programming in Intel 64 x2APIC Mode". + */ + struct + { + uint32_t u2Ign0 : 2; /**< Bits 1:0 - Ignored (read as 0, writes ignored). */ + uint32_t u1DestMode : 1; /**< Bit 2 - DM: Destination Mode. */ + uint32_t u1RedirHint : 1; /**< Bit 3 - RH: Redirection Hint. */ + uint32_t u8Rsvd0 : 8; /**< Bits 11:4 - Reserved. */ + uint32_t u8DestIdLo : 8; /**< Bits 19:12 - Destination Id (bits 7:0). */ + uint32_t u12Addr : 12; /**< Bits 31:20 - Address. */ + uint32_t u8Rsvd : 8; /**< Bits 39:32 - Reserved. */ + uint32_t u24DestIdHi : 24; /**< Bits 63:40 - Destination Id (bits 31:8). */ + } x2apic; + + /* + * Intel IOMMU Remappable Interrupt Format. + * See Intel VT-d spec. 5.1.2.2 "Interrupt Requests in Remappable Format". + */ + struct + { + uint32_t u2Ign0 : 2; /**< Bits 1:0 - Ignored (read as 0, writes ignored). */ + uint32_t u1IntrIndexHi : 1; /**< Bit 2 - Interrupt Index[15]. */ + uint32_t fShv : 1; /**< Bit 3 - Sub-Handle Valid. */ + uint32_t fIntrFormat : 1; /**< Bit 4 - Interrupt Format (1=remappable, 0=compatibility). */ + uint32_t u14IntrIndexLo : 15; /**< Bits 19:5 - Interrupt Index[14:0]. */ + uint32_t u12Addr : 12; /**< Bits 31:20 - Address. */ + uint32_t u32Rsvd0; /**< Bits 63:32 - Reserved. */ + } dmar_remap; + + /** The 32-bit unsigned integer view. */ + uint32_t au32[2]; + + /** The 64-bit unsigned integer view. */ + uint64_t u64; +} MSIADDR; +AssertCompileSize(MSIADDR, 8); +/** Pointer to an MSI address register. */ +typedef MSIADDR *PMSIADDR; +/** Pointer to a const MSI address register. */ +typedef MSIADDR const *PCMSIADDR; + +/** Mask of valid bits in the MSI address register. According to the AMD IOMMU spec. + * and presumably the PCI spec., the top 32-bits are not reserved. From a PCI/IOMMU + * standpoint this makes sense. However, when dealing with the CPU side of things + * we might want to ensure the upper bits are reserved. Does x86/x64 really + * support a 64-bit MSI address? */ +#define VBOX_MSI_ADDR_VALID_MASK UINT64_C(0xfffffffffffffffc) +#define VBOX_MSI_ADDR_ADDR_MASK UINT64_C(0x00000000fff00000) + +/** + * MSI Data Register. + */ +typedef union MSIDATA +{ + /* + * Intel and AMD xAPIC format. + * See Intel spec. 10.11.2 "Message Data Register Format". + * This also conforms to the AMD IOMMU spec. which omits specifying + * individual fields but specifies reserved bits. + */ + struct + { + uint32_t u8Vector : 8; /**< Bits 7:0 - Vector. */ + uint32_t u3DeliveryMode : 3; /**< Bits 10:8 - Delivery Mode. */ + uint32_t u3Rsvd0 : 3; /**< Bits 13:11 - Reserved. */ + uint32_t u1Level : 1; /**< Bit 14 - Level. */ + uint32_t u1TriggerMode : 1; /**< Bit 15 - Trigger Mode (0=edge, 1=level). */ + uint32_t u16Rsvd0 : 16; /**< Bits 31:16 - Reserved. */ + } n; + + /* + * Intel x2APIC Format. + * See Intel VT-d spec. 5.1.6.2 "Programming in Intel 64 x2APIC Mode". + */ + struct + { + uint32_t u8Vector : 8; /**< Bits 7:0 - Vector. */ + uint32_t u1DeliveryMode : 1; /**< Bit 8 - Delivery Mode (0=fixed, 1=lowest priority). */ + uint32_t u23Rsvd0 : 23; /**< Bits 31:9 - Reserved. */ + } x2apic; + + /* + * Intel IOMMU Remappable Interrupt Format. + * See Intel VT-d spec. 5.1.2.2 "Interrupt Requests in Remappable Format". + */ + struct + { + uint16_t u16SubHandle; + uint16_t u16Rsvd0; + } dmar_remap; + + /** The 32-bit unsigned integer view. */ + uint32_t u32; +} MSIDATA; +AssertCompileSize(MSIDATA, 4); +/** Pointer to an MSI data register. */ +typedef MSIDATA *PMSIDATA; +/** Pointer to a const MSI data register. */ +typedef MSIDATA const *PCMSIDATA; + +/** Mask of valid bits in the MSI data register. */ +#define VBOX_MSI_DATA_VALID_MASK UINT64_C(0x000000000000ffff) + +/** + * MSI Message (Address and Data Register Pair). + */ +typedef struct MSIMSG +{ + /** The MSI Address Register. */ + MSIADDR Addr; + /** The MSI Data Register. */ + MSIDATA Data; +} MSIMSG; + +#endif /* !VBOX_INCLUDED_msi_h */ diff --git a/include/VBox/nasm.mac b/include/VBox/nasm.mac new file mode 100644 index 00000000..13abd88b --- /dev/null +++ b/include/VBox/nasm.mac @@ -0,0 +1,44 @@ +;; @file +; Global NASM macros +; +; @deprecated Use VBox/asmdefs.mac +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef __VBox_nasm_mac__ +%define __VBox_nasm_mac__ + +%include "VBox/asmdefs.mac" + +%endif + diff --git a/include/VBox/ostypes.h b/include/VBox/ostypes.h new file mode 100644 index 00000000..8b82da43 --- /dev/null +++ b/include/VBox/ostypes.h @@ -0,0 +1,305 @@ +/** @file + * VirtualBox - Global Guest Operating System definition. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_ostypes_h +#define VBOX_INCLUDED_ostypes_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** + * Global list of guest operating system types. + * + * They are grouped into families. A family identifer is always has + * mod 0x10000 == 0. New entries can be added, however other components + * depend on the values (e.g. the Qt GUI and guest additions) so the + * existing values MUST stay the same. + */ +typedef enum VBOXOSTYPE +{ + VBOXOSTYPE_Unknown = 0, + VBOXOSTYPE_Unknown_x64 = 0x00100, + + /** @name DOS and it's descendants + * @{ */ + VBOXOSTYPE_DOS = 0x10000, + VBOXOSTYPE_Win31 = 0x15000, + VBOXOSTYPE_Win9x = 0x20000, + VBOXOSTYPE_Win95 = 0x21000, + VBOXOSTYPE_Win98 = 0x22000, + VBOXOSTYPE_WinMe = 0x23000, + VBOXOSTYPE_WinNT = 0x30000, + VBOXOSTYPE_WinNT_x64 = 0x30100, + VBOXOSTYPE_WinNT3x = 0x30800, + VBOXOSTYPE_WinNT4 = 0x31000, + VBOXOSTYPE_Win2k = 0x32000, + VBOXOSTYPE_WinXP = 0x33000, + VBOXOSTYPE_WinXP_x64 = 0x33100, + VBOXOSTYPE_Win2k3 = 0x34000, + VBOXOSTYPE_Win2k3_x64 = 0x34100, + VBOXOSTYPE_WinVista = 0x35000, + VBOXOSTYPE_WinVista_x64 = 0x35100, + VBOXOSTYPE_Win2k8 = 0x36000, + VBOXOSTYPE_Win2k8_x64 = 0x36100, + VBOXOSTYPE_Win7 = 0x37000, + VBOXOSTYPE_Win7_x64 = 0x37100, + VBOXOSTYPE_Win8 = 0x38000, + VBOXOSTYPE_Win8_x64 = 0x38100, + VBOXOSTYPE_Win2k12_x64 = 0x39100, + VBOXOSTYPE_Win81 = 0x3A000, + VBOXOSTYPE_Win81_x64 = 0x3A100, + VBOXOSTYPE_Win10 = 0x3B000, + VBOXOSTYPE_Win10_x64 = 0x3B100, + VBOXOSTYPE_Win2k16_x64 = 0x3C100, + VBOXOSTYPE_Win2k19_x64 = 0x3D100, + VBOXOSTYPE_Win11_x64 = 0x3E100, + VBOXOSTYPE_Win2k22_x64 = 0x3F100, + VBOXOSTYPE_OS2 = 0x40000, + VBOXOSTYPE_OS2Warp3 = 0x41000, + VBOXOSTYPE_OS2Warp4 = 0x42000, + VBOXOSTYPE_OS2Warp45 = 0x43000, + VBOXOSTYPE_ECS = 0x44000, + VBOXOSTYPE_ArcaOS = 0x45000, + VBOXOSTYPE_OS21x = 0x48000, + /** @} */ + /** @name Unixy related OSes + * @{ */ + VBOXOSTYPE_Linux = 0x50000, + VBOXOSTYPE_Linux_x64 = 0x50100, + VBOXOSTYPE_Linux22 = 0x51000, + VBOXOSTYPE_Linux24 = 0x52000, + VBOXOSTYPE_Linux24_x64 = 0x52100, + VBOXOSTYPE_Linux26 = 0x53000, + VBOXOSTYPE_Linux26_x64 = 0x53100, + VBOXOSTYPE_ArchLinux = 0x54000, + VBOXOSTYPE_ArchLinux_x64 = 0x54100, + VBOXOSTYPE_Debian = 0x55000, + VBOXOSTYPE_Debian_x64 = 0x55100, + VBOXOSTYPE_Debian31 = 0x55001, // 32-bit only + VBOXOSTYPE_Debian4 = 0x55002, + VBOXOSTYPE_Debian4_x64 = 0x55102, + VBOXOSTYPE_Debian5 = 0x55003, + VBOXOSTYPE_Debian5_x64 = 0x55103, + VBOXOSTYPE_Debian6 = 0x55004, + VBOXOSTYPE_Debian6_x64 = 0x55104, + VBOXOSTYPE_Debian7 = 0x55005, + VBOXOSTYPE_Debian7_x64 = 0x55105, + VBOXOSTYPE_Debian8 = 0x55006, + VBOXOSTYPE_Debian8_x64 = 0x55106, + VBOXOSTYPE_Debian9 = 0x55007, + VBOXOSTYPE_Debian9_x64 = 0x55107, + VBOXOSTYPE_Debian10 = 0x55008, + VBOXOSTYPE_Debian10_x64 = 0x55108, + VBOXOSTYPE_Debian11 = 0x55009, + VBOXOSTYPE_Debian11_x64 = 0x55109, + VBOXOSTYPE_Debian_latest_x64 = VBOXOSTYPE_Debian11_x64, + VBOXOSTYPE_OpenSUSE = 0x56000, + VBOXOSTYPE_OpenSUSE_x64 = 0x56100, + VBOXOSTYPE_OpenSUSE_Leap_x64 = 0x56101, // 64-bit only + VBOXOSTYPE_OpenSUSE_Tumbleweed = 0x56002, + VBOXOSTYPE_OpenSUSE_Tumbleweed_x64 = 0x56102, + VBOXOSTYPE_SUSE_LE = 0x56003, + VBOXOSTYPE_SUSE_LE_x64 = 0x56103, + VBOXOSTYPE_FedoraCore = 0x57000, + VBOXOSTYPE_FedoraCore_x64 = 0x57100, + VBOXOSTYPE_Gentoo = 0x58000, + VBOXOSTYPE_Gentoo_x64 = 0x58100, + VBOXOSTYPE_Mandriva = 0x59000, + VBOXOSTYPE_Mandriva_x64 = 0x59100, + VBOXOSTYPE_OpenMandriva_Lx = 0x59001, + VBOXOSTYPE_OpenMandriva_Lx_x64 = 0x59101, + VBOXOSTYPE_PCLinuxOS = 0x59002, + VBOXOSTYPE_PCLinuxOS_x64 = 0x59102, + VBOXOSTYPE_Mageia = 0x59003, + VBOXOSTYPE_Mageia_x64 = 0x59103, + VBOXOSTYPE_RedHat = 0x5A000, + VBOXOSTYPE_RedHat_x64 = 0x5A100, + VBOXOSTYPE_RedHat3 = 0x5A001, + VBOXOSTYPE_RedHat3_x64 = 0x5A101, + VBOXOSTYPE_RedHat4 = 0x5A002, + VBOXOSTYPE_RedHat4_x64 = 0x5A102, + VBOXOSTYPE_RedHat5 = 0x5A003, + VBOXOSTYPE_RedHat5_x64 = 0x5A103, + VBOXOSTYPE_RedHat6 = 0x5A004, + VBOXOSTYPE_RedHat6_x64 = 0x5A104, + VBOXOSTYPE_RedHat7_x64 = 0x5A105, // 64-bit only + VBOXOSTYPE_RedHat8_x64 = 0x5A106, // 64-bit only + VBOXOSTYPE_RedHat9_x64 = 0x5A107, // 64-bit only + VBOXOSTYPE_RedHat_latest_x64 = VBOXOSTYPE_RedHat9_x64, + VBOXOSTYPE_Turbolinux = 0x5B000, + VBOXOSTYPE_Turbolinux_x64 = 0x5B100, + VBOXOSTYPE_Ubuntu = 0x5C000, + VBOXOSTYPE_Ubuntu_x64 = 0x5C100, + VBOXOSTYPE_Xubuntu = 0x5C001, + VBOXOSTYPE_Xubuntu_x64 = 0x5C101, + VBOXOSTYPE_Lubuntu = 0x5C002, + VBOXOSTYPE_Lubuntu_x64 = 0x5C102, + VBOXOSTYPE_Ubuntu10_LTS = 0x5C003, + VBOXOSTYPE_Ubuntu10_LTS_x64 = 0x5C103, + VBOXOSTYPE_Ubuntu10 = 0x5C004, + VBOXOSTYPE_Ubuntu10_x64 = 0x5C104, + VBOXOSTYPE_Ubuntu11 = 0x5C005, + VBOXOSTYPE_Ubuntu11_x64 = 0x5C105, + VBOXOSTYPE_Ubuntu12_LTS = 0x5C006, + VBOXOSTYPE_Ubuntu12_LTS_x64 = 0x5C106, + VBOXOSTYPE_Ubuntu12 = 0x5C007, + VBOXOSTYPE_Ubuntu12_x64 = 0x5C107, + VBOXOSTYPE_Ubuntu13 = 0x5C008, + VBOXOSTYPE_Ubuntu13_x64 = 0x5C108, + VBOXOSTYPE_Ubuntu14_LTS = 0x5C009, + VBOXOSTYPE_Ubuntu14_LTS_x64 = 0x5C109, + VBOXOSTYPE_Ubuntu14 = 0x5C00a, + VBOXOSTYPE_Ubuntu14_x64 = 0x5C10a, + VBOXOSTYPE_Ubuntu15 = 0x5C00b, + VBOXOSTYPE_Ubuntu15_x64 = 0x5C10b, + VBOXOSTYPE_Ubuntu16_LTS = 0x5C00c, + VBOXOSTYPE_Ubuntu16_LTS_x64 = 0x5C10c, + VBOXOSTYPE_Ubuntu16 = 0x5C00d, + VBOXOSTYPE_Ubuntu16_x64 = 0x5C10d, + VBOXOSTYPE_Ubuntu17 = 0x5C00e, + VBOXOSTYPE_Ubuntu17_x64 = 0x5C10e, + VBOXOSTYPE_Ubuntu18_LTS = 0x5C00f, + VBOXOSTYPE_Ubuntu18_LTS_x64 = 0x5C10f, + VBOXOSTYPE_Ubuntu18 = 0x5C010, + VBOXOSTYPE_Ubuntu18_x64 = 0x5C110, + VBOXOSTYPE_Ubuntu19 = 0x5C011, + VBOXOSTYPE_Ubuntu19_x64 = 0x5C111, + VBOXOSTYPE_Ubuntu20_LTS_x64 = 0x5C112, // 64-bit only + VBOXOSTYPE_Ubuntu20_x64 = 0x5C113, // 64-bit only + VBOXOSTYPE_Ubuntu21_x64 = 0x5C114, // 64-bit only + VBOXOSTYPE_Ubuntu22_LTS_x64 = 0x5C115, // 64-bit only + VBOXOSTYPE_Ubuntu22_x64 = 0x5C116, // 64-bit only + VBOXOSTYPE_Ubuntu_latest_x64 = VBOXOSTYPE_Ubuntu22_x64, + VBOXOSTYPE_Xandros = 0x5D000, + VBOXOSTYPE_Xandros_x64 = 0x5D100, + VBOXOSTYPE_Oracle = 0x5E000, + VBOXOSTYPE_Oracle_x64 = 0x5E100, + VBOXOSTYPE_Oracle4 = 0x5E001, + VBOXOSTYPE_Oracle4_x64 = 0x5E101, + VBOXOSTYPE_Oracle5 = 0x5E002, + VBOXOSTYPE_Oracle5_x64 = 0x5E102, + VBOXOSTYPE_Oracle6 = 0x5E003, + VBOXOSTYPE_Oracle6_x64 = 0x5E103, + VBOXOSTYPE_Oracle7_x64 = 0x5E104, // 64-bit only + VBOXOSTYPE_Oracle8_x64 = 0x5E105, // 64-bit only + VBOXOSTYPE_Oracle9_x64 = 0x5E106, // 64-bit only + VBOXOSTYPE_Oracle_latest_x64 = VBOXOSTYPE_Oracle9_x64, + VBOXOSTYPE_FreeBSD = 0x60000, + VBOXOSTYPE_FreeBSD_x64 = 0x60100, + VBOXOSTYPE_OpenBSD = 0x61000, + VBOXOSTYPE_OpenBSD_x64 = 0x61100, + VBOXOSTYPE_NetBSD = 0x62000, + VBOXOSTYPE_NetBSD_x64 = 0x62100, + VBOXOSTYPE_Netware = 0x70000, + VBOXOSTYPE_Solaris = 0x80000, // Solaris 10U7 (5/09) and earlier + VBOXOSTYPE_Solaris_x64 = 0x80100, // Solaris 10U7 (5/09) and earlier + VBOXOSTYPE_Solaris10U8_or_later = 0x80001, + VBOXOSTYPE_Solaris10U8_or_later_x64 = 0x80101, + VBOXOSTYPE_OpenSolaris = 0x81000, + VBOXOSTYPE_OpenSolaris_x64 = 0x81100, + VBOXOSTYPE_Solaris11_x64 = 0x82100, + VBOXOSTYPE_L4 = 0x90000, + VBOXOSTYPE_QNX = 0xA0000, + VBOXOSTYPE_MacOS = 0xB0000, + VBOXOSTYPE_MacOS_x64 = 0xB0100, + VBOXOSTYPE_MacOS106 = 0xB2000, + VBOXOSTYPE_MacOS106_x64 = 0xB2100, + VBOXOSTYPE_MacOS107_x64 = 0xB3100, + VBOXOSTYPE_MacOS108_x64 = 0xB4100, + VBOXOSTYPE_MacOS109_x64 = 0xB5100, + VBOXOSTYPE_MacOS1010_x64 = 0xB6100, + VBOXOSTYPE_MacOS1011_x64 = 0xB7100, + VBOXOSTYPE_MacOS1012_x64 = 0xB8100, + VBOXOSTYPE_MacOS1013_x64 = 0xB9100, + /** @} */ + /** @name Other OSes and stuff + * @{ */ + VBOXOSTYPE_JRockitVE = 0xC0000, + VBOXOSTYPE_Haiku = 0xD0000, + VBOXOSTYPE_Haiku_x64 = 0xD0100, + VBOXOSTYPE_VBoxBS_x64 = 0xE0100, + /** @} */ + + /** OS type mask. */ + VBOXOSTYPE_OsTypeMask = 0x00fff000, + + /** @name Architecture Type + * @{ */ + /** Mask containing the architecture value. */ + VBOXOSTYPE_ArchitectureMask = 0x00f00, + /** Architecture value for 16-bit and 32-bit x86. */ + VBOXOSTYPE_x86 = 0x00000, + /** Architecture value for 64-bit x86 (AMD64). */ + VBOXOSTYPE_x64 = 0x00100, + /** Architecture value for 32-bit ARM. */ + VBOXOSTYPE_arm32 = 0x00200, + /** Architecture value for 64-bit ARM. */ + VBOXOSTYPE_arm64 = 0x00300, + /** Architecture value for unknown or unsupported architectures. */ + VBOXOSTYPE_UnknownArch = 0x00f00, + /** @} */ + + /** The usual 32-bit hack. */ + VBOXOSTYPE_32BIT_HACK = 0x7fffffff +} VBOXOSTYPE; + + +/** + * Global list of guest OS families. + */ +typedef enum VBOXOSFAMILY +{ + VBOXOSFAMILY_Unknown = 0, + VBOXOSFAMILY_Windows32 = 1, + VBOXOSFAMILY_Windows64 = 2, + VBOXOSFAMILY_Linux32 = 3, + VBOXOSFAMILY_Linux64 = 4, + VBOXOSFAMILY_FreeBSD32 = 5, + VBOXOSFAMILY_FreeBSD64 = 6, + VBOXOSFAMILY_Solaris32 = 7, + VBOXOSFAMILY_Solaris64 = 8, + VBOXOSFAMILY_MacOSX32 = 9, + VBOXOSFAMILY_MacOSX64 = 10, + /** The usual 32-bit hack. */ + VBOXOSFAMILY_32BIT_HACK = 0x7fffffff +} VBOXOSFAMILY; + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_ostypes_h */ diff --git a/include/VBox/param.h b/include/VBox/param.h new file mode 100644 index 00000000..fb6e5ddc --- /dev/null +++ b/include/VBox/param.h @@ -0,0 +1,229 @@ +/** @file + * VirtualBox Parameter Definitions. (VMM,+) + * + * param.mac is generated from this file by running 'kmk incs' in the root. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_param_h +#define VBOX_INCLUDED_param_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_vbox_param VBox Parameter Definition + * @{ + */ + +/** The guest page size (x86). */ +#define GUEST_PAGE_SIZE 0x1000 +/** The guest page offset mask (x86). + * @note If one-complementing this, always put a typecast after the operator! */ +#define GUEST_PAGE_OFFSET_MASK 0xfff +/** The guest page shift (x86). */ +#define GUEST_PAGE_SHIFT 12 + +/** Host page size. */ +#define HOST_PAGE_SIZE PAGE_SIZE +/** Host page offset mask. + * @note If one-complementing this, always put a typecast after the operator! */ +#define HOST_PAGE_OFFSET_MASK PAGE_OFFSET_MASK +/** Host page shift. */ +#define HOST_PAGE_SHIFT PAGE_SHIFT + + +/** The maximum number of pages that can be allocated and mapped + * by various MM, PGM and SUP APIs. */ +#if ARCH_BITS == 64 +# define VBOX_MAX_ALLOC_PAGE_COUNT (_512M / PAGE_SIZE) +#else +# define VBOX_MAX_ALLOC_PAGE_COUNT (_256M / PAGE_SIZE) +#endif + +/** @def VBOX_WITH_PAGE_SHARING + * Enables the page sharing code. + * @remarks This must match GMMR0Init; currently we only support page fusion on + * all 64-bit hosts except Mac OS X */ +#if ( HC_ARCH_BITS == 64 /* ASM-NOINC */ \ + && (defined(RT_OS_FREEBSD) || defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS)) ) /* ASM-NOINC */ \ + || defined(DOXYGEN_RUNNING) /* ASM-NOINC */ +# define VBOX_WITH_PAGE_SHARING /* ASM-NOINC */ +#endif /* ASM-NOINC */ + + +/** @defgroup grp_vbox_param_mm Memory Monitor Parameters + * @{ + */ +/** Initial address of Hypervisor Memory Area. + * MUST BE PAGE TABLE ALIGNED! */ +#define MM_HYPER_AREA_ADDRESS UINT32_C(0xa0000000) + +/** The max size of the hypervisor memory area. */ +#define MM_HYPER_AREA_MAX_SIZE (40U * _1M) /**< @todo Readjust when floating RAMRANGEs have been implemented. Used to be 20 * _1MB */ + +/** Maximum number of bytes we can dynamically map into the hypervisor region. + * This must be a power of 2 number of pages! + */ +#define MM_HYPER_DYNAMIC_SIZE (16U * PAGE_SIZE) + +/** The minimum guest RAM size in bytes. */ +#define MM_RAM_MIN UINT32_C(0x00400000) +/** The maximum guest RAM size in bytes. */ +#if HC_ARCH_BITS == 64 +# define MM_RAM_MAX UINT64_C(0x20000000000) +#else +# define MM_RAM_MAX UINT64_C(0x000E0000000) +#endif +/** The minimum guest RAM size in MBs. */ +#define MM_RAM_MIN_IN_MB UINT32_C(4) +/** The maximum guest RAM size in MBs. */ +#if HC_ARCH_BITS == 64 +# define MM_RAM_MAX_IN_MB UINT32_C(2097152) +#else +# define MM_RAM_MAX_IN_MB UINT32_C(3584) +#endif +/** The default size of the below 4GB RAM hole. */ +#define MM_RAM_HOLE_SIZE_DEFAULT (512U * _1M) +/** The maximum 64-bit MMIO BAR size. + * @remarks There isn't really any limit here other than the size of the + * tracking structures we need (around 1/256 of the size). */ +#if HC_ARCH_BITS == 64 +# define MM_MMIO_64_MAX _1T +#else +# define MM_MMIO_64_MAX (_1G64 * 16) +#endif +/** The maximum 32-bit MMIO BAR size. */ +#define MM_MMIO_32_MAX _2G + +/** @} */ + +/** @defgroup grp_vbox_param_pdm Pluggable Device Manager Parameters + * @{ + */ +/** Max number of network shaper groups. */ +#define PDM_NET_SHAPER_MAX_GROUPS 32 +/** Max length of a network shaper group name (excluding terminator). */ +#define PDM_NET_SHAPER_MAX_NAME_LEN 63 +/** @} */ + + +/** @defgroup grp_vbox_param_pgm Page Manager Parameters + * @{ + */ +/** The number of handy pages. + * This should be a power of two. */ +#define PGM_HANDY_PAGES 128 +/** The threshold at which allocation of more handy pages is flagged. */ +#define PGM_HANDY_PAGES_SET_FF 32 +/** The threshold at which we will allocate more when in ring-3. + * This is must be smaller than both PGM_HANDY_PAGES_SET_FF and + * PGM_HANDY_PAGES_MIN. */ +#define PGM_HANDY_PAGES_R3_ALLOC 8 +/** The threshold at which we will allocate more when in ring-0 or raw mode. + * The idea is that we should never go below this threshold while in ring-0 or + * raw mode because of PGM_HANDY_PAGES_RZ_TO_R3. However, should this happen and + * we are actually out of memory, we will have 8 page to get out of whatever + * code we're executing. + * + * This is must be smaller than both PGM_HANDY_PAGES_SET_FF and + * PGM_HANDY_PAGES_MIN. */ +#define PGM_HANDY_PAGES_RZ_ALLOC 8 +/** The threshold at which we force return to R3 ASAP. + * The idea is that this should be large enough to get out of any code and up to + * the main EM loop when we are out of memory. + * This must be less or equal to PGM_HANDY_PAGES_MIN. */ +#define PGM_HANDY_PAGES_RZ_TO_R3 24 +/** The minimum number of handy pages (after allocation). + * This must be greater or equal to PGM_HANDY_PAGES_SET_FF. + * Another name would be PGM_HANDY_PAGES_EXTRA_RESERVATION or _PARANOIA. :-) */ +#define PGM_HANDY_PAGES_MIN 32 +/** @} */ + + +/** @defgroup grp_vbox_param_vmm VMM Parameters + * @{ + */ +/** VMM stack size. */ +#ifdef RT_OS_DARWIN +# define VMM_STACK_SIZE 16384U +#else +# define VMM_STACK_SIZE 8192U +#endif +/** Min number of Virtual CPUs. */ +#define VMM_MIN_CPU_COUNT 1 +/** Max number of Virtual CPUs. */ +#define VMM_MAX_CPU_COUNT 64 + +/** @} */ + + +/** @defgroup grp_vbox_pci PCI Identifiers + * @{ */ +/** VirtualBox PCI vendor ID. */ +#define VBOX_PCI_VENDORID (0x80ee) + +/** @name VirtualBox graphics card identifiers + * @{ */ +#define VBOX_VENDORID VBOX_PCI_VENDORID /**< @todo wonderful choice of name! Please squeeze a _VGA_ or something in there, please. */ +#define VBOX_DEVICEID (0xbeef) /**< @todo ditto. */ +#define VBOX_VESA_VENDORID VBOX_PCI_VENDORID +#define VBOX_VESA_DEVICEID (0xbeef) +/** @} */ + +/** @name VMMDev PCI card identifiers + * @{ */ +#define VMMDEV_VENDORID VBOX_PCI_VENDORID +#define VMMDEV_DEVICEID (0xcafe) +/** @} */ + +/** @} */ + + +/** @defgroup grp_vbox_param_misc Misc + * @{ */ + +/** The maximum size of a generic segment offload (GSO) frame. This limit is + * imposed by the 16-bit frame size in internal networking header. */ +#define VBOX_MAX_GSO_SIZE 0xfff0 + +/** @} */ + + +/** @} */ + +#endif /* !VBOX_INCLUDED_param_h */ + diff --git a/include/VBox/param.mac b/include/VBox/param.mac new file mode 100644 index 00000000..b35a5f45 --- /dev/null +++ b/include/VBox/param.mac @@ -0,0 +1,98 @@ +;; @file +; VirtualBox Parameter Definitions. (VMM,+) +; +; Automatically generated by various.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef VBOX_INCLUDED_param_h +%define VBOX_INCLUDED_param_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%define GUEST_PAGE_SIZE 0x1000 +%define GUEST_PAGE_OFFSET_MASK 0xfff +%define GUEST_PAGE_SHIFT 12 +%define HOST_PAGE_SIZE PAGE_SIZE +%define HOST_PAGE_OFFSET_MASK PAGE_OFFSET_MASK +%define HOST_PAGE_SHIFT PAGE_SHIFT +%if ARCH_BITS == 64 + %define VBOX_MAX_ALLOC_PAGE_COUNT (_512M / PAGE_SIZE) +%else + %define VBOX_MAX_ALLOC_PAGE_COUNT (_256M / PAGE_SIZE) +%endif +%define MM_HYPER_AREA_ADDRESS 0xa0000000 +%define MM_HYPER_AREA_MAX_SIZE (40U * _1M) +%define MM_HYPER_DYNAMIC_SIZE (16U * PAGE_SIZE) +%define MM_RAM_MIN 0x00400000 +%if HC_ARCH_BITS == 64 + %define MM_RAM_MAX 0x20000000000 +%else + %define MM_RAM_MAX 0x000E0000000 +%endif +%define MM_RAM_MIN_IN_MB 4 +%if HC_ARCH_BITS == 64 + %define MM_RAM_MAX_IN_MB 2097152 +%else + %define MM_RAM_MAX_IN_MB 3584 +%endif +%define MM_RAM_HOLE_SIZE_DEFAULT (512U * _1M) +%if HC_ARCH_BITS == 64 + %define MM_MMIO_64_MAX _1T +%else + %define MM_MMIO_64_MAX (_1G64 * 16) +%endif +%define MM_MMIO_32_MAX _2G +%define PDM_NET_SHAPER_MAX_GROUPS 32 +%define PDM_NET_SHAPER_MAX_NAME_LEN 63 +%define PGM_HANDY_PAGES 128 +%define PGM_HANDY_PAGES_SET_FF 32 +%define PGM_HANDY_PAGES_R3_ALLOC 8 +%define PGM_HANDY_PAGES_RZ_ALLOC 8 +%define PGM_HANDY_PAGES_RZ_TO_R3 24 +%define PGM_HANDY_PAGES_MIN 32 +%ifdef RT_OS_DARWIN + %define VMM_STACK_SIZE 16384 +%else + %define VMM_STACK_SIZE 8192 +%endif +%define VMM_MIN_CPU_COUNT 1 +%define VMM_MAX_CPU_COUNT 64 +%define VBOX_PCI_VENDORID (0x80ee) +%define VBOX_VENDORID VBOX_PCI_VENDORID +%define VBOX_DEVICEID (0xbeef) +%define VBOX_VESA_VENDORID VBOX_PCI_VENDORID +%define VBOX_VESA_DEVICEID (0xbeef) +%define VMMDEV_VENDORID VBOX_PCI_VENDORID +%define VMMDEV_DEVICEID (0xcafe) +%define VBOX_MAX_GSO_SIZE 0xfff0 +%endif diff --git a/include/VBox/pci.h b/include/VBox/pci.h new file mode 100644 index 00000000..8d5054fe --- /dev/null +++ b/include/VBox/pci.h @@ -0,0 +1,827 @@ +/** @file + * PCI - The PCI Controller And Devices Constants. (DEV) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_pci_h +#define VBOX_INCLUDED_pci_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +/** @defgroup grp_pci PCI - The PCI Controller. + * @ingroup grp_devdrv + * @{ + */ + +/** @name PCI device classes. + * @{ */ +#define VBOX_PCI_CLASS_UNCLASSIFIED 0x00 +#define VBOX_PCI_CLASS_MASS_STORAGE 0x01 +#define VBOX_PCI_CLASS_NETWORK 0x02 +#define VBOX_PCI_CLASS_DISPLAY 0x03 +#define VBOX_PCI_CLASS_MULTI_MEDIA 0x04 +#define VBOX_PCI_CLASS_MEMORY 0x05 +#define VBOX_PCI_CLASS_BRIDGE 0x06 +#define VBOX_PCI_CLASS_COMM 0x07 +#define VBOX_PCI_CLASS_SYSTEM 0x08 +#define VBOX_PCI_CLASS_INPUT 0x09 +#define VBOX_PCI_CLASS_DOCKING_STATION 0x0a +#define VBOX_PCI_CLASS_PROCESSOR 0x0b +#define VBOX_PCI_CLASS_SERIAL_BUS 0x0c +#define VBOX_PCI_CLASS_WIRELESS 0x0d +#define VBOX_PCI_CLASS_INTELLIGENT 0x0e +#define VBOX_PCI_CLASS_SAT_COMM 0x0f +#define VBOX_PCI_CLASS_ENCRYPTION 0x10 +#define VBOX_PCI_CLASS_SIG_PROC 0x11 +#define VBOX_PCI_CLASS_PROC_ACCEL 0x12 +#define VBOX_PCI_CLASS_NON_ESS_INSTR 0x13 +#define VBOX_PCI_CLASS_CO_PROCESSOR 0x40 +#define VBOX_PCI_CLASS_UNASSIGNED 0xff +/** @} */ + +/** @name PCI device sub-classes. + * @{ */ +#define VBOX_PCI_SUB_UNCLASSIFIED_NON_VGA 0x00 +#define VBOX_PCI_SUB_UNCLASSIFIED_VGA 0x01 + +#define VBOX_PCI_SUB_MASS_STORAGE_SCSI_BUS 0x00 +#define VBOX_PCI_SUB_MASS_STORAGE_IDE 0x01 +#define VBOX_PCI_SUB_MASS_STORAGE_FLOPPY 0x02 +#define VBOX_PCI_SUB_MASS_STORAGE_IPI_BUS 0x03 +#define VBOX_PCI_SUB_MASS_STORAGE_RAID 0x04 +#define VBOX_PCI_SUB_MASS_STORAGE_ATA 0x05 +#define VBOX_PCI_SUB_MASS_STORAGE_SATA 0x06 +#define VBOX_PCI_SUB_MASS_STORAGE_SCSI 0x07 +#define VBOX_PCI_SUB_MASS_STORAGE_NVME 0x08 +#define VBOX_PCI_SUB_MASS_STORAGE_OTHER 0x80 + +#define VBOX_PCI_SUB_NETWORK_ETHERNET 0x00 +#define VBOX_PCI_SUB_NETWORK_TOKEN_RING 0x01 +#define VBOX_PCI_SUB_NETWORK_FDDI 0x02 +#define VBOX_PCI_SUB_NETWORK_ATM 0x03 +#define VBOX_PCI_SUB_NETWORK_ISDN 0x04 +#define VBOX_PCI_SUB_NETWORK_WORLD_FIP 0x05 +#define VBOX_PCI_SUB_NETWORK_PICMG 0x06 +#define VBOX_PCI_SUB_NETWORK_INFINIBAND 0x07 +#define VBOX_PCI_SUB_NETWORK_FABRIC 0x08 +#define VBOX_PCI_SUB_NETWORK_OTHER 0x80 + +#define VBOX_PCI_SUB_DISPLAY_VGA 0x00 +#define VBOX_PCI_SUB_DISPLAY_XGA 0x01 +#define VBOX_PCI_SUB_DISPLAY_3D 0x02 +#define VBOX_PCI_SUB_DISPLAY_OTHER 0x80 + +#define VBOX_PCI_SUB_MULTI_MEDIA_MM_VIDEO 0x00 +#define VBOX_PCI_SUB_MULTI_MEDIA_MM_AUDIO 0x01 +#define VBOX_PCI_SUB_MULTI_MEDIA_TELE 0x02 +#define VBOX_PCI_SUB_MULTI_MEDIA_AUDIO 0x03 +#define VBOX_PCI_SUB_MULTI_MEDIA_OTHER 0x80 + +#define VBOX_PCI_SUB_MEMORY_RAM 0x00 +#define VBOX_PCI_SUB_MEMORY_FLASH 0x01 +#define VBOX_PCI_SUB_MEMORY_OTHER 0x80 + +#define VBOX_PCI_SUB_BRIDGE_HOST 0x00 +#define VBOX_PCI_SUB_BRIDGE_ISA 0x01 +#define VBOX_PCI_SUB_BRIDGE_EISA 0x02 +#define VBOX_PCI_SUB_BRIDGE_MCA 0x03 +#define VBOX_PCI_SUB_BRIDGE_PCI 0x04 +#define VBOX_PCI_SUB_BRIDGE_PCMCIA 0x05 +#define VBOX_PCI_SUB_BRIDGE_NUBUS 0x06 +#define VBOX_PCI_SUB_BRIDGE_CARDBUS 0x07 +#define VBOX_PCI_SUB_BRIDGE_RACEWAY 0x08 +#define VBOX_PCI_SUB_BRIDGE_SEMI_PCI 0x09 +#define VBOX_PCI_SUB_BRIDGE_INFINIBAND_PCI 0x0a +#define VBOX_PCI_SUB_BRIDGE_OTHER 0x80 + +#define VBOX_PCI_SUB_COMM_SERIAL 0x00 +#define VBOX_PCI_SUB_COMM_PARALLEL 0x01 +#define VBOX_PCI_SUB_COMM_MULTIPORT_SERIAL 0x02 +#define VBOX_PCI_SUB_COMM_MODEM 0x03 +#define VBOX_PCI_SUB_COMM_GBIP 0x04 +#define VBOX_PCI_SUB_COMM_SMART_CARD 0x05 +#define VBOX_PCI_SUB_COMM_OTHER 0x80 + +#define VBOX_PCI_SUB_SYSTEM_PIC 0x00 +#define VBOX_PCI_SUB_SYSTEM_DMA 0x01 +#define VBOX_PCI_SUB_SYSTEM_TIMER 0x02 +#define VBOX_PCI_SUB_SYSTEM_RTC 0x03 +#define VBOX_PCI_SUB_SYSTEM_PCI_HOTPLUG 0x04 +#define VBOX_PCI_SUB_SYSTEM_SD_HOST 0x05 +#define VBOX_PCI_SUB_SYSTEM_IOMMU 0x06 +#define VBOX_PCI_SUB_SYSTEM_OTHER 0x80 + +#define VBOX_PCI_SUB_INPUT_KEYBOARD 0x00 +#define VBOX_PCI_SUB_INPUT_PEN 0x01 +#define VBOX_PCI_SUB_INPUT_MOUSE 0x02 +#define VBOX_PCI_SUB_INPUT_SCANNER 0x03 +#define VBOX_PCI_SUB_INPUT_GAMEPORT 0x04 +#define VBOX_PCI_SUB_INPUT_OTHER 0x80 + +#define VBOX_PCI_SUB_DOCKING_ST_GENERIC 0x00 +#define VBOX_PCI_SUB_DOCKING_ST_OTHER 0x80 + +#define VBOX_PCI_SUB_PROCESSOR_386 0x00 +#define VBOX_PCI_SUB_PROCESSOR_486 0x01 +#define VBOX_PCI_SUB_PROCESSOR_PENTIUM 0x02 +#define VBOX_PCI_SUB_PROCESSOR_PENTIUM_PRO 0x03 +#define VBOX_PCI_SUB_PROCESSOR_ALPHA 0x10 +#define VBOX_PCI_SUB_PROCESSOR_POWERPC 0x20 +#define VBOX_PCI_SUB_PROCESSOR_MIPS 0x30 +#define VBOX_PCI_SUB_PROCESSOR_CO_PROC 0x40 +#define VBOX_PCI_SUB_PROCESSOR_OTHER 0x80 + +#define VBOX_PCI_SUB_SERIAL_BUS_FIREWIRE 0x00 +#define VBOX_PCI_SUB_SERIAL_BUS_ACCESS 0x01 +#define VBOX_PCI_SUB_SERIAL_BUS_SSA 0x02 +#define VBOX_PCI_SUB_SERIAL_BUS_USB 0x03 +#define VBOX_PCI_SUB_SERIAL_BUS_FIBRE 0x04 +#define VBOX_PCI_SUB_SERIAL_BUS_SMBUS 0x05 +#define VBOX_PCI_SUB_SERIAL_BUS_INFINIBAND 0x06 +#define VBOX_PCI_SUB_SERIAL_BUS_IPMI 0x07 +#define VBOX_PCI_SUB_SERIAL_BUS_SERCOS 0x08 +#define VBOX_PCI_SUB_SERIAL_BUS_CANBUS 0x09 +#define VBOX_PCI_SUB_SERIAL_BUS_OTHER 0x80 + +#define VBOX_PCI_SUB_WIRELESS_IRDA 0x00 +#define VBOX_PCI_SUB_WIRELESS_IR 0x01 +#define VBOX_PCI_SUB_WIRELESS_RF 0x10 +#define VBOX_PCI_SUB_WIRELESS_BLUETOOTH 0x11 +#define VBOX_PCI_SUB_WIRELESS_BROADBAND 0x12 +#define VBOX_PCI_SUB_WIRELESS_ETH_8021A 0x20 +#define VBOX_PCI_SUB_WIRELESS_ETH_8021B 0x21 +#define VBOX_PCI_SUB_WIRELESS_OTHER 0x80 + +#define VBOX_PCI_SUB_INTELLIGENT_I20 0x00 + +#define VBOX_PCI_SUB_SAT_COMM_TV 0x01 +#define VBOX_PCI_SUB_SAT_COMM_AUDIO 0x02 +#define VBOX_PCI_SUB_SAT_COMM_VOICE 0x03 +#define VBOX_PCI_SUB_SAT_COMM_DATA 0x04 + +#define VBOX_PCI_SUB_ENCRYPT_NETWORK 0x00 +#define VBOX_PCI_SUB_ENCRYPT_ENTERTAINMENT 0x01 +#define VBOX_PCI_SUB_ENCRYPT_OTHER 0x80 + +#define VBOX_PCI_SUB_SIG_PROC_DPIO 0x00 +#define VBOX_PCI_SUB_SIG_PROC_PERF_COUNTERS 0x01 +#define VBOX_PCI_SUB_SIG_PROC_COMM_SYNC 0x10 +#define VBOX_PCI_SUB_SIG_PROC_MANAGEMENT 0x20 +#define VBOX_PCI_SUB_SIG_PROC_OTHER 0x80 +/** @} */ + +/** + * PCI configuration word 4 (command) and word 6 (status). + */ +typedef enum PCICONFIGCOMMAND +{ + /** Supports/uses memory accesses. */ + PCI_COMMAND_IOACCESS = 0x0001, + PCI_COMMAND_MEMACCESS = 0x0002, + PCI_COMMAND_BUSMASTER = 0x0004 +} PCICONFIGCOMMAND; + + +/** + * PCI Address space specification. + * This is used when registering a I/O region. + */ +/** + * Defined by the PCI specification. + */ +typedef enum PCIADDRESSSPACE +{ + /** Memory. */ + PCI_ADDRESS_SPACE_MEM = 0x00, + /** I/O space. */ + PCI_ADDRESS_SPACE_IO = 0x01, + /** 32-bit BAR. */ + PCI_ADDRESS_SPACE_BAR32 = 0x00, + /** 64-bit BAR. */ + PCI_ADDRESS_SPACE_BAR64 = 0x04, + /** Prefetch memory. */ + PCI_ADDRESS_SPACE_MEM_PREFETCH = 0x08 +} PCIADDRESSSPACE; + + +/** + * PCI Memory Request with Address Type. + * In accordance with the PCI ATS spec. + * See PCI ATS spec. 2.1."Memory Requests with Address Type". + */ +typedef enum PCIADDRTYPE +{ + /** Untranslated request. */ + PCIADDRTYPE_UNTRANSLATED = 0x0, + /** Translation request. */ + PCIADDRTYPE_TRANSLATION, + /** Translated requested. */ + PCIADDRTYPE_TRANSLATED, + /** Reserved. */ + PCIADDRTYPE_RSVD +} PCIADDRTYPE; + + +/** @name PCI Configuration Space Registers + * @{ */ +/* Commented out values common for different header types */ +/* Common part of the header */ +#define VBOX_PCI_VENDOR_ID 0x00 /**< 16-bit RO */ +#define VBOX_PCI_DEVICE_ID 0x02 /**< 16-bit RO */ +#define VBOX_PCI_COMMAND 0x04 /**< 16-bit RW, some bits RO */ +#define VBOX_PCI_STATUS 0x06 /**< 16-bit RW, some bits RO */ +#define VBOX_PCI_REVISION_ID 0x08 /**< 8-bit RO - - device revision */ +#define VBOX_PCI_CLASS_PROG 0x09 /**< 8-bit RO - - register-level programming class code (device specific). */ +#define VBOX_PCI_CLASS_SUB 0x0a /**< 8-bit RO - - sub-class code. */ +#define VBOX_PCI_CLASS_DEVICE VBOX_PCI_CLASS_SUB +#define VBOX_PCI_CLASS_BASE 0x0b /**< 8-bit RO - - base class code. */ +#define VBOX_PCI_CACHE_LINE_SIZE 0x0c /**< 8-bit RW - - system cache line size */ +#define VBOX_PCI_LATENCY_TIMER 0x0d /**< 8-bit RW - - master latency timer, hardwired to 0 for PCIe */ +#define VBOX_PCI_HEADER_TYPE 0x0e /**< 8-bit RO - - header type (0 - device, 1 - bridge, 2 - CardBus bridge) */ +#define VBOX_PCI_BIST 0x0f /**< 8-bit RW - - built-in self test control */ +#define VBOX_PCI_CAPABILITY_LIST 0x34 /**< 8-bit RO? - - linked list of new capabilities implemented by the device, 2 bottom bits reserved */ +#define VBOX_PCI_INTERRUPT_LINE 0x3c /**< 8-bit RW - - interrupt line. */ +#define VBOX_PCI_INTERRUPT_PIN 0x3d /**< 8-bit RO - - interrupt pin. */ + +/* Type 0 header, device */ +#define VBOX_PCI_BASE_ADDRESS_0 0x10 /**< 32-bit RW */ +#define VBOX_PCI_BASE_ADDRESS_1 0x14 /**< 32-bit RW */ +#define VBOX_PCI_BASE_ADDRESS_2 0x18 /**< 32-bit RW */ +#define VBOX_PCI_BASE_ADDRESS_3 0x1c /**< 32-bit RW */ +#define VBOX_PCI_BASE_ADDRESS_4 0x20 /**< 32-bit RW */ +#define VBOX_PCI_BASE_ADDRESS_5 0x24 /**< 32-bit RW */ +#define VBOX_PCI_CARDBUS_CIS 0x28 /**< 32-bit ?? */ +#define VBOX_PCI_SUBSYSTEM_VENDOR_ID 0x2c /**< 16-bit RO */ +#define VBOX_PCI_SUBSYSTEM_ID 0x2e /**< 16-bit RO */ +#define VBOX_PCI_ROM_ADDRESS 0x30 /**< 32-bit ?? */ +/* #define VBOX_PCI_CAPABILITY_LIST 0x34 */ /**< 8-bit? ?? */ +#define VBOX_PCI_RESERVED_35 0x35 /**< 8-bit ?? - - reserved */ +#define VBOX_PCI_RESERVED_36 0x36 /**< 8-bit ?? - - reserved */ +#define VBOX_PCI_RESERVED_37 0x37 /**< 8-bit ?? - - reserved */ +#define VBOX_PCI_RESERVED_38 0x38 /**< 32-bit ?? - - reserved */ +/* #define VBOX_PCI_INTERRUPT_LINE 0x3c */ /**< 8-bit RW - - interrupt line. */ +/* #define VBOX_PCI_INTERRUPT_PIN 0x3d */ /**< 8-bit RO - - interrupt pin. */ +#define VBOX_PCI_MIN_GNT 0x3e /**< 8-bit RO - - burst period length (in 1/4 microsecond units) */ +#define VBOX_PCI_MAX_LAT 0x3f /**< 8-bit RO - - how often the device needs access to the PCI bus (in 1/4 microsecond units) */ + +/* Type 1 header, PCI-to-PCI bridge */ +/* #define VBOX_PCI_BASE_ADDRESS_0 0x10 */ /**< 32-bit RW */ +/* #define VBOX_PCI_BASE_ADDRESS_1 0x14 */ /**< 32-bit RW */ +#define VBOX_PCI_PRIMARY_BUS 0x18 /**< 8-bit ?? - - primary bus number. */ +#define VBOX_PCI_SECONDARY_BUS 0x19 /**< 8-bit ?? - - secondary bus number. */ +#define VBOX_PCI_SUBORDINATE_BUS 0x1a /**< 8-bit ?? - - highest subordinate bus number. (behind the bridge) */ +#define VBOX_PCI_SEC_LATENCY_TIMER 0x1b /**< 8-bit ?? - - secondary latency timer. */ +#define VBOX_PCI_IO_BASE 0x1c /**< 8-bit ?? - - I/O range base. */ +#define VBOX_PCI_IO_LIMIT 0x1d /**< 8-bit ?? - - I/O range limit. */ +#define VBOX_PCI_SEC_STATUS 0x1e /**< 16-bit ?? - - secondary status register. */ +#define VBOX_PCI_MEMORY_BASE 0x20 /**< 16-bit ?? - - memory range base. */ +#define VBOX_PCI_MEMORY_LIMIT 0x22 /**< 16-bit ?? - - memory range limit. */ +#define VBOX_PCI_PREF_MEMORY_BASE 0x24 /**< 16-bit ?? - - prefetchable memory range base. */ +#define VBOX_PCI_PREF_MEMORY_LIMIT 0x26 /**< 16-bit ?? - - prefetchable memory range limit. */ +#define VBOX_PCI_PREF_BASE_UPPER32 0x28 /**< 32-bit ?? - - prefetchable memory range high base.*/ +#define VBOX_PCI_PREF_LIMIT_UPPER32 0x2c /**< 32-bit ?? - - prefetchable memory range high limit. */ +#define VBOX_PCI_IO_BASE_UPPER16 0x30 /**< 16-bit ?? - - memory range high base. */ +#define VBOX_PCI_IO_LIMIT_UPPER16 0x32 /**< 16-bit ?? - - memory range high limit. */ +/* #define VBOX_PCI_CAPABILITY_LIST 0x34 */ /**< 8-bit? ?? */ +/* #define VBOX_PCI_RESERVED_35 0x35 */ /**< 8-bit ?? - - reserved */ +/* #define VBOX_PCI_RESERVED_36 0x36 */ /**< 8-bit ?? - - reserved */ +/* #define VBOX_PCI_RESERVED_37 0x37 */ /**< 8-bit ?? - - reserved */ +#define VBOX_PCI_ROM_ADDRESS_BR 0x38 /**< 32-bit ?? - - expansion ROM base address */ +#define VBOX_PCI_BRIDGE_CONTROL 0x3e /**< 16-bit? ?? - - bridge control */ + +/* Type 2 header, PCI-to-CardBus bridge */ +#define VBOX_PCI_CARDBUS_BASE_ADDRESS 0x10 /**< 32-bit RW - - CardBus Socket/ExCa base address */ +#define VBOX_PCI_CARDBUS_CAPLIST 0x14 /**< 8-bit RO? - - offset of capabilities list */ +#define VBOX_PCI_CARDBUS_RESERVED_15 0x15 /**< 8-bit ?? - - reserved */ +#define VBOX_PCI_CARDBUS_SEC_STATUS 0x16 /**< 16-bit ?? - - secondary status */ +#define VBOX_PCI_CARDBUS_PCIBUS_NUMBER 0x18 /**< 8-bit ?? - - PCI bus number */ +#define VBOX_PCI_CARDBUS_CARDBUS_NUMBER 0x19 /**< 8-bit ?? - - CardBus bus number */ +/* #define VBOX_PCI_SUBORDINATE_BUS 0x1a */ /**< 8-bit ?? - - highest subordinate bus number. (behind the bridge) */ +/* #define VBOX_PCI_SEC_LATENCY_TIMER 0x1b */ /**< 8-bit ?? - - secondary latency timer. */ +#define VBOX_PCI_CARDBUS_MEMORY_BASE0 0x1c /**< 32-bit RW - - memory base address 0 */ +#define VBOX_PCI_CARDBUS_MEMORY_LIMIT0 0x20 /**< 32-bit RW - - memory limit 0 */ +#define VBOX_PCI_CARDBUS_MEMORY_BASE1 0x24 /**< 32-bit RW - - memory base address 1 */ +#define VBOX_PCI_CARDBUS_MEMORY_LIMIT1 0x28 /**< 32-bit RW - - memory limit 1 */ +#define VBOX_PCI_CARDBUS_IO_BASE0 0x2c /**< 32-bit RW - - IO base address 0 */ +#define VBOX_PCI_CARDBUS_IO_LIMIT0 0x30 /**< 32-bit RW - - IO limit 0 */ +#define VBOX_PCI_CARDBUS_IO_BASE1 0x34 /**< 32-bit RW - - IO base address 1 */ +#define VBOX_PCI_CARDBUS_IO_LIMIT1 0x38 /**< 32-bit RW - - IO limit 1 */ +/* #define VBOX_PCI_INTERRUPT_LINE 0x3c */ /**< 8-bit RW - - interrupt line. */ +/* #define VBOX_PCI_INTERRUPT_PIN 0x3d */ /**< 8-bit RO - - interrupt pin. */ +/* #define VBOX_PCI_BRIDGE_CONTROL 0x3e */ /**< 16-bit? ?? - - bridge control */ +/** @} */ + + +/* Possible values in status bitmask */ +#define VBOX_PCI_STATUS_CAP_LIST 0x10 /* Support Capability List */ +#define VBOX_PCI_STATUS_66MHZ 0x20 /* Support 66 Mhz PCI 2.1 bus */ +#define VBOX_PCI_STATUS_UDF 0x40 /* Support User Definable Features [obsolete] */ +#define VBOX_PCI_STATUS_FAST_BACK 0x80 /* Accept fast-back to back */ +#define VBOX_PCI_STATUS_PARITY 0x100 /* Detected parity error */ +#define VBOX_PCI_STATUS_DEVSEL_MASK 0x600 /* DEVSEL timing */ +#define VBOX_PCI_STATUS_DEVSEL_FAST 0x000 +#define VBOX_PCI_STATUS_DEVSEL_MEDIUM 0x200 +#define VBOX_PCI_STATUS_DEVSEL_SLOW 0x400 +#define VBOX_PCI_STATUS_SIG_TARGET_ABORT 0x800 /* Set on target abort */ +#define VBOX_PCI_STATUS_REC_TARGET_ABORT 0x1000 /* Master ack of " */ +#define VBOX_PCI_STATUS_REC_MASTER_ABORT 0x2000 /* Set on master abort */ +#define VBOX_PCI_STATUS_SIG_SYSTEM_ERROR 0x4000 /* Set when we drive SERR */ +#define VBOX_PCI_STATUS_DETECTED_PARITY 0x8000 /* Set on parity error */ + + +/* Command bitmask */ +#define VBOX_PCI_COMMAND_IO 0x1 /* Enable response in I/O space */ +#define VBOX_PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */ +#define VBOX_PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */ +#define VBOX_PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */ +#define VBOX_PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */ +#define VBOX_PCI_COMMAND_VGA_PALETTE 0x20 /* Enable palette snooping */ +#define VBOX_PCI_COMMAND_PARITY 0x40 /* Enable parity checking */ +#define VBOX_PCI_COMMAND_WAIT 0x80 /* Enable address/data stepping */ +#define VBOX_PCI_COMMAND_SERR 0x100 /* Enable SERR */ +#define VBOX_PCI_COMMAND_FAST_BACK 0x200 /* Enable back-to-back writes */ +#define VBOX_PCI_COMMAND_INTX_DISABLE 0x400 /* INTx Emulation Disable */ + + +/* Capability list values (capability offset 0) */ +/* Next value pointer in offset 1, or 0 if none */ +#define VBOX_PCI_CAP_ID_PM 0x01 /* Power Management */ +#define VBOX_PCI_CAP_ID_AGP 0x02 /* Accelerated Graphics Port */ +#define VBOX_PCI_CAP_ID_VPD 0x03 /* Vital Product Data */ +#define VBOX_PCI_CAP_ID_SLOTID 0x04 /* Slot Identification */ +#define VBOX_PCI_CAP_ID_MSI 0x05 /* Message Signalled Interrupts */ +#define VBOX_PCI_CAP_ID_CHSWP 0x06 /* CompactPCI HotSwap */ +#define VBOX_PCI_CAP_ID_PCIX 0x07 /* PCI-X */ +#define VBOX_PCI_CAP_ID_HT 0x08 /* HyperTransport */ +#define VBOX_PCI_CAP_ID_VNDR 0x09 /* Vendor specific */ +#define VBOX_PCI_CAP_ID_DBG 0x0A /* Debug port */ +#define VBOX_PCI_CAP_ID_CCRC 0x0B /* CompactPCI Central Resource Control */ +#define VBOX_PCI_CAP_ID_SHPC 0x0C /* PCI Standard Hot-Plug Controller */ +#define VBOX_PCI_CAP_ID_SSVID 0x0D /* Bridge subsystem vendor/device ID */ +#define VBOX_PCI_CAP_ID_AGP3 0x0E /* AGP Target PCI-PCI bridge */ +#define VBOX_PCI_CAP_ID_SECURE 0x0F /* Secure device (?) */ +#define VBOX_PCI_CAP_ID_EXP 0x10 /* PCI Express */ +#define VBOX_PCI_CAP_ID_MSIX 0x11 /* MSI-X */ +#define VBOX_PCI_CAP_ID_SATA 0x12 /* Serial-ATA HBA */ +#define VBOX_PCI_CAP_ID_AF 0x13 /* PCI Advanced Features */ + +/* Extended Capabilities (PCI-X 2.0 and Express), start at 0x100, next - bits [20..32] */ +#define VBOX_PCI_EXT_CAP_ID_ERR 0x01 /* Advanced Error Reporting */ +#define VBOX_PCI_EXT_CAP_ID_VC 0x02 /* Virtual Channel */ +#define VBOX_PCI_EXT_CAP_ID_DSN 0x03 /* Device Serial Number */ +#define VBOX_PCI_EXT_CAP_ID_PWR 0x04 /* Power Budgeting */ +#define VBOX_PCI_EXT_CAP_ID_RCLINK 0x05 /* Root Complex Link Declaration */ +#define VBOX_PCI_EXT_CAP_ID_RCILINK 0x06 /* Root Complex Internal Link Declaration */ +#define VBOX_PCI_EXT_CAP_ID_RCECOLL 0x07 /* Root Complex Event Collector */ +#define VBOX_PCI_EXT_CAP_ID_MFVC 0x08 /* Multi-Function Virtual Channel */ +#define VBOX_PCI_EXT_CAP_ID_RBCB 0x0a /* Root Bridge Control Block */ +#define VBOX_PCI_EXT_CAP_ID_VNDR 0x0b /* Vendor specific */ +#define VBOX_PCI_EXT_CAP_ID_ACS 0x0d /* Access Controls */ +#define VBOX_PCI_EXT_CAP_ID_ARI 0x0e +#define VBOX_PCI_EXT_CAP_ID_ATS 0x0f +#define VBOX_PCI_EXT_CAP_ID_SRIOV 0x10 + + +/* MSI flags, aka Message Control (2 bytes, capability offset 2) */ +#define VBOX_PCI_MSI_FLAGS_ENABLE 0x0001 /* MSI feature enabled */ +#define VBOX_PCI_MSI_FLAGS_64BIT 0x0080 /* 64-bit addresses allowed */ +#define VBOX_PCI_MSI_FLAGS_MASKBIT 0x0100 /* Per-vector masking support */ +/* Encoding for 3-bit patterns for message queue (per chapter 6.8.1 of PCI spec), + someone very similar to log_2(). + 000 1 + 001 2 + 010 4 + 011 8 + 100 16 + 101 32 + 110 Reserved + 111 Reserved */ +#define VBOX_PCI_MSI_FLAGS_QSIZE 0x0070 /* Message queue size configured (i.e. vectors per device allocated) */ +#define VBOX_PCI_MSI_FLAGS_QMASK 0x000e /* Maximum queue size available (i.e. vectors per device possible) */ + +/* MSI-X flags (2 bytes, capability offset 2) */ +#define VBOX_PCI_MSIX_FLAGS_ENABLE 0x8000 /* MSI-X enable */ +#define VBOX_PCI_MSIX_FLAGS_FUNCMASK 0x4000 /* Function mask */ + +/* Power management flags (2 bytes, capability offset 2) */ +#define VBOX_PCI_PM_CAP_VER_MASK 0x0007 /* Version mask */ +#define VBOX_PCI_PM_CAP_PME_CLOCK 0x0008 /* PME clock required */ +#define VBOX_PCI_PM_CAP_RESERVED 0x0010 /* Reserved field */ +#define VBOX_PCI_PM_CAP_DSI 0x0020 /* Device specific initialization */ +#define VBOX_PCI_PM_CAP_AUX_POWER 0x01C0 /* Auxilliary power support mask */ +#define VBOX_PCI_PM_CAP_D1 0x0200 /* D1 power state support */ +#define VBOX_PCI_PM_CAP_D2 0x0400 /* D2 power state support */ +#define VBOX_PCI_PM_CAP_PME 0x0800 /* PME pin supported */ +#define VBOX_PCI_PM_CAP_PME_MASK 0xF800 /* PME Mask of all supported states */ +#define VBOX_PCI_PM_CAP_PME_D0 0x0800 /* PME# from D0 */ +#define VBOX_PCI_PM_CAP_PME_D1 0x1000 /* PME# from D1 */ +#define VBOX_PCI_PM_CAP_PME_D2 0x2000 /* PME# from D2 */ +#define VBOX_PCI_PM_CAP_PME_D3 0x4000 /* PME# from D3 (hot) */ +#define VBOX_PCI_PM_CAP_PME_D3cold 0x8000 /* PME# from D3 (cold) */ + +/* Power management control flags (2 bytes, capability offset 4) */ +#define VBOX_PCI_PM_CTRL_STATE_MASK 0x0003 /* Current power state (D0 to D3) */ +#define VBOX_PCI_PM_CTRL_NO_SOFT_RESET 0x0008 /* No reset for D3hot->D0 */ +#define VBOX_PCI_PM_CTRL_PME_ENABLE 0x0100 /* PME pin enable */ +#define VBOX_PCI_PM_CTRL_DATA_SEL_MASK 0x1e00 /* Data select (??) */ +#define VBOX_PCI_PM_CTRL_DATA_SCALE_MASK 0x6000 /* Data scale (??) */ +#define VBOX_PCI_PM_CTRL_PME_STATUS 0x8000 /* PME pin status */ + +/* PCI-X config flags (2 bytes, capability offset 2) */ +#define VBOX_PCI_X_CMD_DPERR_E 0x0001 /* Data Parity Error Recovery Enable */ +#define VBOX_PCI_X_CMD_ERO 0x0002 /* Enable Relaxed Ordering */ +#define VBOX_PCI_X_CMD_MAX_OUTSTANDING_SPLIT_TRANS 0x0070 +#define VBOX_PCI_X_CMD_READ_512 0x0000 /* 512 byte maximum read byte count */ +#define VBOX_PCI_X_CMD_READ_1K 0x0004 /* 1Kbyte maximum read byte count */ +#define VBOX_PCI_X_CMD_READ_2K 0x0008 /* 2Kbyte maximum read byte count */ +#define VBOX_PCI_X_CMD_READ_4K 0x000c /* 4Kbyte maximum read byte count */ +#define VBOX_PCI_X_CMD_MAX_READ 0x000c /* Max Memory Read Byte Count */ + +/* PCI-X config flags (4 bytes, capability offset 4) */ +#define VBOX_PCI_X_STATUS_DEVFN 0x000000ff /* A copy of devfn */ +#define VBOX_PCI_X_STATUS_BUS 0x0000ff00 /* A copy of bus nr */ +#define VBOX_PCI_X_STATUS_64BIT 0x00010000 /* 64-bit device */ +#define VBOX_PCI_X_STATUS_133MHZ 0x00020000 /* 133 MHz capable */ +#define VBOX_PCI_X_STATUS_SPL_DISC 0x00040000 /* Split Completion Discarded */ +#define VBOX_PCI_X_STATUS_UNX_SPL 0x00080000 /* Unexpected Split Completion */ +#define VBOX_PCI_X_STATUS_COMPLEX 0x00100000 /* Device Complexity, 0 = simple device, 1 = bridge device */ +#define VBOX_PCI_X_STATUS_MAX_READ 0x00600000 /* Designed Max Memory Read Count, 0 = 512 bytes, 1 = 1024, 2 = 2048, 3 = 4096 */ +#define VBOX_PCI_X_STATUS_MAX_SPLIT 0x03800000 /* Designed Max Outstanding Split Transactions */ +#define VBOX_PCI_X_STATUS_MAX_CUM 0x1c000000 /* Designed Max Cumulative Read Size */ +#define VBOX_PCI_X_STATUS_SPL_ERR 0x20000000 /* Rcvd Split Completion Error Msg */ +#define VBOX_PCI_X_STATUS_266MHZ 0x40000000 /* 266 MHz capable */ +#define VBOX_PCI_X_STATUS_533MHZ 0x80000000 /* 533 MHz capable */ + +/* PCI Express config flags (2 bytes, capability offset 2) */ +#define VBOX_PCI_EXP_FLAGS_VERS 0x000f /* Capability version */ +#define VBOX_PCI_EXP_FLAGS_TYPE 0x00f0 /* Device/Port type */ +#define VBOX_PCI_EXP_TYPE_ENDPOINT 0x0 /* Express Endpoint */ +#define VBOX_PCI_EXP_TYPE_LEG_END 0x1 /* Legacy Endpoint */ +#define VBOX_PCI_EXP_TYPE_ROOT_PORT 0x4 /* Root Port */ +#define VBOX_PCI_EXP_TYPE_UPSTREAM 0x5 /* Upstream Port */ +#define VBOX_PCI_EXP_TYPE_DOWNSTREAM 0x6 /* Downstream Port */ +#define VBOX_PCI_EXP_TYPE_PCI_BRIDGE 0x7 /* PCI/PCI-X Bridge */ +#define VBOX_PCI_EXP_TYPE_PCIE_BRIDGE 0x8 /* PCI/PCI-X to PCIE Bridge */ +#define VBOX_PCI_EXP_TYPE_ROOT_INT_EP 0x9 /* Root Complex Integrated Endpoint */ +#define VBOX_PCI_EXP_TYPE_ROOT_EC 0xa /* Root Complex Event Collector */ +#define VBOX_PCI_EXP_FLAGS_SLOT 0x0100 /* Slot implemented */ +#define VBOX_PCI_EXP_FLAGS_IRQ 0x3e00 /* Interrupt message number */ + +/* PCI Express device capabilities (4 bytes, capability offset 4) */ +#define VBOX_PCI_EXP_DEVCAP_PAYLOAD 0x07 /* Max_Payload_Size */ +#define VBOX_PCI_EXP_DEVCAP_PHANTOM 0x18 /* Phantom functions */ +#define VBOX_PCI_EXP_DEVCAP_EXT_TAG 0x20 /* Extended tags */ +#define VBOX_PCI_EXP_DEVCAP_L0S 0x1c0 /* L0s Acceptable Latency */ +#define VBOX_PCI_EXP_DEVCAP_L1 0xe00 /* L1 Acceptable Latency */ +#define VBOX_PCI_EXP_DEVCAP_ATN_BUT 0x1000 /* Attention Button Present */ +#define VBOX_PCI_EXP_DEVCAP_ATN_IND 0x2000 /* Attention Indicator Present */ +#define VBOX_PCI_EXP_DEVCAP_PWR_IND 0x4000 /* Power Indicator Present */ +#define VBOX_PCI_EXP_DEVCAP_RBE 0x8000 /* Role-Based Error Reporting */ +#define VBOX_PCI_EXP_DEVCAP_PWR_VAL 0x3fc0000 /* Slot Power Limit Value */ +#define VBOX_PCI_EXP_DEVCAP_PWR_SCL 0xc000000 /* Slot Power Limit Scale */ +#define VBOX_PCI_EXP_DEVCAP_FLRESET 0x10000000 /* Function-Level Reset */ + +/* PCI Express device control (2 bytes, capability offset 8) */ +#define VBOX_PCI_EXP_DEVCTL_CERE 0x0001 /* Correctable Error Reporting En. */ +#define VBOX_PCI_EXP_DEVCTL_NFERE 0x0002 /* Non-Fatal Error Reporting Enable */ +#define VBOX_PCI_EXP_DEVCTL_FERE 0x0004 /* Fatal Error Reporting Enable */ +#define VBOX_PCI_EXP_DEVCTL_URRE 0x0008 /* Unsupported Request Reporting En. */ +#define VBOX_PCI_EXP_DEVCTL_RELAXED 0x0010 /* Enable Relaxed Ordering */ +#define VBOX_PCI_EXP_DEVCTL_PAYLOAD 0x00e0 /* Max_Payload_Size */ +#define VBOX_PCI_EXP_DEVCTL_EXT_TAG 0x0100 /* Extended Tag Field Enable */ +#define VBOX_PCI_EXP_DEVCTL_PHANTOM 0x0200 /* Phantom Functions Enable */ +#define VBOX_PCI_EXP_DEVCTL_AUX_PME 0x0400 /* Auxiliary Power PM Enable */ +#define VBOX_PCI_EXP_DEVCTL_NOSNOOP 0x0800 /* Enable No Snoop */ +#define VBOX_PCI_EXP_DEVCTL_READRQ 0x7000 /* Max_Read_Request_Size */ +#define VBOX_PCI_EXP_DEVCTL_BCRE 0x8000 /* Bridge Configuration Retry Enable */ +#define VBOX_PCI_EXP_DEVCTL_FLRESET 0x8000 /* Function-Level Reset [bit shared with BCRE] */ + +/* PCI Express device status (2 bytes, capability offset 10) */ +#define VBOX_PCI_EXP_DEVSTA_CED 0x01 /* Correctable Error Detected */ +#define VBOX_PCI_EXP_DEVSTA_NFED 0x02 /* Non-Fatal Error Detected */ +#define VBOX_PCI_EXP_DEVSTA_FED 0x04 /* Fatal Error Detected */ +#define VBOX_PCI_EXP_DEVSTA_URD 0x08 /* Unsupported Request Detected */ +#define VBOX_PCI_EXP_DEVSTA_AUXPD 0x10 /* AUX Power Detected */ +#define VBOX_PCI_EXP_DEVSTA_TRPND 0x20 /* Transactions Pending */ + +/* PCI Express link capabilities (4 bytes, capability offset 12) */ +#define VBOX_PCI_EXP_LNKCAP_SPEED 0x0000f /* Maximum Link Speed */ +#define VBOX_PCI_EXP_LNKCAP_WIDTH 0x003f0 /* Maximum Link Width */ +#define VBOX_PCI_EXP_LNKCAP_ASPM 0x00c00 /* Active State Power Management */ +#define VBOX_PCI_EXP_LNKCAP_L0S 0x07000 /* L0s Acceptable Latency */ +#define VBOX_PCI_EXP_LNKCAP_L1 0x38000 /* L1 Acceptable Latency */ +#define VBOX_PCI_EXP_LNKCAP_CLOCKPM 0x40000 /* Clock Power Management */ +#define VBOX_PCI_EXP_LNKCAP_SURPRISE 0x80000 /* Surprise Down Error Reporting */ +#define VBOX_PCI_EXP_LNKCAP_DLLA 0x100000 /* Data Link Layer Active Reporting */ +#define VBOX_PCI_EXP_LNKCAP_LBNC 0x200000 /* Link Bandwidth Notification Capability */ +#define VBOX_PCI_EXP_LNKCAP_PORT 0xff000000 /* Port Number */ + +/* PCI Express link control (2 bytes, capability offset 16) */ +#define VBOX_PCI_EXP_LNKCTL_ASPM 0x0003 /* ASPM Control */ +#define VBOX_PCI_EXP_LNKCTL_RCB 0x0008 /* Read Completion Boundary */ +#define VBOX_PCI_EXP_LNKCTL_DISABLE 0x0010 /* Link Disable */ +#define VBOX_PCI_EXP_LNKCTL_RETRAIN 0x0020 /* Retrain Link */ +#define VBOX_PCI_EXP_LNKCTL_CLOCK 0x0040 /* Common Clock Configuration */ +#define VBOX_PCI_EXP_LNKCTL_XSYNCH 0x0080 /* Extended Synch */ +#define VBOX_PCI_EXP_LNKCTL_CLOCKPM 0x0100 /* Clock Power Management */ +#define VBOX_PCI_EXP_LNKCTL_HWAUTWD 0x0200 /* Hardware Autonomous Width Disable */ +#define VBOX_PCI_EXP_LNKCTL_BWMIE 0x0400 /* Bandwidth Mgmt Interrupt Enable */ +#define VBOX_PCI_EXP_LNKCTL_AUTBWIE 0x0800 /* Autonomous Bandwidth Mgmt Interrupt Enable */ + +/* PCI Express link status (2 bytes, capability offset 18) */ +#define VBOX_PCI_EXP_LNKSTA_SPEED 0x000f /* Negotiated Link Speed */ +#define VBOX_PCI_EXP_LNKSTA_WIDTH 0x03f0 /* Negotiated Link Width */ +#define VBOX_PCI_EXP_LNKSTA_TR_ERR 0x0400 /* Training Error (obsolete) */ +#define VBOX_PCI_EXP_LNKSTA_TRAIN 0x0800 /* Link Training */ +#define VBOX_PCI_EXP_LNKSTA_SL_CLK 0x1000 /* Slot Clock Configuration */ +#define VBOX_PCI_EXP_LNKSTA_DL_ACT 0x2000 /* Data Link Layer in DL_Active State */ +#define VBOX_PCI_EXP_LNKSTA_BWMGMT 0x4000 /* Bandwidth Mgmt Status */ +#define VBOX_PCI_EXP_LNKSTA_AUTBW 0x8000 /* Autonomous Bandwidth Mgmt Status */ + +/* PCI Express slot capabilities (4 bytes, capability offset 20) */ +#define VBOX_PCI_EXP_SLTCAP_ATNB 0x0001 /* Attention Button Present */ +#define VBOX_PCI_EXP_SLTCAP_PWRC 0x0002 /* Power Controller Present */ +#define VBOX_PCI_EXP_SLTCAP_MRL 0x0004 /* MRL Sensor Present */ +#define VBOX_PCI_EXP_SLTCAP_ATNI 0x0008 /* Attention Indicator Present */ +#define VBOX_PCI_EXP_SLTCAP_PWRI 0x0010 /* Power Indicator Present */ +#define VBOX_PCI_EXP_SLTCAP_HPS 0x0020 /* Hot-Plug Surprise */ +#define VBOX_PCI_EXP_SLTCAP_HPC 0x0040 /* Hot-Plug Capable */ +#define VBOX_PCI_EXP_SLTCAP_PWR_VAL 0x00007f80 /* Slot Power Limit Value */ +#define VBOX_PCI_EXP_SLTCAP_PWR_SCL 0x00018000 /* Slot Power Limit Scale */ +#define VBOX_PCI_EXP_SLTCAP_INTERLOCK 0x020000 /* Electromechanical Interlock Present */ +#define VBOX_PCI_EXP_SLTCAP_NOCMDCOMP 0x040000 /* No Command Completed Support */ +#define VBOX_PCI_EXP_SLTCAP_PSN 0xfff80000 /* Physical Slot Number */ + +/* PCI Express slot control (2 bytes, capability offset 24) */ +#define VBOX_PCI_EXP_SLTCTL_ATNB 0x0001 /* Attention Button Pressed Enable */ +#define VBOX_PCI_EXP_SLTCTL_PWRF 0x0002 /* Power Fault Detected Enable */ +#define VBOX_PCI_EXP_SLTCTL_MRLS 0x0004 /* MRL Sensor Changed Enable */ +#define VBOX_PCI_EXP_SLTCTL_PRSD 0x0008 /* Presence Detect Changed Enable */ +#define VBOX_PCI_EXP_SLTCTL_CMDC 0x0010 /* Command Completed Interrupt Enable */ +#define VBOX_PCI_EXP_SLTCTL_HPIE 0x0020 /* Hot-Plug Interrupt Enable */ +#define VBOX_PCI_EXP_SLTCTL_ATNI 0x00c0 /* Attention Indicator Control */ +#define VBOX_PCI_EXP_SLTCTL_PWRI 0x0300 /* Power Indicator Control */ +#define VBOX_PCI_EXP_SLTCTL_PWRC 0x0400 /* Power Controller Control */ +#define VBOX_PCI_EXP_SLTCTL_INTERLOCK 0x0800 /* Electromechanical Interlock Control */ +#define VBOX_PCI_EXP_SLTCTL_LLCHG 0x1000 /* Data Link Layer State Changed Enable */ + +/* PCI Express slot status (2 bytes, capability offset 26) */ +#define VBOX_PCI_EXP_SLTSTA_ATNB 0x0001 /* Attention Button Pressed */ +#define VBOX_PCI_EXP_SLTSTA_PWRF 0x0002 /* Power Fault Detected */ +#define VBOX_PCI_EXP_SLTSTA_MRLS 0x0004 /* MRL Sensor Changed */ +#define VBOX_PCI_EXP_SLTSTA_PRSD 0x0008 /* Presence Detect Changed */ +#define VBOX_PCI_EXP_SLTSTA_CMDC 0x0010 /* Command Completed */ +#define VBOX_PCI_EXP_SLTSTA_MRL_ST 0x0020 /* MRL Sensor State */ +#define VBOX_PCI_EXP_SLTSTA_PRES 0x0040 /* Presence Detect State */ +#define VBOX_PCI_EXP_SLTSTA_INTERLOCK 0x0080 /* Electromechanical Interlock Status */ +#define VBOX_PCI_EXP_SLTSTA_LLCHG 0x0100 /* Data Link Layer State Changed */ + +/* PCI Express root control (2 bytes, capability offset 28) */ +#define VBOX_PCI_EXP_RTCTL_SECEE 0x0001 /* System Error on Correctable Error */ +#define VBOX_PCI_EXP_RTCTL_SENFEE 0x0002 /* System Error on Non-Fatal Error */ +#define VBOX_PCI_EXP_RTCTL_SEFEE 0x0004 /* System Error on Fatal Error */ +#define VBOX_PCI_EXP_RTCTL_PMEIE 0x0008 /* PME Interrupt Enable */ +#define VBOX_PCI_EXP_RTCTL_CRSVIS 0x0010 /* Configuration Request Retry Status Visible to SW */ + +/* PCI Express root capabilities (2 bytes, capability offset 30) */ +#define VBOX_PCI_EXP_RTCAP_CRSVIS 0x0010 /* Configuration Request Retry Status Visible to SW */ + +/* PCI Express root status (4 bytes, capability offset 32) */ +#define VBOX_PCI_EXP_RTSTA_PME_REQID 0x0000ffff /* PME Requester ID */ +#define VBOX_PCI_EXP_RTSTA_PME_STATUS 0x00010000 /* PME Status */ +#define VBOX_PCI_EXP_RTSTA_PME_PENDING 0x00020000 /* PME is Pending */ + + +/** Fixed I/O region number for ROM. */ +#define VBOX_PCI_ROM_SLOT 6 +/** Max number of I/O regions. */ +#define VBOX_PCI_NUM_REGIONS 7 + +#define PCI_ROM_SLOT VBOX_PCI_ROM_SLOT /**< deprecated */ +#define PCI_NUM_REGIONS VBOX_PCI_NUM_REGIONS /**< deprecated */ + +/** Number of functions per device. */ +#define VBOX_PCI_MAX_FUNCTIONS 8 +/** Number of devices per bus. */ +#define VBOX_PCI_MAX_DEVICES 32 +/** The function number mask for a device+function number. */ +#define VBOX_PCI_DEVFN_FUN_MASK 0x7 +/** The device number shift count for a device+function number. */ +#define VBOX_PCI_DEVFN_DEV_SHIFT 3 +/** The device number mask for a device+function number. */ +#define VBOX_PCI_DEVFN_DEV_MASK 0x1f +/** The bus number shift count for a bus+device+function number. */ +#define VBOX_PCI_BUS_SHIFT 0x8 +/** The bus number mask a bus+device+function number. */ +#define VBOX_PCI_BUS_MASK 0xff +/** Make a device+function number. */ +#define VBOX_PCI_DEVFN_MAKE(a_uPciDevNo, a_uPciFunNo) ( ((a_uPciDevNo) << VBOX_PCI_DEVFN_DEV_SHIFT) \ + | ((a_uPciFunNo) & VBOX_PCI_DEVFN_FUN_MASK)) + +/** Checks whether the PCIBDF is valid. */ +#define PCIBDF_IS_VALID(a_uBusDevFn) (!((a_uBusDevFn) & PCI_BDF_F_INVALID)) +/** Make a PCIBDF given the bus and device:function. */ +#define PCIBDF_MAKE(a_uBus, a_uDevFn) (((a_uBus) << VBOX_PCI_BUS_SHIFT) | (a_uDevFn)) + +/** Southbridge I/O APIC (when IOMMU is enabled): Bus. */ +#define VBOX_PCI_BUS_SB_IOAPIC 0 +/** Southbridge I/O APIC (when IOMMU is enabled): Device. */ +#define VBOX_PCI_DEV_SB_IOAPIC 0x14 +/** Southbridge I/O APIC (when IOMMU is enabled): Function. */ +#define VBOX_PCI_FN_SB_IOAPIC 0 +/** PCI BDF (hardcoded by linux guests) reserved for the SB I/O APIC when using VMs + * with an AMD IOMMU. */ +#define VBOX_PCI_BDF_SB_IOAPIC PCIBDF_MAKE(VBOX_PCI_BUS_SB_IOAPIC, \ + VBOX_PCI_DEVFN_MAKE(VBOX_PCI_DEV_SB_IOAPIC, VBOX_PCI_FN_SB_IOAPIC)) + +/** + * A PCI PASID (Process Address Space ID). + * + * A PASID is 20 bits wide. We use bit 31 to indicate the PASID is invalid or not + * present. + */ +typedef uint32_t PCIPASID; +/** PCIPASID: Valid. */ +#define PCIPASID_F_VALID RT_BIT(31) +/** Nil PCIPASID value. */ +#define NIL_PCIPASID UINT32_C(0) +/** Returns whether the PCI PASID is valid. */ +#define PCIPASID_IS_VALID(a) (((a) & PCIPASID_F_VALID) != 0) +/** Returns the PASID value of a PCI PASID. */ +#define PCIPASID_VAL(a) ((a) & UINT32_C(0xfffff)) + + +#if defined(__cplusplus) && defined(IN_RING3) +/* For RTStrPrintf(). */ +# include + +/** + * Class representing PCI address. PCI device consist of + * bus, device and function numbers. Generally device PCI + * address could be changed during runtime, but only by + * an OS PCI driver. + * + * @remarks C++ classes (structs included) are not generally accepted in + * VMM devices or drivers. An exception may be granted for this class + * if it's contained to ring-3 and that this is a one time exception + * which sets no precedent. + */ +struct PCIBusAddress +{ + /** @todo: think if we'll need domain, which is higher + * word of the address. */ + int miBus; + int miDevice; + int miFn; + + PCIBusAddress() + { + clear(); + } + + PCIBusAddress(int iBus, int iDevice, int iFn) + { + init(iBus, iDevice, iFn); + } + + PCIBusAddress(int32_t iAddr) + { + clear(); + fromLong(iAddr); + } + + PCIBusAddress& clear() + { + miBus = miDevice = miFn = -1; + return *this; + } + + void init(int iBus, int iDevice, int iFn) + { + miBus = iBus; + miDevice = iDevice; + miFn = iFn; + } + + void init(const PCIBusAddress &a) + { + miBus = a.miBus; + miDevice = a.miDevice; + miFn = a.miFn; + } + + bool operator<(const PCIBusAddress &a) const + { + if (miBus < a.miBus) + return true; + + if (miBus > a.miBus) + return false; + + if (miDevice < a.miDevice) + return true; + + if (miDevice > a.miDevice) + return false; + + if (miFn < a.miFn) + return true; + + if (miFn > a.miFn) + return false; + + return false; + } + + bool operator==(const PCIBusAddress &a) const + { + return (miBus == a.miBus) + && (miDevice == a.miDevice) + && (miFn == a.miFn); + } + + bool operator!=(const PCIBusAddress &a) const + { + return (miBus != a.miBus) + || (miDevice != a.miDevice) + || (miFn != a.miFn); + } + + bool valid() const + { + return (miBus != -1) + && (miDevice != -1) + && (miFn != -1); + } + + int32_t asLong() const + { + Assert(valid()); + return (miBus << 8) | (miDevice << 3) | miFn; + } + + PCIBusAddress& fromLong(int32_t value) + { + miBus = (value >> 8) & 0xff; + miDevice = (value & 0xff) >> 3; + miFn = (value & 7); + return *this; + } + + /** Create string representation of this PCI address. */ + bool format(char* szBuf, int32_t cBufSize) + { + if (cBufSize < (/* bus */ 2 + /* : */ 1 + /* device */ 2 + /* . */ 1 + /* function*/ 1 + /* \0 */1)) + return false; + + if (valid()) + RTStrPrintf(szBuf, cBufSize, "%02x:%02x.%01x", miBus, miDevice, miFn); + else + RTStrPrintf(szBuf, cBufSize, "%s", ""); + + return true; + } + + static const size_t cMaxAddrSize = 10; +}; + +#endif /* __cplusplus && IN_RING3 */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_pci_h */ diff --git a/include/VBox/rawpci.h b/include/VBox/rawpci.h new file mode 100644 index 00000000..290983c0 --- /dev/null +++ b/include/VBox/rawpci.h @@ -0,0 +1,618 @@ +/** @file + * Raw PCI Devices (aka PCI pass-through). (VMM) + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_rawpci_h +#define VBOX_INCLUDED_rawpci_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** + * Handle for the raw PCI device. + */ +typedef uint32_t PCIRAWDEVHANDLE; + +/** + * Handle for the ISR. + */ +typedef uint32_t PCIRAWISRHANDLE; + +/** + * Physical memory action enumeration. + */ +typedef enum PCIRAWMEMINFOACTION +{ + /** Pages mapped. */ + PCIRAW_MEMINFO_MAP, + /** Pages unmapped. */ + PCIRAW_MEMINFO_UNMAP, + /** The usual 32-bit type blow up. */ + PCIRAW_MEMINFO_32BIT_HACK = 0x7fffffff +} PCIRAWMEMINFOACTION; + +/** + * Per-VM capability flag bits. + */ +typedef enum PCIRAWVMFLAGS +{ + /** If we can use IOMMU in this VM. */ + PCIRAW_VMFLAGS_HAS_IOMMU = (1 << 0), + PCIRAW_VMFLAGS_32BIT_HACK = 0x7fffffff +} PCIRAWVMFLAGS; + +/* Forward declaration. */ +struct RAWPCIPERVM; + +/** + * Callback to notify raw PCI subsystem about mapping/unmapping of + * host pages to the guest. Typical usecase is to register physical + * RAM pages with IOMMU, so that it could allow DMA for PCI devices + * directly from the guest RAM. + * Region shall be one or more contigous (both host and guest) pages + * of physical memory. + * + * @returns VBox status code. + * + * @param pVmData The per VM data. + * @param HCPhysStart Physical address of region start on the host. + * @param GCPhysStart Physical address of region start on the guest. + * @param cbMem Region size in bytes. + * @param enmAction Action performed (i.e. if page was mapped + * or unmapped). + */ +typedef DECLCALLBACKTYPE(int, FNRAWPCICONTIGPHYSMEMINFO,(struct RAWPCIPERVM *pVmData, RTHCPHYS HCPhysStart, + RTGCPHYS GCPhysStart, uint64_t cbMem, PCIRAWMEMINFOACTION enmAction)); +typedef FNRAWPCICONTIGPHYSMEMINFO *PFNRAWPCICONTIGPHYSMEMINFO; + +/** Data being part of the VM structure. */ +typedef struct RAWPCIPERVM +{ + /** Shall only be interpreted by the host PCI driver. */ + RTR0PTR pDriverData; + /** Callback called when mapping of host pages to the guest changes. */ + PFNRAWPCICONTIGPHYSMEMINFO pfnContigMemInfo; + /** Flags describing VM capabilities (such as IOMMU presence). */ + uint32_t fVmCaps; +} RAWPCIPERVM; +typedef RAWPCIPERVM *PRAWPCIPERVM; + +/** Parameters buffer for PCIRAWR0_DO_OPEN_DEVICE call */ +typedef struct +{ + /* in */ + uint32_t PciAddress; + uint32_t fFlags; + /* out */ + PCIRAWDEVHANDLE Device; + uint32_t fDevFlags; +} PCIRAWREQOPENDEVICE; + +/** Parameters buffer for PCIRAWR0_DO_CLOSE_DEVICE call */ +typedef struct +{ + /* in */ + uint32_t fFlags; +} PCIRAWREQCLOSEDEVICE; + +/** Parameters buffer for PCIRAWR0_DO_GET_REGION_INFO call */ +typedef struct +{ + /* in */ + int32_t iRegion; + /* out */ + RTGCPHYS RegionStart; + uint64_t u64RegionSize; + bool fPresent; + uint32_t fFlags; +} PCIRAWREQGETREGIONINFO; + +/** Parameters buffer for PCIRAWR0_DO_MAP_REGION call. */ +typedef struct +{ + /* in */ + RTGCPHYS StartAddress; + uint64_t iRegionSize; + int32_t iRegion; + uint32_t fFlags; + /* out */ + RTR3PTR pvAddressR3; + RTR0PTR pvAddressR0; +} PCIRAWREQMAPREGION; + +/** Parameters buffer for PCIRAWR0_DO_UNMAP_REGION call. */ +typedef struct +{ + /* in */ + RTGCPHYS StartAddress; + uint64_t iRegionSize; + RTR3PTR pvAddressR3; + RTR0PTR pvAddressR0; + int32_t iRegion; +} PCIRAWREQUNMAPREGION; + +/** Parameters buffer for PCIRAWR0_DO_PIO_WRITE call. */ +typedef struct +{ + /* in */ + uint16_t iPort; + uint16_t cb; + uint32_t iValue; +} PCIRAWREQPIOWRITE; + +/** Parameters buffer for PCIRAWR0_DO_PIO_READ call. */ +typedef struct +{ + /* in */ + uint16_t iPort; + uint16_t cb; + /* out */ + uint32_t iValue; +} PCIRAWREQPIOREAD; + +/** Memory operand. */ +typedef struct +{ + union + { + uint8_t u8; + uint16_t u16; + uint32_t u32; + uint64_t u64; + } u; + uint8_t cb; +} PCIRAWMEMLOC; + +/** Parameters buffer for PCIRAWR0_DO_MMIO_WRITE call. */ +typedef struct +{ + /* in */ + RTR0PTR Address; + PCIRAWMEMLOC Value; +} PCIRAWREQMMIOWRITE; + +/** Parameters buffer for PCIRAWR0_DO_MMIO_READ call. */ +typedef struct +{ + /* in */ + RTR0PTR Address; + /* inout (Value.cb is in) */ + PCIRAWMEMLOC Value; +} PCIRAWREQMMIOREAD; + +/* Parameters buffer for PCIRAWR0_DO_PCICFG_WRITE call. */ +typedef struct +{ + /* in */ + uint32_t iOffset; + PCIRAWMEMLOC Value; +} PCIRAWREQPCICFGWRITE; + +/** Parameters buffer for PCIRAWR0_DO_PCICFG_READ call. */ +typedef struct +{ + /* in */ + uint32_t iOffset; + /* inout (Value.cb is in) */ + PCIRAWMEMLOC Value; +} PCIRAWREQPCICFGREAD; + +/** Parameters buffer for PCIRAWR0_DO_GET_IRQ call. */ +typedef struct PCIRAWREQGETIRQ +{ + /* in */ + int64_t iTimeout; + /* out */ + int32_t iIrq; +} PCIRAWREQGETIRQ; + +/** Parameters buffer for PCIRAWR0_DO_POWER_STATE_CHANGE call. */ +typedef struct PCIRAWREQPOWERSTATECHANGE +{ + /* in */ + uint32_t iState; + /* in/out */ + uint64_t u64Param; +} PCIRAWREQPOWERSTATECHANGE; + +/** + * Request buffer use for communication with the driver. + */ +typedef struct PCIRAWSENDREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Alternative to passing the taking the session from the VM handle. + * Either use this member or use the VM handle, don't do both. + */ + PSUPDRVSESSION pSession; + /** Request type. */ + int32_t iRequest; + /** Host device request targetted to. */ + PCIRAWDEVHANDLE TargetDevice; + /** Call parameters. */ + union + { + PCIRAWREQOPENDEVICE aOpenDevice; + PCIRAWREQCLOSEDEVICE aCloseDevice; + PCIRAWREQGETREGIONINFO aGetRegionInfo; + PCIRAWREQMAPREGION aMapRegion; + PCIRAWREQUNMAPREGION aUnmapRegion; + PCIRAWREQPIOWRITE aPioWrite; + PCIRAWREQPIOREAD aPioRead; + PCIRAWREQMMIOWRITE aMmioWrite; + PCIRAWREQMMIOREAD aMmioRead; + PCIRAWREQPCICFGWRITE aPciCfgWrite; + PCIRAWREQPCICFGREAD aPciCfgRead; + PCIRAWREQGETIRQ aGetIrq; + PCIRAWREQPOWERSTATECHANGE aPowerStateChange; + } u; +} PCIRAWSENDREQ; +typedef PCIRAWSENDREQ *PPCIRAWSENDREQ; + +/** + * Operations performed by the driver. + */ +typedef enum PCIRAWR0OPERATION +{ + /* Open device. */ + PCIRAWR0_DO_OPEN_DEVICE, + /* Close device. */ + PCIRAWR0_DO_CLOSE_DEVICE, + /* Get PCI region info. */ + PCIRAWR0_DO_GET_REGION_INFO, + /* Map PCI region into VM address space. */ + PCIRAWR0_DO_MAP_REGION, + /* Unmap PCI region from VM address space. */ + PCIRAWR0_DO_UNMAP_REGION, + /* Perform PIO write. */ + PCIRAWR0_DO_PIO_WRITE, + /* Perform PIO read. */ + PCIRAWR0_DO_PIO_READ, + /* Perform MMIO write. */ + PCIRAWR0_DO_MMIO_WRITE, + /* Perform MMIO read. */ + PCIRAWR0_DO_MMIO_READ, + /* Perform PCI config write. */ + PCIRAWR0_DO_PCICFG_WRITE, + /* Perform PCI config read. */ + PCIRAWR0_DO_PCICFG_READ, + /* Get next IRQ for the device. */ + PCIRAWR0_DO_GET_IRQ, + /* Enable getting IRQs for the device. */ + PCIRAWR0_DO_ENABLE_IRQ, + /* Disable getting IRQs for the device. */ + PCIRAWR0_DO_DISABLE_IRQ, + /* Notify driver about guest power state change. */ + PCIRAWR0_DO_POWER_STATE_CHANGE, + /** The usual 32-bit type blow up. */ + PCIRAWR0_DO_32BIT_HACK = 0x7fffffff +} PCIRAWR0OPERATION; + +/** + * Power state enumeration. + */ +typedef enum PCIRAWPOWERSTATE +{ + /* Power on. */ + PCIRAW_POWER_ON, + /* Power off. */ + PCIRAW_POWER_OFF, + /* Suspend. */ + PCIRAW_POWER_SUSPEND, + /* Resume. */ + PCIRAW_POWER_RESUME, + /* Reset. */ + PCIRAW_POWER_RESET, + /** The usual 32-bit type blow up. */ + PCIRAW_POWER_32BIT_HACK = 0x7fffffff +} PCIRAWPOWERSTATE; + + +/** Forward declarations. */ +typedef struct RAWPCIFACTORY *PRAWPCIFACTORY; +typedef struct RAWPCIDEVPORT *PRAWPCIDEVPORT; + +/** + * Interrupt service routine callback. + * + * @returns if interrupt was processed. + * + * @param pvContext Opaque user data passed to the handler. + * @param iIrq Interrupt number. + */ +typedef DECLCALLBACKTYPE(bool, FNRAWPCIISR,(void *pvContext, int32_t iIrq)); +typedef FNRAWPCIISR *PFNRAWPCIISR; + +/** + * This is the port on the device interface, i.e. the driver side which the + * host device is connected to. + * + * This is only used for the in-kernel PCI device connections. + */ +typedef struct RAWPCIDEVPORT +{ + /** Structure version number. (RAWPCIDEVPORT_VERSION) */ + uint32_t u32Version; + + /** + * Init device. + * + * @param pPort Pointer to this structure. + * @param fFlags Initialization flags. + */ + DECLR0CALLBACKMEMBER(int, pfnInit,(PRAWPCIDEVPORT pPort, + uint32_t fFlags)); + + + /** + * Deinit device. + * + * @param pPort Pointer to this structure. + * @param fFlags Initialization flags. + */ + DECLR0CALLBACKMEMBER(int, pfnDeinit,(PRAWPCIDEVPORT pPort, + uint32_t fFlags)); + + + /** + * Destroy device. + * + * @param pPort Pointer to this structure. + */ + DECLR0CALLBACKMEMBER(int, pfnDestroy,(PRAWPCIDEVPORT pPort)); + + /** + * Get PCI region info. + * + * @param pPort Pointer to this structure. + * @param iRegion Region number. + * @param pRegionStart Where to start the region address. + * @param pu64RegionSize Where to store the region size. + * @param pfPresent Where to store if the region is present. + * @param pfFlags Where to store the flags. + */ + DECLR0CALLBACKMEMBER(int, pfnGetRegionInfo,(PRAWPCIDEVPORT pPort, + int32_t iRegion, + RTHCPHYS *pRegionStart, + uint64_t *pu64RegionSize, + bool *pfPresent, + uint32_t *pfFlags)); + + + /** + * Map PCI region. + * + * @param pPort Pointer to this structure. + * @param iRegion Region number. + * @param RegionStart Region start. + * @param u64RegionSize Region size. + * @param fFlags Flags. + * @param pRegionBaseR0 Where to store the R0 address. + */ + DECLR0CALLBACKMEMBER(int, pfnMapRegion,(PRAWPCIDEVPORT pPort, + int32_t iRegion, + RTHCPHYS RegionStart, + uint64_t u64RegionSize, + int32_t fFlags, + RTR0PTR *pRegionBaseR0)); + + /** + * Unmap PCI region. + * + * @param pPort Pointer to this structure. + * @param iRegion Region number. + * @param RegionStart Region start. + * @param u64RegionSize Region size. + * @param RegionBase Base address. + */ + DECLR0CALLBACKMEMBER(int, pfnUnmapRegion,(PRAWPCIDEVPORT pPort, + int32_t iRegion, + RTHCPHYS RegionStart, + uint64_t u64RegionSize, + RTR0PTR RegionBase)); + + /** + * Read device PCI register. + * + * @param pPort Pointer to this structure. + * @param Register PCI register. + * @param pValue Read value (with desired read width). + */ + DECLR0CALLBACKMEMBER(int, pfnPciCfgRead,(PRAWPCIDEVPORT pPort, + uint32_t Register, + PCIRAWMEMLOC *pValue)); + + + /** + * Write device PCI register. + * + * @param pPort Pointer to this structure. + * @param Register PCI register. + * @param pValue Write value (with desired write width). + */ + DECLR0CALLBACKMEMBER(int, pfnPciCfgWrite,(PRAWPCIDEVPORT pPort, + uint32_t Register, + PCIRAWMEMLOC *pValue)); + + /** + * Request to register interrupt handler. + * + * @param pPort Pointer to this structure. + * @param pfnHandler Pointer to the handler. + * @param pIrqContext Context passed to the handler. + * @param phIsr Handle for the ISR, . + */ + DECLR0CALLBACKMEMBER(int, pfnRegisterIrqHandler,(PRAWPCIDEVPORT pPort, + PFNRAWPCIISR pfnHandler, + void* pIrqContext, + PCIRAWISRHANDLE *phIsr)); + + /** + * Request to unregister interrupt handler. + * + * @param pPort Pointer to this structure. + * @param hIsr Handle of ISR to unregister (retured by earlier pfnRegisterIrqHandler). + */ + DECLR0CALLBACKMEMBER(int, pfnUnregisterIrqHandler,(PRAWPCIDEVPORT pPort, + PCIRAWISRHANDLE hIsr)); + + /** + * Power state change notification. + * + * @param pPort Pointer to this structure. + * @param aState New power state. + * @param pu64Param State-specific in/out parameter. + */ + DECLR0CALLBACKMEMBER(int, pfnPowerStateChange,(PRAWPCIDEVPORT pPort, + PCIRAWPOWERSTATE aState, + uint64_t *pu64Param)); + + /** Structure version number. (RAWPCIDEVPORT_VERSION) */ + uint32_t u32VersionEnd; +} RAWPCIDEVPORT; +/** Version number for the RAWPCIDEVPORT::u32Version and RAWPCIIFPORT::u32VersionEnd fields. */ +#define RAWPCIDEVPORT_VERSION UINT32_C(0xAFBDCC02) + +/** + * The component factory interface for create a raw PCI interfaces. + */ +typedef struct RAWPCIFACTORY +{ + /** + * Release this factory. + * + * SUPR0ComponentQueryFactory (SUPDRVFACTORY::pfnQueryFactoryInterface to be precise) + * will retain a reference to the factory and the caller has to call this method to + * release it once the pfnCreateAndConnect call(s) has been done. + * + * @param pFactory Pointer to this structure. + */ + DECLR0CALLBACKMEMBER(void, pfnRelease,(PRAWPCIFACTORY pFactory)); + + /** + * Create an instance for the specfied host PCI card and connects it + * to the driver. + * + * + * @returns VBox status code. + * + * @param pFactory Pointer to this structure. + * @param u32HostAddress Address of PCI device on the host. + * @param fFlags Creation flags. + * @param pVmCtx Context of VM where device is created. + * @param ppDevPort Where to store the pointer to the device port + * on success. + * @param pfDevFlags Where to store the device flags. + * + */ + DECLR0CALLBACKMEMBER(int, pfnCreateAndConnect,(PRAWPCIFACTORY pFactory, + uint32_t u32HostAddress, + uint32_t fFlags, + PRAWPCIPERVM pVmCtx, + PRAWPCIDEVPORT *ppDevPort, + uint32_t *pfDevFlags)); + + + /** + * Initialize per-VM data related to PCI passthrough. + * + * @returns VBox status code. + * + * @param pFactory Pointer to this structure. + * @param pVM The cross context VM structure. + * @param pVmData Pointer to PCI data. + */ + DECLR0CALLBACKMEMBER(int, pfnInitVm,(PRAWPCIFACTORY pFactory, + PVM pVM, + PRAWPCIPERVM pVmData)); + + /** + * Deinitialize per-VM data related to PCI passthrough. + * + * @returns VBox status code. + * + * @param pFactory Pointer to this structure. + * @param pVM The cross context VM structure. + * @param pVmData Pointer to PCI data. + */ + DECLR0CALLBACKMEMBER(void, pfnDeinitVm,(PRAWPCIFACTORY pFactory, + PVM pVM, + PRAWPCIPERVM pVmData)); +} RAWPCIFACTORY; + +#define RAWPCIFACTORY_UUID_STR "ea089839-4171-476f-adfb-9e7ab1cbd0fb" + +/** + * Flags passed to pfnPciDeviceConstructStart(), to notify driver + * about options to be used to open device. + */ +typedef enum PCIRAWDRIVERFLAGS +{ + /** If runtime shall try to detach host driver. */ + PCIRAWDRIVERRFLAG_DETACH_HOST_DRIVER = (1 << 0), + /** The usual 32-bit type blow up. */ + PCIRAWDRIVERRFLAG_32BIT_HACK = 0x7fffffff +} PCIRAWDRIVERFLAGS; + +/** + * Flags used to describe PCI region, matches to PCIADDRESSSPACE + * in pci.h. + */ +typedef enum PCIRAWADDRESSSPACE +{ + /** Memory. */ + PCIRAW_ADDRESS_SPACE_MEM = 0x00, + /** I/O space. */ + PCIRAW_ADDRESS_SPACE_IO = 0x01, + /** 32-bit BAR. */ + PCIRAW_ADDRESS_SPACE_BAR32 = 0x00, + /** 64-bit BAR. */ + PCIRAW_ADDRESS_SPACE_BAR64 = 0x04, + /** Prefetch memory. */ + PCIRAW_ADDRESS_SPACE_MEM_PREFETCH = 0x08, + /** The usual 32-bit type blow up. */ + PCIRAW_ADDRESS_SPACE_32BIT_HACK = 0x7fffffff +} PCIRAWADDRESSSPACE; + +RT_C_DECLS_END + +/* #define VBOX_WITH_SHARED_PCI_INTERRUPTS */ + +#endif /* !VBOX_INCLUDED_rawpci_h */ diff --git a/include/VBox/scsi.h b/include/VBox/scsi.h new file mode 100644 index 00000000..1acf1f3c --- /dev/null +++ b/include/VBox/scsi.h @@ -0,0 +1,339 @@ +/** @file + * VirtualBox - SCSI declarations. (DEV,+) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_scsi_h +#define VBOX_INCLUDED_scsi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** + * @todo: Remove when the splitting code was removed from DevATA. + * The limit doesn't belong here but is specific for each host platform. + */ +#ifdef RT_OS_FREEBSD +/* The cam subsystem doesn't allow more */ +# define SCSI_MAX_BUFFER_SIZE (64 * _1K) +#else +# define SCSI_MAX_BUFFER_SIZE (100 * _1K) +#endif + +/** + * SCSI command opcode identifiers. + * + * SCSI-3, so far for CD/DVD Logical Units, from Table 49 of the MMC-3 draft standard. + */ +typedef enum SCSICMD +{ + SCSI_BLANK = 0xa1, + SCSI_CLOSE_TRACK_SESSION = 0x5b, + SCSI_ERASE_10 = 0x2c, + SCSI_FORMAT_UNIT = 0x04, + SCSI_GET_CONFIGURATION = 0x46, + SCSI_GET_EVENT_STATUS_NOTIFICATION = 0x4a, + SCSI_GET_PERFORMANCE = 0xac, + /** Inquiry command. */ + SCSI_INQUIRY = 0x12, + SCSI_LOAD_UNLOAD_MEDIUM = 0xa6, + SCSI_MECHANISM_STATUS = 0xbd, + SCSI_MODE_SELECT_10 = 0x55, + SCSI_MODE_SENSE_10 = 0x5a, + SCSI_PAUSE_RESUME = 0x4b, + SCSI_PLAY_AUDIO_10 = 0x45, + SCSI_PLAY_AUDIO_12 = 0xa5, + SCSI_PLAY_AUDIO_MSF = 0x47, + SCSI_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1e, + /** Read(10) command. */ + SCSI_READ_10 = 0x28, + SCSI_READ_12 = 0xa8, + SCSI_READ_BUFFER = 0x3c, + SCSI_READ_BUFFER_CAPACITY = 0x5c, + /** Read Capacity(6) command. */ + SCSI_READ_CAPACITY = 0x25, + SCSI_READ_CD = 0xbe, + SCSI_READ_CD_MSF = 0xb9, + SCSI_READ_DISC_INFORMATION = 0x51, + SCSI_READ_DVD_STRUCTURE = 0xad, + SCSI_READ_FORMAT_CAPACITIES = 0x23, + SCSI_READ_SUBCHANNEL = 0x42, + SCSI_READ_TOC_PMA_ATIP = 0x43, + SCSI_READ_TRACK_INFORMATION = 0x52, + SCSI_REPAIR_TRACK = 0x58, + SCSI_REPORT_KEY = 0xa4, + SCSI_REQUEST_SENSE = 0x03, + SCSI_RESERVE_TRACK = 0x53, + SCSI_SCAN = 0xba, + SCSI_SEEK_10 = 0x2b, + SCSI_SEND_CUE_SHEET = 0x5d, + SCSI_SEND_DVD_STRUCTURE = 0xbf, + SCSI_SEND_EVENT = 0xa2, + SCSI_SEND_KEY = 0xa3, + SCSI_SEND_OPC_INFORMATION = 0x54, + SCSI_SET_CD_SPEED = 0xbb, + SCSI_SET_READ_AHEAD = 0xa7, + SCSI_SET_STREAMING = 0xb6, + SCSI_START_STOP_UNIT = 0x1b, + SCSI_LOAD_UNLOAD = 0x1b, + SCSI_STOP_PLAY_SCAN = 0x4e, + /** Synchronize Cache command. */ + SCSI_SYNCHRONIZE_CACHE = 0x35, + SCSI_TEST_UNIT_READY = 0x00, + SCSI_VERIFY_10 = 0x2f, + /** Write(10) command. */ + SCSI_WRITE_10 = 0x2a, + SCSI_WRITE_12 = 0xaa, + SCSI_WRITE_AND_VERIFY_10 = 0x2e, + SCSI_WRITE_BUFFER = 0x3b, + + /** Mode Select(6) command */ + SCSI_MODE_SELECT_6 = 0x15, + /** Mode Sense(6) command */ + SCSI_MODE_SENSE_6 = 0x1a, + /** Report LUNs command. */ + SCSI_REPORT_LUNS = 0xa0, + SCSI_REPORT_DENSITY = 0x44, + /** Rezero Unit command. Obsolete for ages now, but used by cdrecord. */ + SCSI_REZERO_UNIT = 0x01, + SCSI_REWIND = 0x01, + SCSI_SERVICE_ACTION_IN_16 = 0x9e, + SCSI_READ_16 = 0x88, + SCSI_WRITE_16 = 0x8a, + SCSI_READ_6 = 0x08, + SCSI_WRITE_6 = 0x0a, + SCSI_LOG_SENSE = 0x4d, + SCSI_UNMAP = 0x42, + SCSI_RESERVE_6 = 0x16, + SCSI_RELEASE_6 = 0x17, + SCSI_RESERVE_10 = 0x56, + SCSI_RELEASE_10 = 0x57, + SCSI_READ_BLOCK_LIMITS = 0x05, + SCSI_MAINTENANCE_IN = 0xa3 +} SCSICMD; + +/** + * Service action in opcode identifiers + */ +typedef enum SCSISVCACTIONIN +{ + SCSI_SVC_ACTION_IN_READ_CAPACITY_16 = 0x10 +} SCSISVCACTIONIN; + +/** + * Maintenance in opcode identifiers + */ +typedef enum SCSIMAINTENANCEIN +{ + SCSI_MAINTENANCE_IN_REPORT_SUPP_OPC = 0x0c +} SCSIMAINTENANCEIN; + +/* Mode page codes for mode sense/select commands. */ +#define SCSI_MODEPAGE_ERROR_RECOVERY 0x01 +#define SCSI_MODEPAGE_WRITE_PARAMETER 0x05 +#define SCSI_MODEPAGE_CD_STATUS 0x2a + + +/* Page control codes. */ +#define SCSI_PAGECONTROL_CURRENT 0x00 +#define SCSI_PAGECONTROL_CHANGEABLE 0x01 +#define SCSI_PAGECONTROL_DEFAULT 0x02 +#define SCSI_PAGECONTROL_SAVED 0x03 + + +/* Status codes */ +#define SCSI_STATUS_OK 0x00 +#define SCSI_STATUS_CHECK_CONDITION 0x02 +#define SCSI_STATUS_CONDITION_MET 0x04 +#define SCSI_STATUS_BUSY 0x08 +#define SCSI_STATUS_INTERMEDIATE 0x10 +#define SCSI_STATUS_DATA_UNDEROVER_RUN 0x12 +#define SCSI_STATUS_INTERMEDIATE_CONDITION_MET 0x14 +#define SCSI_STATUS_RESERVATION_CONFLICT 0x18 +#define SCSI_STATUS_COMMAND_TERMINATED 0x22 +#define SCSI_STATUS_QUEUE_FULL 0x28 +#define SCSI_STATUS_ACA_ACTIVE 0x30 +#define SCSI_STATUS_TASK_ABORTED 0x40 + +/* Sense data response codes - This is the first byte in the sense data */ +#define SCSI_SENSE_RESPONSE_CODE_CURR_FIXED 0x70 +#define SCSI_SENSE_RESPONSE_CODE_DEFERRED_FIXED 0x71 +#define SCSI_SENSE_RESPONSE_CODE_CURR_DESC 0x72 +#define SCSI_SENSE_RESPONSE_CODE_DEFERRED_DESC 0x73 + +/* Sense keys */ +#define SCSI_SENSE_NONE 0 +#define SCSI_SENSE_RECOVERED_ERROR 1 +#define SCSI_SENSE_NOT_READY 2 +#define SCSI_SENSE_MEDIUM_ERROR 3 +#define SCSI_SENSE_HARDWARE_ERROR 4 +#define SCSI_SENSE_ILLEGAL_REQUEST 5 +#define SCSI_SENSE_UNIT_ATTENTION 6 +#define SCSI_SENSE_DATA_PROTECT 7 +#define SCSI_SENSE_BLANK_CHECK 8 +#define SCSI_SENSE_VENDOR_SPECIFIC 9 +#define SCSI_SENSE_COPY_ABORTED 10 +#define SCSI_SENSE_ABORTED_COMMAND 11 +#define SCSI_SENSE_VOLUME_OVERFLOW 13 +#define SCSI_SENSE_MISCOMPARE 14 + +/* Additional sense bit flags (to be ORed with sense key). */ +#define SCSI_SENSE_FLAG_FILEMARK 0x80 +#define SCSI_SENSE_FLAG_EOM 0x40 +#define SCSI_SENSE_FLAG_ILI 0x20 + +/* Additional sense keys */ +#define SCSI_ASC_NONE 0x00 +#define SCSI_ASC_WRITE_ERROR 0x0c +#define SCSI_ASC_READ_ERROR 0x11 +#define SCSI_ASC_ILLEGAL_OPCODE 0x20 +#define SCSI_ASC_LOGICAL_BLOCK_OOR 0x21 +#define SCSI_ASC_INV_FIELD_IN_CMD_PACKET 0x24 +#define SCSI_ASC_LOGICAL_UNIT_NOT_SUPPORTED 0x25 +#define SCSI_ASC_WRITE_PROTECTED 0x27 +#define SCSI_ASC_MEDIUM_MAY_HAVE_CHANGED 0x28 +#define SCSI_ASC_POWER_ON_RESET_BUS_DEVICE_RESET_OCCURRED 0x29 +#define SCSI_ASC_CANNOT_READ_MEDIUM 0x30 +#define SCSI_ASC_MEDIUM_NOT_PRESENT 0x3a +#define SCSI_ASC_SAVING_PARAMETERS_NOT_SUPPORTED 0x39 +#define SCSI_ASC_INTERNAL_TARGET_FAILURE 0x44 +#define SCSI_ASC_INVALID_MESSAGE 0x49 +#define SCSI_ASC_MEDIA_LOAD_OR_EJECT_FAILED 0x53 +#define SCSI_ASC_LOGICAL_UNIT_DOES_NOT_RESPOND_TO_SELECTION 0x00 +#define SCSI_ASC_SYSTEM_RESOURCE_FAILURE 0x55 +#define SCSI_ASC_ILLEGAL_MODE_FOR_THIS_TRACK 0x64 +#define SCSI_ASC_COMMAND_TO_LOGICAL_UNIT_FAILED 0x6E + +/** Additional sense code qualifiers (ASCQ). */ +/* NB: The ASC/ASCQ combination determines the full meaning. */ +#define SCSI_ASCQ_SYSTEM_BUFFER_FULL 0x01 +#define SCSI_ASCQ_POWER_ON_RESET_BUS_DEVICE_RESET_OCCURRED 0x00 +#define SCSI_ASCQ_END_OF_DATA_DETECTED 0x05 +#define SCSI_ASCQ_FILEMARK_DETECTED 0x01 +#define SCSI_ASCQ_EOP_EOM_DETECTED 0x02 +#define SCSI_ASCQ_SETMARK_DETECTED 0x03 +#define SCSI_ASCQ_BOP_BOM_DETECTED 0x04 +#define SCSI_ASCQ_UNKNOWN_FORMAT 0x01 +#define SCSI_ASCQ_INCOMPATIBLE_FORMAT 0x02 +#define SCSI_ASCQ_COPY_TARGET_DEVICE_DATA_OVERRUN 0x0d + +/** @name SCSI_INQUIRY + * @{ + */ + +/** Length of the SCSI INQUIRY vendor identifier (without termination). */ +#define SCSI_INQUIRY_VENDOR_ID_LENGTH 8 +/** Length of the SCSI INQUIRY product identifier (without termination). */ +#define SCSI_INQUIRY_PRODUCT_ID_LENGTH 16 +/** Length of the SCSI INQUIRY revision identifier (without termination). */ +#define SCSI_INQUIRY_REVISION_LENGTH 4 + +#pragma pack(1) +typedef struct SCSIINQUIRYCDB +{ + unsigned u8Cmd : 8; + unsigned fEVPD : 1; + unsigned u4Reserved : 4; + unsigned u3LUN : 3; + unsigned u8PageCode : 8; + unsigned u8Reserved : 8; + uint8_t cbAlloc; + uint8_t u8Control; +} SCSIINQUIRYCDB; +#pragma pack() +AssertCompileSize(SCSIINQUIRYCDB, 6); +typedef SCSIINQUIRYCDB *PSCSIINQUIRYCDB; +typedef const SCSIINQUIRYCDB *PCSCSIINQUIRYCDB; + +#pragma pack(1) +typedef struct SCSIINQUIRYDATA +{ + unsigned u5PeripheralDeviceType : 5; /**< 0x00 / 00 */ + unsigned u3PeripheralQualifier : 3; + unsigned u6DeviceTypeModifier : 7; /**< 0x01 */ + unsigned fRMB : 1; + unsigned u3AnsiVersion : 3; /**< 0x02 */ + unsigned u3EcmaVersion : 3; + unsigned u2IsoVersion : 2; + unsigned u4ResponseDataFormat : 4; /**< 0x03 */ + unsigned u2Reserved0 : 2; + unsigned fTrmlOP : 1; + unsigned fAEC : 1; + unsigned cbAdditional : 8; /**< 0x04 */ + unsigned u8Reserved1 : 8; /**< 0x05 */ + unsigned u8Reserved2 : 8; /**< 0x06 */ + unsigned fSftRe : 1; /**< 0x07 */ + unsigned fCmdQue : 1; + unsigned fReserved3 : 1; + unsigned fLinked : 1; + unsigned fSync : 1; + unsigned fWBus16 : 1; + unsigned fWBus32 : 1; + unsigned fRelAdr : 1; + int8_t achVendorId[SCSI_INQUIRY_VENDOR_ID_LENGTH]; /**< 0x08 */ + int8_t achProductId[SCSI_INQUIRY_PRODUCT_ID_LENGTH]; /**< 0x10 */ + int8_t achProductLevel[SCSI_INQUIRY_REVISION_LENGTH]; /**< 0x20 */ + uint8_t abVendorSpecific[20]; /**< 0x24/36 - Optional it seems. */ + uint8_t abReserved4[40]; + uint8_t abVendorSpecificParameters[1]; /**< 0x60/96 - Variable size. */ +} SCSIINQUIRYDATA; +#pragma pack() +AssertCompileSize(SCSIINQUIRYDATA, 97); +typedef SCSIINQUIRYDATA *PSCSIINQUIRYDATA; +typedef const SCSIINQUIRYDATA *PCSCSIINQUIRYDATA; + +#define SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_CONNECTED 0x00 +#define SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_BUT_SUPPORTED 0x01 +#define SCSI_INQUIRY_DATA_PERIPHERAL_QUALIFIER_NOT_CONNECTED_NOT_SUPPORTED 0x03 + +#define SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_DIRECT_ACCESS 0x00 +#define SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_SEQUENTIAL_ACCESS 0x01 +#define SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_CD_DVD 0x05 +#define SCSI_INQUIRY_DATA_PERIPHERAL_DEVICE_TYPE_UNKNOWN 0x1f + +/** @} */ + +#if defined(IN_RING3) && (defined(LOG_ENABLED) || defined(RT_STRICT)) +const char * SCSICmdText(uint8_t uCmd); +const char * SCSIStatusText(uint8_t uStatus); +const char * SCSISenseText(uint8_t uSense); +const char * SCSISenseExtText(uint8_t uASC, uint8_t uASCQ); +int SCSILogModePage(char *pszBuf, size_t cchBuffer, uint8_t *pbModePage, + size_t cbModePage); +int SCSILogCueSheet(char *pszBuf, size_t cchBuffer, uint8_t *pbCueSheet, + size_t cbCueSheet); +#endif + +#endif /* !VBOX_INCLUDED_scsi_h */ diff --git a/include/VBox/scsiinline.h b/include/VBox/scsiinline.h new file mode 100644 index 00000000..c27a1f67 --- /dev/null +++ b/include/VBox/scsiinline.h @@ -0,0 +1,246 @@ +/* $Id: scsiinline.h $ */ +/** @file + * VirtualBox: SCSI inline helpers used by devices, drivers, etc. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_scsiinline_h +#define VBOX_INCLUDED_scsiinline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_scsi_inline The SCSI inline helpers + * @{ + */ + + +/** + * Converts a given 16bit value to big endian and stores it in the given buffer. + * + * @returns nothing. + * @param pbBuf The buffer to store the value into. + * @param u16Val The value to store. + */ +DECLINLINE(void) scsiH2BE_U16(uint8_t *pbBuf, uint16_t u16Val) +{ + pbBuf[0] = u16Val >> 8; + pbBuf[1] = u16Val; +} + + +/** + * Converts a given 24bit value to big endian and stores it in the given buffer. + * + * @returns nothing. + * @param pbBuf The buffer to store the value into. + * @param u32Val The value to store. + */ +DECLINLINE(void) scsiH2BE_U24(uint8_t *pbBuf, uint32_t u32Val) +{ + pbBuf[0] = u32Val >> 16; + pbBuf[1] = u32Val >> 8; + pbBuf[2] = u32Val; +} + + +/** + * Converts a given 32bit value to big endian and stores it in the given buffer. + * + * @returns nothing. + * @param pbBuf The buffer to store the value into. + * @param u32Val The value to store. + */ +DECLINLINE(void) scsiH2BE_U32(uint8_t *pbBuf, uint32_t u32Val) +{ + pbBuf[0] = u32Val >> 24; + pbBuf[1] = u32Val >> 16; + pbBuf[2] = u32Val >> 8; + pbBuf[3] = u32Val; +} + + +/** + * Converts a given 64bit value to big endian and stores it in the given buffer. + * + * @returns nothing. + * @param pbBuf The buffer to store the value into. + * @param u64Val The value to store. + */ +DECLINLINE(void) scsiH2BE_U64(uint8_t *pbBuf, uint64_t u64Val) +{ + pbBuf[0] = u64Val >> 56; + pbBuf[1] = u64Val >> 48; + pbBuf[2] = u64Val >> 40; + pbBuf[3] = u64Val >> 32; + pbBuf[4] = u64Val >> 24; + pbBuf[5] = u64Val >> 16; + pbBuf[6] = u64Val >> 8; + pbBuf[7] = u64Val; +} + +/** + * Returns a 16bit value read from the given buffer converted to host endianess. + * + * @returns The converted 16bit value. + * @param pbBuf The buffer to read the value from. + */ +DECLINLINE(uint16_t) scsiBE2H_U16(const uint8_t *pbBuf) +{ + return (pbBuf[0] << 8) | pbBuf[1]; +} + + +/** + * Returns a 24bit value read from the given buffer converted to host endianess. + * + * @returns The converted 24bit value as a 32bit unsigned integer. + * @param pbBuf The buffer to read the value from. + */ +DECLINLINE(uint32_t) scsiBE2H_U24(const uint8_t *pbBuf) +{ + return (pbBuf[0] << 16) | (pbBuf[1] << 8) | pbBuf[2]; +} + + +/** + * Returns a 32bit value read from the given buffer converted to host endianess. + * + * @returns The converted 32bit value. + * @param pbBuf The buffer to read the value from. + */ +DECLINLINE(uint32_t) scsiBE2H_U32(const uint8_t *pbBuf) +{ + return (pbBuf[0] << 24) | (pbBuf[1] << 16) | (pbBuf[2] << 8) | pbBuf[3]; +} + + +/** + * Returns a 64bit value read from the given buffer converted to host endianess. + * + * @returns The converted 64bit value. + * @param pbBuf The buffer to read the value from. + */ +DECLINLINE(uint64_t) scsiBE2H_U64(const uint8_t *pbBuf) +{ + return ((uint64_t)pbBuf[0] << 56) + | ((uint64_t)pbBuf[1] << 48) + | ((uint64_t)pbBuf[2] << 40) + | ((uint64_t)pbBuf[3] << 32) + | ((uint64_t)pbBuf[4] << 24) + | ((uint64_t)pbBuf[5] << 16) + | ((uint64_t)pbBuf[6] << 8) + | (uint64_t)pbBuf[7]; +} + + +/** + * Converts the given LBA number to the MSF (Minutes:Seconds:Frames) format + * and stores it in the given buffer. + * + * @returns nothing. + * @param pbBuf The buffer to store the value into. + * @param iLBA The LBA to convert. + */ +DECLINLINE(void) scsiLBA2MSF(uint8_t *pbBuf, uint32_t iLBA) +{ + iLBA += 150; + pbBuf[0] = (iLBA / 75) / 60; + pbBuf[1] = (iLBA / 75) % 60; + pbBuf[2] = iLBA % 75; +} + + +/** + * Converts a MSF formatted address value read from the given buffer + * to an LBA number. + * + * @returns The LBA number. + * @param pbBuf The buffer to read the MSF formatted address + * from. + */ +DECLINLINE(uint32_t) scsiMSF2LBA(const uint8_t *pbBuf) +{ + return (pbBuf[0] * 60 + pbBuf[1]) * 75 + pbBuf[2] - 150; +} + + +/** + * Copies a given string to the given destination padding all unused space + * in the destination with spaces. + * + * @returns nothing. + * @param pbDst Where to store the string padded with spaces. + * @param pbSrc The string to copy. + * @param cbSize Size of the destination buffer. + */ +DECLINLINE(void) scsiPadStr(uint8_t *pbDst, const char *pbSrc, uint32_t cbSize) +{ + uint32_t i; + for (i = 0; i < cbSize; i++) + { + if (*pbSrc) + pbDst[i] = *pbSrc++; + else + pbDst[i] = ' '; + } +} + + +/** + * Copies a given string to the given destination padding all unused space + * in the destination with spaces. + * + * @returns nothing. + * @param pbDst Where to store the string padded with spaces. + * @param pbSrc The string to copy. + * @param cbSize Size of the destination buffer. + */ +DECLINLINE(void) scsiPadStrS(int8_t *pbDst, const char *pbSrc, uint32_t cbSize) +{ + uint32_t i; + for (i = 0; i < cbSize; i++) + { + if (*pbSrc) + pbDst[i] = *pbSrc++; + else + pbDst[i] = ' '; + } +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_scsiinline_h */ + diff --git a/include/VBox/settings.h b/include/VBox/settings.h new file mode 100644 index 00000000..866a9818 --- /dev/null +++ b/include/VBox/settings.h @@ -0,0 +1,1539 @@ +/** @file + * Settings file data structures. + * + * These structures are created by the settings file loader and filled with values + * copied from the raw XML data. This was all new with VirtualBox 3.1 and allows us + * to finally make the XML reader version-independent and read VirtualBox XML files + * from earlier and even newer (future) versions without requiring complicated, + * tedious and error-prone XSLT conversions. + * + * It is this file that defines all structures that map VirtualBox global and + * machine settings to XML files. These structures are used by the rest of Main, + * even though this header file does not require anything else in Main. + * + * Note: Headers in Main code have been tweaked to only declare the structures + * defined here so that this header need only be included from code files that + * actually use these structures. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_settings_h +#define VBOX_INCLUDED_settings_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +#include "VBox/com/VirtualBox.h" + +#include +#include +#include + +#include +#include +#include + +/** + * Maximum depth of a medium tree, to prevent stack overflows. + * XPCOM has a relatively low stack size for its workers, and we have + * to avoid crashes due to exceeding the limit both on reading and + * writing config files. The bottleneck is in libxml2. + * Data point: a release and asan build could both handle 3800 on Debian 10. + */ +#define SETTINGS_MEDIUM_DEPTH_MAX 300 + +/** + * Maximum depth of the snapshot tree, to prevent stack overflows. + * XPCOM has a relatively low stack size for its workers, and we have + * to avoid crashes due to exceeding the limit both on reading and + * writing config files. The bottleneck is reading config files with + * deep snapshot nesting, as libxml2 needs quite some stack space. + * Data point: a release and asan build could both handle 1300 on Debian 10. + */ +#define SETTINGS_SNAPSHOT_DEPTH_MAX 250 + +namespace xml +{ + class ElementNode; +} + +namespace settings +{ + +class ConfigFileError; + +//////////////////////////////////////////////////////////////////////////////// +// +// Structures shared between Machine XML and VirtualBox.xml +// +//////////////////////////////////////////////////////////////////////////////// + +typedef std::map StringsMap; +typedef std::list StringsList; + +/** + * USB device filter definition. This struct is used both in MainConfigFile + * (for global USB filters) and MachineConfigFile (for machine filters). + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct USBDeviceFilter +{ + USBDeviceFilter(); + + bool operator==(const USBDeviceFilter&u) const; + + com::Utf8Str strName; + bool fActive; + com::Utf8Str strVendorId, + strProductId, + strRevision, + strManufacturer, + strProduct, + strSerialNumber, + strPort; + USBDeviceFilterAction_T action; // only used with host USB filters + com::Utf8Str strRemote; // irrelevant for host USB objects + uint32_t ulMaskedInterfaces; // irrelevant for host USB objects +}; + +typedef std::list USBDeviceFiltersList; + +struct Medium; +typedef std::list MediaList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct Medium +{ + Medium(); + + bool operator==(const Medium &m) const; + + com::Guid uuid; + com::Utf8Str strLocation; + com::Utf8Str strDescription; + + // the following are for hard disks only: + com::Utf8Str strFormat; + bool fAutoReset; // optional, only for diffs, default is false + StringsMap properties; + MediumType_T hdType; + + MediaList llChildren; // only used with hard disks + + static const struct Medium Empty; +}; + +/** + * A media registry. Starting with VirtualBox 3.3, this can appear in both the + * VirtualBox.xml file as well as machine XML files with settings version 1.11 + * or higher, so these lists are now in ConfigFileBase. + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct MediaRegistry +{ + bool operator==(const MediaRegistry &m) const; + + MediaList llHardDisks, + llDvdImages, + llFloppyImages; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct NATRule +{ + NATRule(); + + bool operator==(const NATRule &r) const; + + com::Utf8Str strName; + NATProtocol_T proto; + uint16_t u16HostPort; + com::Utf8Str strHostIP; + uint16_t u16GuestPort; + com::Utf8Str strGuestIP; +}; +typedef std::map NATRulesMap; + +struct NATHostLoopbackOffset +{ + NATHostLoopbackOffset(); + + bool operator==(const NATHostLoopbackOffset &o) const; + + bool operator==(const com::Utf8Str& strAddr) + { + return strLoopbackHostAddress == strAddr; + } + + bool operator==(uint32_t off) + { + return u32Offset == off; + } + + /** Note: 128/8 is only acceptable */ + com::Utf8Str strLoopbackHostAddress; + uint32_t u32Offset; +}; + +typedef std::list NATLoopbackOffsetList; + +typedef std::vector IconBlob; + +/** + * Common base class for both MainConfigFile and MachineConfigFile + * which contains some common logic for both. + */ +class ConfigFileBase +{ +public: + bool fileExists(); + SettingsVersion_T getSettingsVersion(); + + void copyBaseFrom(const ConfigFileBase &b); + +protected: + ConfigFileBase(const com::Utf8Str *pstrFilename); + /* Note: this copy constructor doesn't create a full copy of other, cause + * the file based stuff (xml doc) could not be copied. */ + ConfigFileBase(const ConfigFileBase &other); + + ~ConfigFileBase(); + + typedef enum {Error, HardDisk, DVDImage, FloppyImage} MediaType; + + static const char *stringifyMediaType(MediaType t); + SettingsVersion_T parseVersion(const com::Utf8Str &strVersion, + const xml::ElementNode *pElm); + void parseUUID(com::Guid &guid, + const com::Utf8Str &strUUID, + const xml::ElementNode *pElm) const; + void parseTimestamp(RTTIMESPEC ×tamp, + const com::Utf8Str &str, + const xml::ElementNode *pElm) const; + void parseBase64(IconBlob &binary, + const com::Utf8Str &str, + const xml::ElementNode *pElm) const; + com::Utf8Str stringifyTimestamp(const RTTIMESPEC &tm) const; + void toBase64(com::Utf8Str &str, + const IconBlob &binary) const; + + void readExtraData(const xml::ElementNode &elmExtraData, + StringsMap &map); + void readUSBDeviceFilters(const xml::ElementNode &elmDeviceFilters, + USBDeviceFiltersList &ll); + void readMediumOne(MediaType t, const xml::ElementNode &elmMedium, Medium &med); + void readMedium(MediaType t, const xml::ElementNode &elmMedium, Medium &med); + void readMediaRegistry(const xml::ElementNode &elmMediaRegistry, MediaRegistry &mr); + void readNATForwardRulesMap(const xml::ElementNode &elmParent, NATRulesMap &mapRules); + void readNATLoopbacks(const xml::ElementNode &elmParent, NATLoopbackOffsetList &llLoopBacks); + + void setVersionAttribute(xml::ElementNode &elm); + void specialBackupIfFirstBump(); + void createStubDocument(); + + void buildExtraData(xml::ElementNode &elmParent, const StringsMap &me); + void buildUSBDeviceFilters(xml::ElementNode &elmParent, + const USBDeviceFiltersList &ll, + bool fHostMode); + void buildMedium(MediaType t, + xml::ElementNode &elmMedium, + const Medium &med); + void buildMediaRegistry(xml::ElementNode &elmParent, + const MediaRegistry &mr); + void buildNATForwardRulesMap(xml::ElementNode &elmParent, const NATRulesMap &mapRules); + void buildNATLoopbacks(xml::ElementNode &elmParent, const NATLoopbackOffsetList &natLoopbackList); + void clearDocument(); + + struct Data; + Data *m; + + friend class ConfigFileError; +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// VirtualBox.xml structures +// +//////////////////////////////////////////////////////////////////////////////// + +struct USBDeviceSource +{ + com::Utf8Str strName; + com::Utf8Str strBackend; + com::Utf8Str strAddress; + StringsMap properties; +}; + +typedef std::list USBDeviceSourcesList; + +#ifdef VBOX_WITH_UPDATE_AGENT +struct UpdateAgent +{ + UpdateAgent(); + + bool fEnabled; + UpdateChannel_T enmChannel; + uint32_t uCheckFreqSeconds; + com::Utf8Str strRepoUrl; + com::Utf8Str strLastCheckDate; + uint32_t uCheckCount; +}; +#endif /* VBOX_WITH_UPDATE_AGENT */ + +struct Host +{ + USBDeviceFiltersList llUSBDeviceFilters; + USBDeviceSourcesList llUSBDeviceSources; +#ifdef VBOX_WITH_UPDATE_AGENT + UpdateAgent updateHost; + /** @todo Add handling for ExtPack and Guest Additions updates here later. See @bugref{7983}. */ +#endif /* VBOX_WITH_UPDATE_AGENT */ +}; + +struct SystemProperties +{ + SystemProperties(); + + com::Utf8Str strDefaultMachineFolder; + com::Utf8Str strDefaultHardDiskFolder; + com::Utf8Str strDefaultHardDiskFormat; + com::Utf8Str strVRDEAuthLibrary; + com::Utf8Str strWebServiceAuthLibrary; + com::Utf8Str strDefaultVRDEExtPack; + com::Utf8Str strDefaultCryptoExtPack; + com::Utf8Str strAutostartDatabasePath; + com::Utf8Str strDefaultAdditionsISO; + com::Utf8Str strDefaultFrontend; + com::Utf8Str strLoggingLevel; + com::Utf8Str strProxyUrl; + uint32_t uProxyMode; /**< ProxyMode_T */ + uint32_t uLogHistoryCount; + bool fExclusiveHwVirt; + com::Utf8Str strLanguageId; +}; + +struct MachineRegistryEntry +{ + com::Guid uuid; + com::Utf8Str strSettingsFile; +}; + +typedef std::list MachinesRegistry; + +struct DhcpOptValue +{ + DhcpOptValue(); + DhcpOptValue(const com::Utf8Str &aText, DHCPOptionEncoding_T aEncoding = DHCPOptionEncoding_Normal); + + com::Utf8Str strValue; + DHCPOptionEncoding_T enmEncoding; +}; + +typedef std::map DhcpOptionMap; +typedef DhcpOptionMap::value_type DhcpOptValuePair; +typedef DhcpOptionMap::iterator DhcpOptIterator; +typedef DhcpOptionMap::const_iterator DhcpOptConstIterator; + +struct DHCPGroupCondition +{ + DHCPGroupCondition(); + + bool fInclusive; + DHCPGroupConditionType_T enmType; + com::Utf8Str strValue; +}; +typedef std::vector DHCPGroupConditionVec; + + +struct DHCPConfig +{ + DHCPConfig(); + + DhcpOptionMap mapOptions; + uint32_t secMinLeaseTime; + uint32_t secDefaultLeaseTime; + uint32_t secMaxLeaseTime; + com::Utf8Str strForcedOptions; + com::Utf8Str strSuppressedOptions; +}; + +struct DHCPGroupConfig : DHCPConfig +{ + DHCPGroupConfig(); + + com::Utf8Str strName; + DHCPGroupConditionVec vecConditions; +}; +typedef std::vector DHCPGroupConfigVec; + +struct DHCPIndividualConfig : DHCPConfig +{ + DHCPIndividualConfig(); + + com::Utf8Str strMACAddress; + com::Utf8Str strVMName; + uint32_t uSlot; + com::Utf8Str strFixedAddress; +}; +typedef std::map DHCPIndividualConfigMap; + +struct DHCPServer +{ + DHCPServer(); + + com::Utf8Str strNetworkName; + com::Utf8Str strIPAddress; + com::Utf8Str strIPLower; + com::Utf8Str strIPUpper; + bool fEnabled; + DHCPConfig globalConfig; + DHCPGroupConfigVec vecGroupConfigs; + DHCPIndividualConfigMap mapIndividualConfigs; +}; +typedef std::list DHCPServersList; + + +/** + * NAT Networking settings (NAT service). + */ +struct NATNetwork +{ + NATNetwork(); + + com::Utf8Str strNetworkName; + com::Utf8Str strIPv4NetworkCidr; + com::Utf8Str strIPv6Prefix; + bool fEnabled; + bool fIPv6Enabled; + bool fAdvertiseDefaultIPv6Route; + bool fNeedDhcpServer; + uint32_t u32HostLoopback6Offset; + NATLoopbackOffsetList llHostLoopbackOffsetList; + NATRulesMap mapPortForwardRules4; + NATRulesMap mapPortForwardRules6; +}; + +typedef std::list NATNetworksList; + +#ifdef VBOX_WITH_VMNET +/** + * HostOnly Networking settings. + */ +struct HostOnlyNetwork +{ + HostOnlyNetwork(); + + com::Guid uuid; + com::Utf8Str strNetworkName; + com::Utf8Str strNetworkMask; + com::Utf8Str strIPLower; + com::Utf8Str strIPUpper; + bool fEnabled; +}; + +typedef std::list HostOnlyNetworksList; +#endif /* VBOX_WITH_VMNET */ + +#ifdef VBOX_WITH_CLOUD_NET +/** + * Cloud Networking settings. + */ +struct CloudNetwork +{ + CloudNetwork(); + + com::Utf8Str strNetworkName; + com::Utf8Str strProviderShortName; + com::Utf8Str strProfileName; + com::Utf8Str strNetworkId; + bool fEnabled; +}; + +typedef std::list CloudNetworksList; +#endif /* VBOX_WITH_CLOUD_NET */ + + +class MainConfigFile : public ConfigFileBase +{ +public: + MainConfigFile(const com::Utf8Str *pstrFilename); + + void readMachineRegistry(const xml::ElementNode &elmMachineRegistry); + void readNATNetworks(const xml::ElementNode &elmNATNetworks); +#ifdef VBOX_WITH_VMNET + void readHostOnlyNetworks(const xml::ElementNode &elmHostOnlyNetworks); +#endif /* VBOX_WITH_VMNET */ +#ifdef VBOX_WITH_CLOUD_NET + void readCloudNetworks(const xml::ElementNode &elmCloudNetworks); +#endif /* VBOX_WITH_CLOUD_NET */ + + void write(const com::Utf8Str strFilename); + + Host host; + SystemProperties systemProperties; + MediaRegistry mediaRegistry; + MachinesRegistry llMachines; + DHCPServersList llDhcpServers; + NATNetworksList llNATNetworks; +#ifdef VBOX_WITH_VMNET + HostOnlyNetworksList llHostOnlyNetworks; +#endif /* VBOX_WITH_VMNET */ +#ifdef VBOX_WITH_CLOUD_NET + CloudNetworksList llCloudNetworks; +#endif /* VBOX_WITH_CLOUD_NET */ + StringsMap mapExtraDataItems; + +private: + void bumpSettingsVersionIfNeeded(); + void buildUSBDeviceSources(xml::ElementNode &elmParent, const USBDeviceSourcesList &ll); + void readUSBDeviceSources(const xml::ElementNode &elmDeviceSources, USBDeviceSourcesList &ll); + void buildDHCPServers(xml::ElementNode &elmDHCPServers, DHCPServersList const &ll); + void buildDHCPOptions(xml::ElementNode &elmOptions, DHCPConfig const &rConfig, bool fIgnoreSubnetMask); + void readDHCPServers(const xml::ElementNode &elmDHCPServers); + void readDHCPOptions(DHCPConfig &rConfig, const xml::ElementNode &elmOptions, bool fIgnoreSubnetMask); + bool convertGuiProxySettings(const com::Utf8Str &strUIProxySettings); +}; + +//////////////////////////////////////////////////////////////////////////////// +// +// Machine XML structures +// +//////////////////////////////////////////////////////////////////////////////// + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct VRDESettings +{ + VRDESettings(); + + bool areDefaultSettings(SettingsVersion_T sv) const; + + bool operator==(const VRDESettings& v) const; + + bool fEnabled; + AuthType_T authType; + uint32_t ulAuthTimeout; + com::Utf8Str strAuthLibrary; + bool fAllowMultiConnection, + fReuseSingleConnection; + com::Utf8Str strVrdeExtPack; + StringsMap mapProperties; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct BIOSSettings +{ + BIOSSettings(); + + bool areDefaultSettings() const; + + bool operator==(const BIOSSettings &d) const; + + bool fACPIEnabled, + fIOAPICEnabled, + fLogoFadeIn, + fLogoFadeOut, + fPXEDebugEnabled, + fSmbiosUuidLittleEndian; + uint32_t ulLogoDisplayTime; + BIOSBootMenuMode_T biosBootMenuMode; + APICMode_T apicMode; // requires settings version 1.16 (VirtualBox 5.1) + int64_t llTimeOffset; + com::Utf8Str strLogoImagePath; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct TpmSettings +{ + TpmSettings(); + + bool areDefaultSettings() const; + + bool operator==(const TpmSettings &d) const; + + TpmType_T tpmType; + com::Utf8Str strLocation; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct NvramSettings +{ + NvramSettings(); + + bool areDefaultSettings() const; + + bool operator==(const NvramSettings &d) const; + + com::Utf8Str strNvramPath; + com::Utf8Str strKeyId; + com::Utf8Str strKeyStore; +}; + +/** List for keeping a recording feature list. */ +typedef std::map RecordingFeatureMap; + +/** + * Recording settings for a single screen (e.g. virtual monitor). + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct RecordingScreenSettings +{ + RecordingScreenSettings(uint32_t idScreen = UINT32_MAX); + + virtual ~RecordingScreenSettings(); + + void applyDefaults(void); + + bool areDefaultSettings(void) const; + + bool isFeatureEnabled(RecordingFeature_T enmFeature) const; + + static const char *getDefaultOptions(void); + + static int featuresFromString(const com::Utf8Str &strFeatures, RecordingFeatureMap &featureMap); + + static void featuresToString(const RecordingFeatureMap &featureMap, com::Utf8Str &strFeatures); + + static int audioCodecFromString(const com::Utf8Str &strCodec, RecordingAudioCodec_T &enmCodec); + + static void audioCodecToString(const RecordingAudioCodec_T &enmCodec, com::Utf8Str &strCodec); + + static int videoCodecFromString(const com::Utf8Str &strCodec, RecordingVideoCodec_T &enmCodec); + + static void videoCodecToString(const RecordingVideoCodec_T &enmCodec, com::Utf8Str &strCodec); + + bool operator==(const RecordingScreenSettings &d) const; + + /** Screen ID. + * UINT32_MAX if not set. */ + uint32_t idScreen; + /** Whether to record this screen or not. */ + bool fEnabled; // requires settings version 1.14 (VirtualBox 4.3) + /** Destination to record to. */ + RecordingDestination_T enmDest; + /** Which features are enable or not. */ + RecordingFeatureMap featureMap; // requires settings version 1.19 (VirtualBox 7.0) + /** Maximum time (in s) to record. If set to 0, no time limit is set. */ + uint32_t ulMaxTimeS; // requires settings version 1.14 (VirtualBox 4.3) + /** Options string for hidden / advanced / experimental features. + * Use RecordingScreenSettings::getDefaultOptions(). */ + com::Utf8Str strOptions; // new since VirtualBox 5.2. + + /** + * Structure holding settings for audio recording. + */ + struct Audio + { + /** The audio codec type to use. */ + RecordingAudioCodec_T enmCodec; // requires settings version 1.19 (VirtualBox 7.0) + /** Codec deadline to use. */ + RecordingCodecDeadline_T enmDeadline; // requires settings version 1.19 (VirtualBox 7.0) + /** Rate control mode to use. */ + RecordingRateControlMode_T + enmRateCtlMode;// requires settings version 1.19 (VirtualBox 7.0) + /** Hz rate. */ + uint16_t uHz; // requires settings version 1.19 (VirtualBox 7.0) + /** Bits per sample. */ + uint8_t cBits; // requires settings version 1.19 (VirtualBox 7.0) + /** Number of audio channels. */ + uint8_t cChannels; // requires settings version 1.19 (VirtualBox 7.0) + } Audio; + + /** + * Structure holding settings for video recording. + */ + struct Video + { + /** The codec to use. */ + RecordingVideoCodec_T enmCodec; // requires settings version 1.19 (VirtualBox 7.0) + /** Codec deadline to use. */ + RecordingCodecDeadline_T enmDeadline; // requires settings version 1.19 (VirtualBox 7.0) + /** Rate control mode to use. */ + RecordingRateControlMode_T + enmRateCtlMode; // requires settings version 1.19 (VirtualBox 7.0) + /** Rate control mode to use. */ + RecordingVideoScalingMode_T + enmScalingMode; // requires settings version 1.19 (VirtualBox 7.0) + /** Target frame width in pixels (X). */ + uint32_t ulWidth; // requires settings version 1.14 (VirtualBox 4.3) + /** Target frame height in pixels (Y). */ + uint32_t ulHeight; // requires settings version 1.14 (VirtualBox 4.3) + /** Encoding rate. */ + uint32_t ulRate; // requires settings version 1.14 (VirtualBox 4.3) + /** Frames per second (FPS). */ + uint32_t ulFPS; // requires settings version 1.14 (VirtualBox 4.3) + } Video; + + /** + * Structure holding settings if the destination is a file. + */ + struct File + { + /** Maximum size (in MB) the file is allowed to have. + * When reaching the limit, recording will stop. 0 means no limit. */ + uint32_t ulMaxSizeMB; // requires settings version 1.14 (VirtualBox 4.3) + /** Absolute file name path to use for recording. + * When empty, this is considered as being the default setting. */ + com::Utf8Str strName; // requires settings version 1.14 (VirtualBox 4.3) + } File; +}; + +/** Map for keeping settings per virtual screen. + * The key specifies the screen ID. */ +typedef std::map RecordingScreenSettingsMap; + +/** + * Common recording settings, shared among all per-screen recording settings. + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct RecordingCommonSettings +{ + RecordingCommonSettings(); + + void applyDefaults(void); + + bool areDefaultSettings(void) const; + + bool operator==(const RecordingCommonSettings &d) const; + + /** Whether recording as a whole is enabled or disabled. */ + bool fEnabled; // requires settings version 1.14 (VirtualBox 4.3) +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct RecordingSettings +{ + RecordingSettings(); + + void applyDefaults(void); + + bool areDefaultSettings(void) const; + + bool operator==(const RecordingSettings &that) const; + + /** Common settings for all per-screen recording settings. */ + RecordingCommonSettings common; + /** Map of handled recording screen settings. + * The key specifies the screen ID. */ + RecordingScreenSettingsMap mapScreens; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct GraphicsAdapter +{ + GraphicsAdapter(); + + bool areDefaultSettings() const; + + bool operator==(const GraphicsAdapter &g) const; + + GraphicsControllerType_T graphicsControllerType; + uint32_t ulVRAMSizeMB; + uint32_t cMonitors; + bool fAccelerate3D, + fAccelerate2DVideo; // requires settings version 1.8 (VirtualBox 3.1) +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct USBController +{ + USBController(); + + bool operator==(const USBController &u) const; + + com::Utf8Str strName; + USBControllerType_T enmType; +}; + +typedef std::list USBControllerList; + +struct USB +{ + USB(); + + bool operator==(const USB &u) const; + + /** List of USB controllers present. */ + USBControllerList llUSBControllers; + /** List of USB device filters. */ + USBDeviceFiltersList llDeviceFilters; +}; + +struct NAT +{ + NAT(); + + bool areDNSDefaultSettings() const; + bool areAliasDefaultSettings() const; + bool areTFTPDefaultSettings() const; + bool areLocalhostReachableDefaultSettings(SettingsVersion_T sv) const; + bool areDefaultSettings(SettingsVersion_T sv) const; + + bool operator==(const NAT &n) const; + + com::Utf8Str strNetwork; + com::Utf8Str strBindIP; + uint32_t u32Mtu; + uint32_t u32SockRcv; + uint32_t u32SockSnd; + uint32_t u32TcpRcv; + uint32_t u32TcpSnd; + com::Utf8Str strTFTPPrefix; + com::Utf8Str strTFTPBootFile; + com::Utf8Str strTFTPNextServer; + bool fDNSPassDomain; + bool fDNSProxy; + bool fDNSUseHostResolver; + bool fAliasLog; + bool fAliasProxyOnly; + bool fAliasUseSamePorts; + bool fLocalhostReachable; + NATRulesMap mapRules; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct NetworkAdapter +{ + NetworkAdapter(); + + bool areGenericDriverDefaultSettings() const; + bool areDefaultSettings(SettingsVersion_T sv) const; + bool areDisabledDefaultSettings(SettingsVersion_T sv) const; + + bool operator==(const NetworkAdapter &n) const; + + uint32_t ulSlot; + + NetworkAdapterType_T type; + bool fEnabled; + com::Utf8Str strMACAddress; + bool fCableConnected; + uint32_t ulLineSpeed; + NetworkAdapterPromiscModePolicy_T enmPromiscModePolicy; + bool fTraceEnabled; + com::Utf8Str strTraceFile; + + NetworkAttachmentType_T mode; + NAT nat; + com::Utf8Str strBridgedName; + com::Utf8Str strHostOnlyName; +#ifdef VBOX_WITH_VMNET + com::Utf8Str strHostOnlyNetworkName; +#endif /* VBOX_WITH_VMNET */ + com::Utf8Str strInternalNetworkName; + com::Utf8Str strGenericDriver; + StringsMap genericProperties; + com::Utf8Str strNATNetworkName; +#ifdef VBOX_WITH_CLOUD_NET + com::Utf8Str strCloudNetworkName; +#endif /* VBOX_WITH_CLOUD_NET */ + uint32_t ulBootPriority; + com::Utf8Str strBandwidthGroup; // requires settings version 1.13 (VirtualBox 4.2) +}; + +typedef std::list NetworkAdaptersList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct SerialPort +{ + SerialPort(); + + bool operator==(const SerialPort &n) const; + + uint32_t ulSlot; + + bool fEnabled; + uint32_t ulIOBase; + uint32_t ulIRQ; + PortMode_T portMode; + com::Utf8Str strPath; + bool fServer; + UartType_T uartType; +}; + +typedef std::list SerialPortsList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct ParallelPort +{ + ParallelPort(); + + bool operator==(const ParallelPort &d) const; + + uint32_t ulSlot; + + bool fEnabled; + uint32_t ulIOBase; + uint32_t ulIRQ; + com::Utf8Str strPath; +}; + +typedef std::list ParallelPortsList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct AudioAdapter +{ + AudioAdapter(); + + bool areDefaultSettings(SettingsVersion_T sv) const; + + bool operator==(const AudioAdapter &a) const; + + bool fEnabled; + bool fEnabledIn; + bool fEnabledOut; + AudioControllerType_T controllerType; + AudioCodecType_T codecType; + AudioDriverType_T driverType; + settings::StringsMap properties; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct SharedFolder +{ + SharedFolder(); + + bool operator==(const SharedFolder &a) const; + + com::Utf8Str strName, + strHostPath; + bool fWritable; + bool fAutoMount; + com::Utf8Str strAutoMountPoint; +}; + +typedef std::list SharedFoldersList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct GuestProperty +{ + GuestProperty(); + + bool operator==(const GuestProperty &g) const; + + com::Utf8Str strName, + strValue; + uint64_t timestamp; + com::Utf8Str strFlags; +}; + +typedef std::list GuestPropertiesList; + +typedef std::map BootOrderMap; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct CpuIdLeaf +{ + CpuIdLeaf(); + + bool operator==(const CpuIdLeaf &c) const; + + uint32_t idx; + uint32_t idxSub; + uint32_t uEax; + uint32_t uEbx; + uint32_t uEcx; + uint32_t uEdx; +}; + +typedef std::list CpuIdLeafsList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct Cpu +{ + Cpu(); + + bool operator==(const Cpu &c) const; + + uint32_t ulId; +}; + +typedef std::list CpuList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct BandwidthGroup +{ + BandwidthGroup(); + + bool operator==(const BandwidthGroup &i) const; + + com::Utf8Str strName; + uint64_t cMaxBytesPerSec; + BandwidthGroupType_T enmType; +}; + +typedef std::list BandwidthGroupList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct IOSettings +{ + IOSettings(); + + bool areIOCacheDefaultSettings() const; + bool areDefaultSettings() const; + + bool operator==(const IOSettings &i) const; + + bool fIOCacheEnabled; + uint32_t ulIOCacheSize; + BandwidthGroupList llBandwidthGroups; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct HostPCIDeviceAttachment +{ + HostPCIDeviceAttachment(); + + bool operator==(const HostPCIDeviceAttachment &a) const; + + com::Utf8Str strDeviceName; + uint32_t uHostAddress; + uint32_t uGuestAddress; +}; + +typedef std::list HostPCIDeviceAttachmentList; + +/** + * A device attached to a storage controller. This can either be a + * hard disk or a DVD drive or a floppy drive and also specifies + * which medium is "in" the drive; as a result, this is a combination + * of the Main IMedium and IMediumAttachment interfaces. + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct AttachedDevice +{ + AttachedDevice(); + + bool operator==(const AttachedDevice &a) const; + + DeviceType_T deviceType; // only HardDisk, DVD or Floppy are allowed + + // DVDs can be in pass-through mode: + bool fPassThrough; + + // Whether guest-triggered eject of DVDs will keep the medium in the + // VM config or not: + bool fTempEject; + + // Whether the medium is non-rotational: + bool fNonRotational; + + // Whether the medium supports discarding unused blocks: + bool fDiscard; + + // Whether the medium is hot-pluggable: + bool fHotPluggable; + + int32_t lPort; + int32_t lDevice; + + // if an image file is attached to the device (ISO, RAW, or hard disk image such as VDI), + // this is its UUID; it depends on deviceType which media registry this then needs to + // be looked up in. If no image file (only permitted for DVDs and floppies), then the UUID is NULL + com::Guid uuid; + + // for DVDs and floppies, the attachment can also be a host device: + com::Utf8Str strHostDriveSrc; // if != NULL, value of /@src + + // Bandwidth group the device is attached to. + com::Utf8Str strBwGroup; +}; + +typedef std::list AttachedDevicesList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct StorageController +{ + StorageController(); + + bool operator==(const StorageController &s) const; + + com::Utf8Str strName; + StorageBus_T storageBus; // _SATA, _SCSI, _IDE, _SAS + StorageControllerType_T controllerType; + uint32_t ulPortCount; + uint32_t ulInstance; + bool fUseHostIOCache; + bool fBootable; + + // only for when controllerType == StorageControllerType_IntelAhci: + int32_t lIDE0MasterEmulationPort, + lIDE0SlaveEmulationPort, + lIDE1MasterEmulationPort, + lIDE1SlaveEmulationPort; + + AttachedDevicesList llAttachedDevices; +}; + +typedef std::list StorageControllersList; + +/** + * We wrap the storage controllers list into an extra struct so we can + * use an undefined struct without needing std::list<> in all the headers. + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct Storage +{ + bool operator==(const Storage &s) const; + + StorageControllersList llStorageControllers; +}; + +/** + * Representation of Machine hardware; this is used in the MachineConfigFile.hardwareMachine + * field. + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct Hardware +{ + Hardware(); + + bool areParavirtDefaultSettings(SettingsVersion_T sv) const; + bool areBootOrderDefaultSettings() const; + bool areDisplayDefaultSettings() const; + bool areAllNetworkAdaptersDefaultSettings(SettingsVersion_T sv) const; + + bool operator==(const Hardware&) const; + + com::Utf8Str strVersion; // hardware version, optional + com::Guid uuid; // hardware uuid, optional (null). + + bool fHardwareVirt, + fNestedPaging, + fLargePages, + fVPID, + fUnrestrictedExecution, + fHardwareVirtForce, + fUseNativeApi, + fSyntheticCpu, + fTripleFaultReset, + fPAE, + fAPIC, // requires settings version 1.16 (VirtualBox 5.1) + fX2APIC; // requires settings version 1.16 (VirtualBox 5.1) + bool fIBPBOnVMExit; //< added out of cycle, after 1.16 was out. + bool fIBPBOnVMEntry; //< added out of cycle, after 1.16 was out. + bool fSpecCtrl; //< added out of cycle, after 1.16 was out. + bool fSpecCtrlByHost; //< added out of cycle, after 1.16 was out. + bool fL1DFlushOnSched ; //< added out of cycle, after 1.16 was out. + bool fL1DFlushOnVMEntry ; //< added out of cycle, after 1.16 was out. + bool fMDSClearOnSched; //< added out of cycle, after 1.16 was out. + bool fMDSClearOnVMEntry; //< added out of cycle, after 1.16 was out. + bool fNestedHWVirt; //< requires settings version 1.17 (VirtualBox 6.0) + bool fVirtVmsaveVmload; //< requires settings version 1.18 (VirtualBox 6.1) + typedef enum LongModeType { LongMode_Enabled, LongMode_Disabled, LongMode_Legacy } LongModeType; + LongModeType enmLongMode; + uint32_t cCPUs; + bool fCpuHotPlug; // requires settings version 1.10 (VirtualBox 3.2) + CpuList llCpus; // requires settings version 1.10 (VirtualBox 3.2) + bool fHPETEnabled; // requires settings version 1.10 (VirtualBox 3.2) + uint32_t ulCpuExecutionCap; // requires settings version 1.11 (VirtualBox 3.3) + uint32_t uCpuIdPortabilityLevel; // requires settings version 1.15 (VirtualBox 5.0) + com::Utf8Str strCpuProfile; // requires settings version 1.16 (VirtualBox 5.1) + + CpuIdLeafsList llCpuIdLeafs; + + uint32_t ulMemorySizeMB; + + BootOrderMap mapBootOrder; // item 0 has highest priority + + FirmwareType_T firmwareType; // requires settings version 1.9 (VirtualBox 3.1) + + PointingHIDType_T pointingHIDType; // requires settings version 1.10 (VirtualBox 3.2) + KeyboardHIDType_T keyboardHIDType; // requires settings version 1.10 (VirtualBox 3.2) + + ChipsetType_T chipsetType; // requires settings version 1.11 (VirtualBox 4.0) + IommuType_T iommuType; // requires settings version 1.19 (VirtualBox 6.2) + ParavirtProvider_T paravirtProvider; // requires settings version 1.15 (VirtualBox 4.4) + com::Utf8Str strParavirtDebug; // requires settings version 1.16 (VirtualBox 5.1) + + bool fEmulatedUSBCardReader; // 1.12 (VirtualBox 4.1) + + VRDESettings vrdeSettings; + + BIOSSettings biosSettings; + NvramSettings nvramSettings; + GraphicsAdapter graphicsAdapter; + USB usbSettings; + TpmSettings tpmSettings; // requires settings version 1.19 (VirtualBox 6.2) + NetworkAdaptersList llNetworkAdapters; + SerialPortsList llSerialPorts; + ParallelPortsList llParallelPorts; + AudioAdapter audioAdapter; + Storage storage; + + // technically these two have no business in the hardware section, but for some + // clever reason is where they are in the XML.... + SharedFoldersList llSharedFolders; + + ClipboardMode_T clipboardMode; + bool fClipboardFileTransfersEnabled; + + DnDMode_T dndMode; + + uint32_t ulMemoryBalloonSize; + bool fPageFusionEnabled; + + GuestPropertiesList llGuestProperties; + + IOSettings ioSettings; // requires settings version 1.10 (VirtualBox 3.2) + HostPCIDeviceAttachmentList pciAttachments; // requires settings version 1.12 (VirtualBox 4.1) + + com::Utf8Str strDefaultFrontend; // requires settings version 1.14 (VirtualBox 4.3) +}; + +/** + * Settings that has to do with debugging. + */ +struct Debugging +{ + Debugging(); + + bool areDefaultSettings() const; + + bool operator==(const Debugging &rOther) const; + + bool fTracingEnabled; + bool fAllowTracingToAccessVM; + com::Utf8Str strTracingConfig; + GuestDebugProvider_T enmDbgProvider; + GuestDebugIoProvider_T enmIoProvider; + com::Utf8Str strAddress; + uint32_t ulPort; +}; + +/** + * Settings that has to do with autostart. + */ +struct Autostart +{ + Autostart(); + + bool areDefaultSettings() const; + + bool operator==(const Autostart &rOther) const; + + bool fAutostartEnabled; + uint32_t uAutostartDelay; + AutostopType_T enmAutostopType; +}; + +struct Snapshot; +typedef std::list SnapshotsList; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct Snapshot +{ + Snapshot(); + + bool operator==(const Snapshot &s) const; + + com::Guid uuid; + com::Utf8Str strName, + strDescription; // optional + RTTIMESPEC timestamp; + + com::Utf8Str strStateFile; // for online snapshots only + + Hardware hardware; + + Debugging debugging; + Autostart autostart; + RecordingSettings recordingSettings; + + SnapshotsList llChildSnapshots; + + static const struct Snapshot Empty; +}; + +/** + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by MachineConfigFile::operator==(), or otherwise + * your settings might never get saved. + */ +struct MachineUserData +{ + MachineUserData(); + + bool operator==(const MachineUserData &c) const; + + com::Utf8Str strName; + bool fDirectoryIncludesUUID; + bool fNameSync; + com::Utf8Str strDescription; + StringsList llGroups; + com::Utf8Str strOsType; + com::Utf8Str strSnapshotFolder; + bool fTeleporterEnabled; + uint32_t uTeleporterPort; + com::Utf8Str strTeleporterAddress; + com::Utf8Str strTeleporterPassword; + bool fRTCUseUTC; + IconBlob ovIcon; + VMProcPriority_T enmVMPriority; +}; + + +/** + * MachineConfigFile represents an XML machine configuration. All the machine settings + * that go out to the XML (or are read from it) are in here. + * + * NOTE: If you add any fields in here, you must update a) the constructor and b) + * the operator== which is used by Machine::saveSettings(), or otherwise your settings + * might never get saved. + */ +class MachineConfigFile : public ConfigFileBase +{ +public: + com::Guid uuid; + + enum + { + ParseState_NotParsed, + ParseState_PasswordError, + ParseState_Parsed + } enmParseState; + + MachineUserData machineUserData; + + com::Utf8Str strStateKeyId; + com::Utf8Str strStateKeyStore; + com::Utf8Str strStateFile; + bool fCurrentStateModified; // optional, default is true + RTTIMESPEC timeLastStateChange; // optional, defaults to now + bool fAborted; // optional, default is false + + com::Guid uuidCurrentSnapshot; + + Hardware hardwareMachine; + MediaRegistry mediaRegistry; + Debugging debugging; + Autostart autostart; + RecordingSettings recordingSettings; + + StringsMap mapExtraDataItems; + + SnapshotsList llFirstSnapshot; // first snapshot or empty list if there's none + + com::Utf8Str strKeyId; + com::Utf8Str strKeyStore; // if not empty, the encryption is used + com::Utf8Str strLogKeyId; + com::Utf8Str strLogKeyStore; + + MachineConfigFile(const com::Utf8Str *pstrFilename, + PCVBOXCRYPTOIF pCryptoIf = NULL, + const char *pszPassword = NULL); + + bool operator==(const MachineConfigFile &m) const; + + bool canHaveOwnMediaRegistry() const; + + void importMachineXML(const xml::ElementNode &elmMachine); + + void write(const com::Utf8Str &strFilename, PCVBOXCRYPTOIF pCryptoIf = NULL, const char *pszPassword = NULL); + + enum + { + BuildMachineXML_IncludeSnapshots = 0x01, + BuildMachineXML_WriteVBoxVersionAttribute = 0x02, + BuildMachineXML_SkipRemovableMedia = 0x04, + BuildMachineXML_MediaRegistry = 0x08, + BuildMachineXML_SuppressSavedState = 0x10 + }; + + void copyEncryptionSettingsFrom(const MachineConfigFile &other); + void buildMachineXML(xml::ElementNode &elmMachine, + uint32_t fl, + std::list *pllElementsWithUuidAttributes); + + static bool isAudioDriverAllowedOnThisHost(AudioDriverType_T enmDrvType); + static AudioDriverType_T getHostDefaultAudioDriver(); + +private: + void readNetworkAdapters(const xml::ElementNode &elmHardware, NetworkAdaptersList &ll); + void readAttachedNetworkMode(const xml::ElementNode &pelmMode, bool fEnabled, NetworkAdapter &nic); + void readCpuIdTree(const xml::ElementNode &elmCpuid, CpuIdLeafsList &ll); + void readCpuTree(const xml::ElementNode &elmCpu, CpuList &ll); + void readSerialPorts(const xml::ElementNode &elmUART, SerialPortsList &ll); + void readParallelPorts(const xml::ElementNode &elmLPT, ParallelPortsList &ll); + void readAudioAdapter(const xml::ElementNode &elmAudioAdapter, AudioAdapter &aa); + void readGuestProperties(const xml::ElementNode &elmGuestProperties, Hardware &hw); + void readStorageControllerAttributes(const xml::ElementNode &elmStorageController, StorageController &sctl); + void readHardware(const xml::ElementNode &elmHardware, Hardware &hw); + void readHardDiskAttachments_pre1_7(const xml::ElementNode &elmHardDiskAttachments, Storage &strg); + void readStorageControllers(const xml::ElementNode &elmStorageControllers, Storage &strg); + void readDVDAndFloppies_pre1_9(const xml::ElementNode &elmHardware, Storage &strg); + void readTeleporter(const xml::ElementNode &elmTeleporter, MachineUserData &userData); + void readDebugging(const xml::ElementNode &elmDbg, Debugging &dbg); + void readAutostart(const xml::ElementNode &elmAutostart, Autostart &autostrt); + void readRecordingSettings(const xml::ElementNode &elmRecording, uint32_t cMonitors, RecordingSettings &recording); + void readGroups(const xml::ElementNode &elmGroups, StringsList &llGroups); + bool readSnapshot(const com::Guid &curSnapshotUuid, const xml::ElementNode &elmSnapshot, Snapshot &snap); + void convertOldOSType_pre1_5(com::Utf8Str &str); + void readMachine(const xml::ElementNode &elmMachine); + void readMachineEncrypted(const xml::ElementNode &elmMachine, PCVBOXCRYPTOIF pCryptoIf, const char *pszPassword); + + void buildHardwareXML(xml::ElementNode &elmParent, const Hardware &hw, uint32_t fl, std::list *pllElementsWithUuidAttributes); + void buildNetworkXML(NetworkAttachmentType_T mode, bool fEnabled, xml::ElementNode &elmParent, const NetworkAdapter &nic); + void buildStorageControllersXML(xml::ElementNode &elmParent, + const Storage &st, + bool fSkipRemovableMedia, + std::list *pllElementsWithUuidAttributes); + void buildDebuggingXML(xml::ElementNode &elmParent, const Debugging &dbg); + void buildAutostartXML(xml::ElementNode &elmParent, const Autostart &autostrt); + void buildRecordingXML(xml::ElementNode &elmParent, const RecordingSettings &recording); + void buildGroupsXML(xml::ElementNode &elmParent, const StringsList &llGroups); + void buildSnapshotXML(xml::ElementNode &elmParent, const Snapshot &snap); + + void buildMachineEncryptedXML(xml::ElementNode &elmMachine, + uint32_t fl, + std::list *pllElementsWithUuidAttributes, + PCVBOXCRYPTOIF pCryptoIf, + const char *pszPassword); + + void bumpSettingsVersionIfNeeded(); +}; + +} // namespace settings + + +#endif /* !VBOX_INCLUDED_settings_h */ diff --git a/include/VBox/shflsvc.h b/include/VBox/shflsvc.h new file mode 100644 index 00000000..725eae76 --- /dev/null +++ b/include/VBox/shflsvc.h @@ -0,0 +1,2151 @@ +/** @file + * Shared Folders - Common header for host service and guest clients. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef VBOX_INCLUDED_shflsvc_h +#define VBOX_INCLUDED_shflsvc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef IN_MODULE +# include +# include +#endif +#include +#include +#include +#include +#include +#include +#if defined(IN_RING3) || (defined(IN_RING0) && defined(RT_OS_DARWIN)) +# include +#endif +#include + + + +/** @defgroup grp_vbox_shfl Shared Folder Interface Definition. + * + * Structures shared between guest and the service can be relocated and use + * offsets to point to variable length parts. + * + * Shared folders protocol works with handles. Before doing any action on a + * file system object, one have to obtain the object handle via a SHFL_FN_CREATE + * request. A handle must be closed with SHFL_FN_CLOSE. + * + * @{ + */ + +/** @name Some bit flag manipulation macros. + * @{ */ +#ifndef BIT_FLAG +#define BIT_FLAG(__Field,__Flag) ((__Field) & (__Flag)) +#endif + +#ifndef BIT_FLAG_SET +#define BIT_FLAG_SET(__Field,__Flag) ((__Field) |= (__Flag)) +#endif + +#ifndef BIT_FLAG_CLEAR +#define BIT_FLAG_CLEAR(__Field,__Flag) ((__Field) &= ~(__Flag)) +#endif +/** @} */ + + +/** @name Shared Folders service functions. (guest) + * @{ + */ +/** Query mappings changes. + * @note Description is currently misleading, it will always return all + * current mappings with SHFL_MS_NEW status. Only modification is the + * SHFL_MF_AUTOMOUNT flag that causes filtering out non-auto mounts. */ +#define SHFL_FN_QUERY_MAPPINGS (1) +/** Query the name of a map. */ +#define SHFL_FN_QUERY_MAP_NAME (2) +/** Open/create object. */ +#define SHFL_FN_CREATE (3) +/** Close object handle. */ +#define SHFL_FN_CLOSE (4) +/** Read object content. */ +#define SHFL_FN_READ (5) +/** Write new object content. */ +#define SHFL_FN_WRITE (6) +/** Lock/unlock a range in the object. */ +#define SHFL_FN_LOCK (7) +/** List object content. */ +#define SHFL_FN_LIST (8) +/** Query/set object information. */ +#define SHFL_FN_INFORMATION (9) +/** Remove object */ +#define SHFL_FN_REMOVE (11) +/** Map folder (legacy) */ +#define SHFL_FN_MAP_FOLDER_OLD (12) +/** Unmap folder */ +#define SHFL_FN_UNMAP_FOLDER (13) +/** Rename object (possibly moving it to another directory) */ +#define SHFL_FN_RENAME (14) +/** Flush file */ +#define SHFL_FN_FLUSH (15) +/** @todo macl, a description, please. */ +#define SHFL_FN_SET_UTF8 (16) +/** Map folder */ +#define SHFL_FN_MAP_FOLDER (17) +/** Read symlink destination. + * @since VBox 4.0 */ +#define SHFL_FN_READLINK (18) /**< @todo rename to SHFL_FN_READ_LINK (see struct capitalization) */ +/** Create symlink. + * @since VBox 4.0 */ +#define SHFL_FN_SYMLINK (19) +/** Ask host to show symlinks + * @since VBox 4.0 */ +#define SHFL_FN_SET_SYMLINKS (20) +/** Query information about a map. + * @since VBox 6.0 */ +#define SHFL_FN_QUERY_MAP_INFO (21) +/** Wait for changes to the mappings. + * @since VBox 6.0 */ +#define SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES (22) +/** Cancel all waits for changes to the mappings for the calling client. + * The wait calls will return VERR_CANCELLED. + * @since VBox 6.0 */ +#define SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS (23) +/** Sets the file size. + * @since VBox 6.0 */ +#define SHFL_FN_SET_FILE_SIZE (24) +/** Queries supported features. + * @since VBox 6.0.6 */ +#define SHFL_FN_QUERY_FEATURES (25) +/** Copies a file to another. + * @since VBox 6.0.6 */ +#define SHFL_FN_COPY_FILE (26) +/** Copies part of a file to another. + * @since VBox 6.0.6 */ +#define SHFL_FN_COPY_FILE_PART (27) +/** Close handle to (optional) and remove object by path. + * This function is tailored for Windows guests. + * @since VBox 6.0.8 */ +#define SHFL_FN_CLOSE_AND_REMOVE (28) +/** Set the host error code style. + * This is for more efficiently getting the correct error status when the host + * and guest OS types differs and it won't happen naturally. + * @since VBox 6.0.10 */ +#define SHFL_FN_SET_ERROR_STYLE (29) +/** The last function number. */ +#define SHFL_FN_LAST SHFL_FN_SET_ERROR_STYLE +/** @} */ + + +/** @name Shared Folders service functions. (host) + * @{ + */ +/** Add shared folder mapping. */ +#define SHFL_FN_ADD_MAPPING (1) +/** Remove shared folder mapping. */ +#define SHFL_FN_REMOVE_MAPPING (2) +/** Set the led status light address. */ +#define SHFL_FN_SET_STATUS_LED (3) +/** Allow the guest to create symbolic links + * @since VBox 4.0 */ +#define SHFL_FN_ALLOW_SYMLINKS_CREATE (4) +/** @} */ + + +/** Root handle for a mapping. Root handles are unique. + * + * @note Function parameters structures consider the root handle as 32 bit + * value. If the typedef will be changed, then function parameters must be + * changed accordingly. All those parameters are marked with SHFLROOT in + * comments. + */ +typedef uint32_t SHFLROOT; + +/** NIL shared folder root handle. */ +#define SHFL_ROOT_NIL ((SHFLROOT)~0) + + +/** A shared folders handle for an opened object. */ +typedef uint64_t SHFLHANDLE; + +#define SHFL_HANDLE_NIL ((SHFLHANDLE)~0LL) +#define SHFL_HANDLE_ROOT ((SHFLHANDLE)0LL) + +/** Hardcoded maximum length (in chars) of a shared folder name. */ +#define SHFL_MAX_LEN (256) +/** Hardcoded maximum number of shared folder mapping available to the guest. */ +#define SHFL_MAX_MAPPINGS (64) + + +/** @name Shared Folders strings. They can be either UTF-8 or UTF-16. + * @{ + */ + +/** + * Shared folder string buffer structure. + */ +typedef struct _SHFLSTRING +{ + /** Allocated size of the String member in bytes. */ + uint16_t u16Size; + + /** Length of string without trailing nul in bytes. */ + uint16_t u16Length; + + /** UTF-8 or UTF-16 string. Nul terminated. */ + union + { +#if 1 + char ach[1]; /**< UTF-8 but with a type that makes some more sense. */ + uint8_t utf8[1]; + RTUTF16 utf16[1]; + uint16_t ucs2[1]; /**< misnomer, use utf16. */ +#else + uint8_t utf8[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + RTUTF16 utf16[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; + RTUTF16 ucs2[RT_FLEXIBLE_ARRAY_IN_NESTED_UNION]; /**< misnomer, use utf16. */ +#endif + } String; +} SHFLSTRING; +AssertCompileSize(RTUTF16, 2); +AssertCompileSize(SHFLSTRING, 6); +AssertCompileMemberOffset(SHFLSTRING, String, 4); +/** The size of SHFLSTRING w/o the string part. */ +#define SHFLSTRING_HEADER_SIZE 4 +AssertCompileMemberOffset(SHFLSTRING, String, SHFLSTRING_HEADER_SIZE); + +/** Pointer to a shared folder string buffer. */ +typedef SHFLSTRING *PSHFLSTRING; +/** Pointer to a const shared folder string buffer. */ +typedef const SHFLSTRING *PCSHFLSTRING; + +/** Calculate size of the string. */ +DECLINLINE(uint32_t) ShflStringSizeOfBuffer(PCSHFLSTRING pString) +{ + return pString ? (uint32_t)(SHFLSTRING_HEADER_SIZE + pString->u16Size) : 0; +} + +DECLINLINE(uint32_t) ShflStringLength(PCSHFLSTRING pString) +{ + return pString ? pString->u16Length : 0; +} + +DECLINLINE(PSHFLSTRING) ShflStringInitBuffer(void *pvBuffer, uint32_t u32Size) +{ + PSHFLSTRING pString = NULL; + const uint32_t u32HeaderSize = SHFLSTRING_HEADER_SIZE; + + /* + * Check that the buffer size is big enough to hold a zero sized string + * and is not too big to fit into 16 bit variables. + */ + if (u32Size >= u32HeaderSize && u32Size - u32HeaderSize <= 0xFFFF) + { + pString = (PSHFLSTRING)pvBuffer; + pString->u16Size = (uint16_t)(u32Size - u32HeaderSize); + pString->u16Length = 0; + if (pString->u16Size >= sizeof(pString->String.ucs2[0])) + pString->String.ucs2[0] = 0; + else if (pString->u16Size >= sizeof(pString->String.utf8[0])) + pString->String.utf8[0] = 0; + } + + return pString; +} + +/** + * Helper for copying one string into another. + * + * @returns IPRT status code. + * @retval VERR_BUFFER_OVERFLOW and pDst->u16Length set to source length. + * @param pDst The destination string. + * @param pSrc The source string. + * @param cbTerm The size of the string terminator. + */ +DECLINLINE(int) ShflStringCopy(PSHFLSTRING pDst, PCSHFLSTRING pSrc, size_t cbTerm) +{ + int rc = VINF_SUCCESS; + if (pDst->u16Size >= pSrc->u16Length + cbTerm) + { + memcpy(&pDst->String, &pSrc->String, pSrc->u16Length); + switch (cbTerm) + { + default: + case 2: pDst->String.ach[pSrc->u16Length + 1] = '\0'; RT_FALL_THROUGH(); + case 1: pDst->String.ach[pSrc->u16Length + 0] = '\0'; break; + case 0: break; + } + } + else + rc = VERR_BUFFER_OVERFLOW; + pDst->u16Length = pSrc->u16Length; + return rc; +} + +#if defined(IN_RING3) \ + || (defined(IN_RING0) && defined(RT_OS_DARWIN)) + +/** + * Duplicates a string using RTMemAlloc as allocator. + * + * @returns Copy, NULL if out of memory. + * @param pSrc The source string. + */ +DECLINLINE(PSHFLSTRING) ShflStringDup(PCSHFLSTRING pSrc) +{ + PSHFLSTRING pDst = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + pSrc->u16Size); + if (pDst) + { + pDst->u16Length = pSrc->u16Length; + pDst->u16Size = pSrc->u16Size; + memcpy(&pDst->String, &pSrc->String, pSrc->u16Size); + } + return pDst; +} + +/** + * Duplicates a UTF-16 string using RTMemAlloc as allocator. + * + * The returned string will be using UTF-16 encoding too. + * + * @returns Pointer to copy on success - pass to RTMemFree to free. + * NULL if out of memory. + * @param pwszSrc The source string. Encoding is not checked. + */ +DECLINLINE(PSHFLSTRING) ShflStringDupUtf16(PCRTUTF16 pwszSrc) +{ + size_t cwcSrc = RTUtf16Len(pwszSrc); + if (cwcSrc < UINT16_MAX / sizeof(RTUTF16)) + { + PSHFLSTRING pDst = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + (cwcSrc + 1) * sizeof(RTUTF16)); + if (pDst) + { + pDst->u16Length = (uint16_t)(cwcSrc * sizeof(RTUTF16)); + pDst->u16Size = (uint16_t)((cwcSrc + 1) * sizeof(RTUTF16)); + memcpy(&pDst->String, pwszSrc, (cwcSrc + 1) * sizeof(RTUTF16)); + return pDst; + } + } + AssertFailed(); + return NULL; +} + +/** + * Duplicates a UTF-8 string using RTMemAlloc as allocator. + * + * The returned string will be using UTF-8 encoding too. + * + * @returns Pointer to copy on success - pass to RTMemFree to free. + * NULL if out of memory. + * @param pszSrc The source string. Encoding is not checked. + */ +DECLINLINE(PSHFLSTRING) ShflStringDupUtf8(const char *pszSrc) +{ + size_t cchSrc = strlen(pszSrc); + if (cchSrc < UINT16_MAX) + { + PSHFLSTRING pDst = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + cchSrc + 1); + if (pDst) + { + pDst->u16Length = (uint16_t)cchSrc; + pDst->u16Size = (uint16_t)(cchSrc + 1); + memcpy(&pDst->String, pszSrc, cchSrc + 1); + return pDst; + } + } + AssertFailed(); + return NULL; +} + +/** + * Creates a UTF-16 duplicate of the UTF-8 string @a pszSrc using RTMemAlloc as + * allocator. + * + * @returns Pointer to copy on success - pass to RTMemFree to free. + * NULL if out of memory or invalid UTF-8 encoding. + * @param pszSrc The source string. + */ +DECLINLINE(PSHFLSTRING) ShflStringDupUtf8AsUtf16(const char *pszSrc) +{ + size_t cwcConversion = 0; + int rc = RTStrCalcUtf16LenEx(pszSrc, RTSTR_MAX, &cwcConversion); + if ( RT_SUCCESS(rc) + && cwcConversion < UINT16_MAX / sizeof(RTUTF16)) + { + PSHFLSTRING pDst = (PSHFLSTRING)RTMemAlloc(SHFLSTRING_HEADER_SIZE + (cwcConversion + 1) * sizeof(RTUTF16)); + if (pDst) + { + PRTUTF16 pwszDst = pDst->String.ucs2; + pDst->u16Size = (uint16_t)((cwcConversion + 1) * sizeof(RTUTF16)); + rc = RTStrToUtf16Ex(pszSrc, RTSTR_MAX, &pwszDst, cwcConversion + 1, &cwcConversion); + AssertRC(rc); + if (RT_SUCCESS(rc)) + { + pDst->u16Length = (uint16_t)(cwcConversion * sizeof(RTUTF16)); + return pDst; + } + RTMemFree(pDst); + } + } + AssertMsgFailed(("rc=%Rrc cwcConversion=%#x\n", rc, cwcConversion)); + return NULL; +} + +/** + * Copies a UTF-8 string to a buffer as UTF-16. + * + * @returns IPRT status code. + * @param pDst The destination buffer. + * @param pszSrc The source string. + * @param cchSrc The source string length, or RTSTR_MAX. + */ +DECLINLINE(int) ShflStringCopyUtf8AsUtf16(PSHFLSTRING pDst, const char *pszSrc, size_t cchSrc) +{ + int rc; + size_t cwcDst = 0; + if (pDst->u16Size >= sizeof(RTUTF16)) + { + PRTUTF16 pwszDst = pDst->String.utf16; + rc = RTStrToUtf16Ex(pszSrc, cchSrc, &pwszDst, pDst->u16Size / sizeof(RTUTF16), &cwcDst); + } + else + { + RTStrCalcUtf16LenEx(pszSrc, cchSrc, &cwcDst); + rc = VERR_BUFFER_OVERFLOW; + } + pDst->u16Length = (uint16_t)(cwcDst * sizeof(RTUTF16)); + return rc != VERR_BUFFER_OVERFLOW || cwcDst < UINT16_MAX / sizeof(RTUTF16) ? rc : VERR_TOO_MUCH_DATA; +} + +/** + * Copies a UTF-8 string buffer to another buffer as UTF-16 + * + * @returns IPRT status code. + * @param pDst The destination buffer (UTF-16). + * @param pSrc The source buffer (UTF-8). + */ +DECLINLINE(int) ShflStringCopyUtf8BufAsUtf16(PSHFLSTRING pDst, PCSHFLSTRING pSrc) +{ + return ShflStringCopyUtf8AsUtf16(pDst, pSrc->String.ach, pSrc->u16Length); +} + +/** + * Copies a UTF-16 string to a buffer as UTF-8 + * + * @returns IPRT status code. + * @param pDst The destination buffer. + * @param pwszSrc The source string. + * @param cwcSrc The source string length, or RTSTR_MAX. + */ +DECLINLINE(int) ShflStringCopyUtf16AsUtf8(PSHFLSTRING pDst, PCRTUTF16 pwszSrc, size_t cwcSrc) +{ + int rc; + size_t cchDst = 0; + if (pDst->u16Size > 0) + { + char *pszDst = pDst->String.ach; + rc = RTUtf16ToUtf8Ex(pwszSrc, cwcSrc, &pszDst, pDst->u16Size, &cchDst); + } + else + { + RTUtf16CalcUtf8LenEx(pwszSrc, cwcSrc, &cchDst); + rc = VERR_BUFFER_OVERFLOW; + } + pDst->u16Length = (uint16_t)cchDst; + return rc != VERR_BUFFER_OVERFLOW || cchDst < UINT16_MAX ? rc : VERR_TOO_MUCH_DATA; +} + +/** + * Copies a UTF-16 string buffer to another buffer as UTF-8 + * + * @returns IPRT status code. + * @param pDst The destination buffer (UTF-8). + * @param pSrc The source buffer (UTF-16). + */ +DECLINLINE(int) ShflStringCopyUtf16BufAsUtf8(PSHFLSTRING pDst, PCSHFLSTRING pSrc) +{ + return ShflStringCopyUtf16AsUtf8(pDst, pSrc->String.utf16, pSrc->u16Length / sizeof(RTUTF16)); +} + +#endif /* IN_RING3 */ + +/** + * Validates a HGCM string output parameter. + * + * @returns true if valid, false if not. + * + * @param pString The string buffer pointer. + * @param cbBuf The buffer size from the parameter. + */ +DECLINLINE(bool) ShflStringIsValidOut(PCSHFLSTRING pString, uint32_t cbBuf) +{ + if (RT_LIKELY(cbBuf > RT_UOFFSETOF(SHFLSTRING, String))) + if (RT_LIKELY((uint32_t)pString->u16Size + RT_UOFFSETOF(SHFLSTRING, String) <= cbBuf)) + if (RT_LIKELY(pString->u16Length < pString->u16Size)) + return true; + return false; +} + +/** + * Validates a HGCM string input parameter. + * + * @returns true if valid, false if not. + * + * @param pString The string buffer pointer. + * @param cbBuf The buffer size from the parameter. + * @param fUtf8Not16 Set if UTF-8 encoding, clear if UTF-16 encoding. + */ +DECLINLINE(bool) ShflStringIsValidIn(PCSHFLSTRING pString, uint32_t cbBuf, bool fUtf8Not16) +{ + int rc; + if (RT_LIKELY(cbBuf > RT_UOFFSETOF(SHFLSTRING, String))) + { + if (RT_LIKELY((uint32_t)pString->u16Size + RT_UOFFSETOF(SHFLSTRING, String) <= cbBuf)) + { + if (fUtf8Not16) + { + /* UTF-8: */ + if (RT_LIKELY(pString->u16Length < pString->u16Size)) + { + rc = RTStrValidateEncodingEx((const char *)&pString->String.utf8[0], pString->u16Length + 1, + RTSTR_VALIDATE_ENCODING_EXACT_LENGTH | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); + if (RT_SUCCESS(rc)) + return true; + } + } + else + { + /* UTF-16: */ + if (RT_LIKELY(!(pString->u16Length & 1))) + { + if (RT_LIKELY((uint32_t)sizeof(RTUTF16) + pString->u16Length <= pString->u16Size)) + { + rc = RTUtf16ValidateEncodingEx(&pString->String.ucs2[0], pString->u16Length / 2 + 1, + RTSTR_VALIDATE_ENCODING_EXACT_LENGTH + | RTSTR_VALIDATE_ENCODING_ZERO_TERMINATED); + if (RT_SUCCESS(rc)) + return true; + } + } + } + } + } + return false; +} + +/** + * Validates an optional HGCM string input parameter. + * + * @returns true if valid, false if not. + * + * @param pString The string buffer pointer. Can be NULL. + * @param cbBuf The buffer size from the parameter. + * @param fUtf8Not16 Set if UTF-8 encoding, clear if UTF-16 encoding. + */ +DECLINLINE(bool) ShflStringIsValidOrNullIn(PCSHFLSTRING pString, uint32_t cbBuf, bool fUtf8Not16) +{ + if (pString) + return ShflStringIsValidIn(pString, cbBuf, fUtf8Not16); + if (RT_LIKELY(cbBuf == 0)) + return true; + return false; +} + +/** Macro for passing as string as a HGCM parmeter (pointer) */ +#define SHFLSTRING_TO_HGMC_PARAM(a_pParam, a_pString) \ + do { \ + (a_pParam)->type = VBOX_HGCM_SVC_PARM_PTR; \ + (a_pParam)->u.pointer.addr = (a_pString); \ + (a_pParam)->u.pointer.size = ShflStringSizeOfBuffer(a_pString); \ + } while (0) + +/** @} */ + + +/** + * The available additional information in a SHFLFSOBJATTR object. + */ +typedef enum SHFLFSOBJATTRADD +{ + /** No additional information is available / requested. */ + SHFLFSOBJATTRADD_NOTHING = 1, + /** The additional unix attributes (SHFLFSOBJATTR::u::Unix) are + * available / requested. */ + SHFLFSOBJATTRADD_UNIX, + /** The additional extended attribute size (SHFLFSOBJATTR::u::EASize) is + * available / requested. */ + SHFLFSOBJATTRADD_EASIZE, + /** The last valid item (inclusive). + * The valid range is SHFLFSOBJATTRADD_NOTHING thru + * SHFLFSOBJATTRADD_LAST. */ + SHFLFSOBJATTRADD_LAST = SHFLFSOBJATTRADD_EASIZE, + + /** The usual 32-bit hack. */ + SHFLFSOBJATTRADD_32BIT_SIZE_HACK = 0x7fffffff +} SHFLFSOBJATTRADD; + + +/* Assert sizes of the IRPT types we're using below. */ +AssertCompileSize(RTFMODE, 4); +AssertCompileSize(RTFOFF, 8); +AssertCompileSize(RTINODE, 8); +AssertCompileSize(RTTIMESPEC, 8); +AssertCompileSize(RTDEV, 4); +AssertCompileSize(RTUID, 4); + +/** + * Shared folder filesystem object attributes. + */ +#pragma pack(1) +typedef struct SHFLFSOBJATTR +{ + /** Mode flags (st_mode). RTFS_UNIX_*, RTFS_TYPE_*, and RTFS_DOS_*. + * @remarks We depend on a number of RTFS_ defines to remain unchanged. + * Fortuntately, these are depending on windows, dos and unix + * standard values, so this shouldn't be much of a pain. */ + RTFMODE fMode; + + /** The additional attributes available. */ + SHFLFSOBJATTRADD enmAdditional; + + /** + * Additional attributes. + * + * Unless explicitly specified to an API, the API can provide additional + * data as it is provided by the underlying OS. + */ + union SHFLFSOBJATTRUNION + { + /** Additional Unix Attributes + * These are available when SHFLFSOBJATTRADD is set in fUnix. + */ + struct SHFLFSOBJATTRUNIX + { + /** The user owning the filesystem object (st_uid). + * This field is ~0U if not supported. */ + RTUID uid; + + /** The group the filesystem object is assigned (st_gid). + * This field is ~0U if not supported. */ + RTGID gid; + + /** Number of hard links to this filesystem object (st_nlink). + * This field is 1 if the filesystem doesn't support hardlinking or + * the information isn't available. + */ + uint32_t cHardlinks; + + /** The device number of the device which this filesystem object resides on (st_dev). + * This field is 0 if this information is not available. */ + RTDEV INodeIdDevice; + + /** The unique identifier (within the filesystem) of this filesystem object (st_ino). + * Together with INodeIdDevice, this field can be used as a OS wide unique id + * when both their values are not 0. + * This field is 0 if the information is not available. */ + RTINODE INodeId; + + /** User flags (st_flags). + * This field is 0 if this information is not available. */ + uint32_t fFlags; + + /** The current generation number (st_gen). + * This field is 0 if this information is not available. */ + uint32_t GenerationId; + + /** The device number of a character or block device type object (st_rdev). + * This field is 0 if the file isn't of a character or block device type and + * when the OS doesn't subscribe to the major+minor device idenfication scheme. */ + RTDEV Device; + } Unix; + + /** + * Extended attribute size. + */ + struct SHFLFSOBJATTREASIZE + { + /** Size of EAs. */ + RTFOFF cb; + } EASize; + } u; +} SHFLFSOBJATTR; +#pragma pack() +AssertCompileSize(SHFLFSOBJATTR, 44); +/** Pointer to a shared folder filesystem object attributes structure. */ +typedef SHFLFSOBJATTR *PSHFLFSOBJATTR; +/** Pointer to a const shared folder filesystem object attributes structure. */ +typedef const SHFLFSOBJATTR *PCSHFLFSOBJATTR; + + +/** + * Filesystem object information structure. + */ +#pragma pack(1) +typedef struct SHFLFSOBJINFO +{ + /** Logical size (st_size). + * For normal files this is the size of the file. + * For symbolic links, this is the length of the path name contained + * in the symbolic link. + * For other objects this fields needs to be specified. + */ + RTFOFF cbObject; + + /** Disk allocation size (st_blocks * DEV_BSIZE). */ + RTFOFF cbAllocated; + + /** Time of last access (st_atime). + * @remarks Here (and other places) we depend on the IPRT timespec to + * remain unchanged. */ + RTTIMESPEC AccessTime; + + /** Time of last data modification (st_mtime). */ + RTTIMESPEC ModificationTime; + + /** Time of last status change (st_ctime). + * If not available this is set to ModificationTime. + */ + RTTIMESPEC ChangeTime; + + /** Time of file birth (st_birthtime). + * If not available this is set to ChangeTime. + */ + RTTIMESPEC BirthTime; + + /** Attributes. */ + SHFLFSOBJATTR Attr; + +} SHFLFSOBJINFO; +#pragma pack() +AssertCompileSize(SHFLFSOBJINFO, 92); +/** Pointer to a shared folder filesystem object information structure. */ +typedef SHFLFSOBJINFO *PSHFLFSOBJINFO; +/** Pointer to a const shared folder filesystem object information + * structure. */ +typedef const SHFLFSOBJINFO *PCSHFLFSOBJINFO; + + +/** + * Copy file system objinfo from IPRT to shared folder format. + * + * @param pDst The shared folder structure. + * @param pSrc The IPRT structure. + */ +DECLINLINE(void) vbfsCopyFsObjInfoFromIprt(PSHFLFSOBJINFO pDst, PCRTFSOBJINFO pSrc) +{ + pDst->cbObject = pSrc->cbObject; + pDst->cbAllocated = pSrc->cbAllocated; + pDst->AccessTime = pSrc->AccessTime; + pDst->ModificationTime = pSrc->ModificationTime; + pDst->ChangeTime = pSrc->ChangeTime; + pDst->BirthTime = pSrc->BirthTime; + pDst->Attr.fMode = pSrc->Attr.fMode; + /* Clear bits which we don't pass through for security reasons. */ + pDst->Attr.fMode &= ~(RTFS_UNIX_ISUID | RTFS_UNIX_ISGID | RTFS_UNIX_ISTXT); + RT_ZERO(pDst->Attr.u); + switch (pSrc->Attr.enmAdditional) + { + default: + case RTFSOBJATTRADD_NOTHING: + pDst->Attr.enmAdditional = SHFLFSOBJATTRADD_NOTHING; + break; + + case RTFSOBJATTRADD_UNIX: + pDst->Attr.enmAdditional = SHFLFSOBJATTRADD_UNIX; + pDst->Attr.u.Unix.uid = pSrc->Attr.u.Unix.uid; + pDst->Attr.u.Unix.gid = pSrc->Attr.u.Unix.gid; + pDst->Attr.u.Unix.cHardlinks = pSrc->Attr.u.Unix.cHardlinks; + pDst->Attr.u.Unix.INodeIdDevice = pSrc->Attr.u.Unix.INodeIdDevice; + pDst->Attr.u.Unix.INodeId = pSrc->Attr.u.Unix.INodeId; + pDst->Attr.u.Unix.fFlags = pSrc->Attr.u.Unix.fFlags; + pDst->Attr.u.Unix.GenerationId = pSrc->Attr.u.Unix.GenerationId; + pDst->Attr.u.Unix.Device = pSrc->Attr.u.Unix.Device; + break; + + case RTFSOBJATTRADD_EASIZE: + pDst->Attr.enmAdditional = SHFLFSOBJATTRADD_EASIZE; + pDst->Attr.u.EASize.cb = pSrc->Attr.u.EASize.cb; + break; + } +} + + +/** Result of an open/create request. + * Along with handle value the result code + * identifies what has happened while + * trying to open the object. + */ +typedef enum _SHFLCREATERESULT +{ + SHFL_NO_RESULT, + /** Specified path does not exist. */ + SHFL_PATH_NOT_FOUND, + /** Path to file exists, but the last component does not. */ + SHFL_FILE_NOT_FOUND, + /** File already exists and either has been opened or not. */ + SHFL_FILE_EXISTS, + /** New file was created. */ + SHFL_FILE_CREATED, + /** Existing file was replaced or overwritten. */ + SHFL_FILE_REPLACED, + /** Blow the type up to 32-bit. */ + SHFL_32BIT_HACK = 0x7fffffff +} SHFLCREATERESULT; +AssertCompile(SHFL_NO_RESULT == 0); +AssertCompileSize(SHFLCREATERESULT, 4); + + +/** @name Open/create flags. + * @{ + */ + +/** No flags. Initialization value. */ +#define SHFL_CF_NONE (0x00000000) + +/** Lookup only the object, do not return a handle. All other flags are ignored. */ +#define SHFL_CF_LOOKUP (0x00000001) + +/** Open parent directory of specified object. + * Useful for the corresponding Windows FSD flag + * and for opening paths like \\dir\\*.* to search the 'dir'. + * @todo possibly not needed??? + */ +#define SHFL_CF_OPEN_TARGET_DIRECTORY (0x00000002) + +/** Create/open a directory. */ +#define SHFL_CF_DIRECTORY (0x00000004) + +/** Open/create action to do if object exists + * and if the object does not exists. + * REPLACE file means atomically DELETE and CREATE. + * OVERWRITE file means truncating the file to 0 and + * setting new size. + * When opening an existing directory REPLACE and OVERWRITE + * actions are considered invalid, and cause returning + * FILE_EXISTS with NIL handle. + */ +#define SHFL_CF_ACT_MASK_IF_EXISTS (0x000000F0) +#define SHFL_CF_ACT_MASK_IF_NEW (0x00000F00) + +/** What to do if object exists. */ +#define SHFL_CF_ACT_OPEN_IF_EXISTS (0x00000000) +#define SHFL_CF_ACT_FAIL_IF_EXISTS (0x00000010) +#define SHFL_CF_ACT_REPLACE_IF_EXISTS (0x00000020) +#define SHFL_CF_ACT_OVERWRITE_IF_EXISTS (0x00000030) + +/** What to do if object does not exist. */ +#define SHFL_CF_ACT_CREATE_IF_NEW (0x00000000) +#define SHFL_CF_ACT_FAIL_IF_NEW (0x00000100) + +/** Read/write requested access for the object. */ +#define SHFL_CF_ACCESS_MASK_RW (0x00003000) + +/** No access requested. */ +#define SHFL_CF_ACCESS_NONE (0x00000000) +/** Read access requested. */ +#define SHFL_CF_ACCESS_READ (0x00001000) +/** Write access requested. */ +#define SHFL_CF_ACCESS_WRITE (0x00002000) +/** Read/Write access requested. */ +#define SHFL_CF_ACCESS_READWRITE (SHFL_CF_ACCESS_READ | SHFL_CF_ACCESS_WRITE) + +/** Requested share access for the object. */ +#define SHFL_CF_ACCESS_MASK_DENY (0x0000C000) + +/** Allow any access. */ +#define SHFL_CF_ACCESS_DENYNONE (0x00000000) +/** Do not allow read. */ +#define SHFL_CF_ACCESS_DENYREAD (0x00004000) +/** Do not allow write. */ +#define SHFL_CF_ACCESS_DENYWRITE (0x00008000) +/** Do not allow access. */ +#define SHFL_CF_ACCESS_DENYALL (SHFL_CF_ACCESS_DENYREAD | SHFL_CF_ACCESS_DENYWRITE) + +/** Requested access to attributes of the object. */ +#define SHFL_CF_ACCESS_MASK_ATTR (0x00030000) + +/** No access requested. */ +#define SHFL_CF_ACCESS_ATTR_NONE (0x00000000) +/** Read access requested. */ +#define SHFL_CF_ACCESS_ATTR_READ (0x00010000) +/** Write access requested. */ +#define SHFL_CF_ACCESS_ATTR_WRITE (0x00020000) +/** Read/Write access requested. */ +#define SHFL_CF_ACCESS_ATTR_READWRITE (SHFL_CF_ACCESS_ATTR_READ | SHFL_CF_ACCESS_ATTR_WRITE) + +/** The file is opened in append mode. Ignored if SHFL_CF_ACCESS_WRITE is not set. */ +#define SHFL_CF_ACCESS_APPEND (0x00040000) + +/** @} */ + +#pragma pack(1) +typedef struct _SHFLCREATEPARMS +{ + /* Returned handle of opened object. */ + SHFLHANDLE Handle; + + /* Returned result of the operation */ + SHFLCREATERESULT Result; + + /* SHFL_CF_* */ + uint32_t CreateFlags; + + /* Attributes of object to create and + * returned actual attributes of opened/created object. + */ + SHFLFSOBJINFO Info; + +} SHFLCREATEPARMS; +#pragma pack() + +typedef SHFLCREATEPARMS *PSHFLCREATEPARMS; + + +/** @name Shared Folders mappings. + * @{ + */ + +/** The mapping has been added since last query. */ +#define SHFL_MS_NEW (1) +/** The mapping has been deleted since last query. */ +#define SHFL_MS_DELETED (2) + +typedef struct _SHFLMAPPING +{ + /** Mapping status. + * @note Currently always set to SHFL_MS_NEW. */ + uint32_t u32Status; + /** Root handle. */ + SHFLROOT root; +} SHFLMAPPING; +/** Pointer to a SHFLMAPPING structure. */ +typedef SHFLMAPPING *PSHFLMAPPING; + +/** @} */ + + +/** @name Shared Folder directory information + * @{ + */ + +typedef struct _SHFLDIRINFO +{ + /** Full information about the object. */ + SHFLFSOBJINFO Info; + /** The length of the short field (number of RTUTF16 chars). + * It is 16-bit for reasons of alignment. */ + uint16_t cucShortName; + /** The short name for 8.3 compatibility. + * Empty string if not available. + */ + RTUTF16 uszShortName[14]; + /** @todo malc, a description, please. */ + SHFLSTRING name; +} SHFLDIRINFO, *PSHFLDIRINFO; + + +/** + * Shared folder filesystem properties. + */ +typedef struct SHFLFSPROPERTIES +{ + /** The maximum size of a filesystem object name. + * This does not include the '\\0'. */ + uint32_t cbMaxComponent; + + /** True if the filesystem is remote. + * False if the filesystem is local. */ + bool fRemote; + + /** True if the filesystem is case sensitive. + * False if the filesystem is case insensitive. */ + bool fCaseSensitive; + + /** True if the filesystem is mounted read only. + * False if the filesystem is mounted read write. */ + bool fReadOnly; + + /** True if the filesystem can encode unicode object names. + * False if it can't. */ + bool fSupportsUnicode; + + /** True if the filesystem is compresses. + * False if it isn't or we don't know. */ + bool fCompressed; + + /** True if the filesystem compresses of individual files. + * False if it doesn't or we don't know. */ + bool fFileCompression; + + /** @todo more? */ +} SHFLFSPROPERTIES; +AssertCompileSize(SHFLFSPROPERTIES, 12); +/** Pointer to a shared folder filesystem properties structure. */ +typedef SHFLFSPROPERTIES *PSHFLFSPROPERTIES; +/** Pointer to a const shared folder filesystem properties structure. */ +typedef SHFLFSPROPERTIES const *PCSHFLFSPROPERTIES; + + +/** + * Copy file system properties from IPRT to shared folder format. + * + * @param pDst The shared folder structure. + * @param pSrc The IPRT structure. + */ +DECLINLINE(void) vbfsCopyFsPropertiesFromIprt(PSHFLFSPROPERTIES pDst, PCRTFSPROPERTIES pSrc) +{ + RT_ZERO(*pDst); /* zap the implicit padding. */ + pDst->cbMaxComponent = pSrc->cbMaxComponent; + pDst->fRemote = pSrc->fRemote; + pDst->fCaseSensitive = pSrc->fCaseSensitive; + pDst->fReadOnly = pSrc->fReadOnly; + pDst->fSupportsUnicode = pSrc->fSupportsUnicode; + pDst->fCompressed = pSrc->fCompressed; + pDst->fFileCompression = pSrc->fFileCompression; +} + + +typedef struct _SHFLVOLINFO +{ + RTFOFF ullTotalAllocationBytes; + RTFOFF ullAvailableAllocationBytes; + uint32_t ulBytesPerAllocationUnit; + uint32_t ulBytesPerSector; + uint32_t ulSerial; + SHFLFSPROPERTIES fsProperties; +} SHFLVOLINFO, *PSHFLVOLINFO; + +/** @} */ + + +/** @defgroup grp_vbox_shfl_params Function parameter structures. + * @{ + */ + +/** @name SHFL_FN_QUERY_MAPPINGS + * @{ + */ +/** Validation mask. Needs to be adjusted + * whenever a new SHFL_MF_ flag is added. */ +#define SHFL_MF_MASK (0x00000011) +/** UTF-16 enconded strings. */ +#define SHFL_MF_UCS2 (0x00000000) +/** Guest uses UTF8 strings, if not set then the strings are unicode (UCS2). */ +#define SHFL_MF_UTF8 (0x00000001) +/** Just handle the auto-mounted folders. */ +#define SHFL_MF_AUTOMOUNT (0x00000010) + +/** Parameters structure. */ +typedef struct _VBoxSFQueryMappings +{ + VBGLIOCHGCMCALL callInfo; + + /** 32bit, in: + * Flags describing various client needs. + */ + HGCMFunctionParameter flags; + + /** 32bit, in/out: + * Number of mappings the client expects. + * This is the number of elements in the + * mappings array. + */ + HGCMFunctionParameter numberOfMappings; + + /** pointer, in/out: + * Points to array of SHFLMAPPING structures. + */ + HGCMFunctionParameter mappings; + +} VBoxSFQueryMappings; + +/** Number of parameters */ +#define SHFL_CPARMS_QUERY_MAPPINGS (3) +/** @} */ + + +/** @name SHFL_FN_QUERY_MAP_NAME + * @{ + */ + +/** Parameters structure. */ +typedef struct _VBoxSFQueryMapName +{ + VBGLIOCHGCMCALL callInfo; + + /** 32bit, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in/out: + * Points to SHFLSTRING buffer. + */ + HGCMFunctionParameter name; + +} VBoxSFQueryMapName; + +/** Number of parameters */ +#define SHFL_CPARMS_QUERY_MAP_NAME (2) +/** @} */ + + +/** @name SHFL_FN_MAP_FOLDER_OLD + * @{ + */ + +/** Parameters structure. */ +typedef struct _VBoxSFMapFolder_Old +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: + * Points to SHFLSTRING buffer. + */ + HGCMFunctionParameter path; + + /** pointer, out: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: RTUTF16 + * Path delimiter + */ + HGCMFunctionParameter delimiter; + +} VBoxSFMapFolder_Old; + +/** Number of parameters */ +#define SHFL_CPARMS_MAP_FOLDER_OLD (3) +/** @} */ + + +/** @name SHFL_FN_MAP_FOLDER + * @{ + */ + +/** SHFL_FN_MAP_FOLDER parameters. */ +typedef struct VBoxSFParmMapFolder +{ + /** pointer, in: SHFLSTRING with the name of the folder to map. */ + HGCMFunctionParameter pStrName; + /** value32, out: The root ID (SHFLROOT) of the mapping. */ + HGCMFunctionParameter id32Root; + /** value32, in: Path delimiter code point. */ + HGCMFunctionParameter uc32Delimiter; + /** value32, in: case senstive flag */ + HGCMFunctionParameter fCaseSensitive; +} VBoxSFParmMapFolder; + +/** Parameters structure. */ +typedef struct _VBoxSFMapFolder +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: + * Points to SHFLSTRING buffer. + */ + HGCMFunctionParameter path; + + /** pointer, out: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: RTUTF16 + * Path delimiter + */ + HGCMFunctionParameter delimiter; + + /** pointer, in: SHFLROOT + * Case senstive flag + */ + HGCMFunctionParameter fCaseSensitive; + +} VBoxSFMapFolder; + +/** Number of parameters */ +#define SHFL_CPARMS_MAP_FOLDER (4) +/** @} */ + + +/** @name SHFL_FN_UNMAP_FOLDER + * @{ + */ + +/** SHFL_FN_UNMAP_FOLDER parameters. */ +typedef struct VBoxSFParmUnmapFolder +{ + /** value32, in: SHFLROOT of the mapping to unmap */ + HGCMFunctionParameter id32Root; +} VBoxSFParmUnmapFolder; + +/** Parameters structure. */ +typedef struct _VBoxSFUnmapFolder +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + +} VBoxSFUnmapFolder; + +/** Number of parameters */ +#define SHFL_CPARMS_UNMAP_FOLDER (1) +/** @} */ + + +/** @name SHFL_FN_CREATE + * @{ + */ + +/** SHFL_FN_CREATE parameters. */ +typedef struct VBoxSFParmCreate +{ + /** value32, in: SHFLROOT + * Root handle of the mapping which name is queried. */ + HGCMFunctionParameter id32Root; + /** pointer, in: Points to SHFLSTRING buffer. */ + HGCMFunctionParameter pStrPath; + /** pointer, in/out: Points to SHFLCREATEPARMS buffer. */ + HGCMFunctionParameter pCreateParms; +} VBoxSFParmCreate; + +/** Parameters structure. */ +typedef struct _VBoxSFCreate +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: + * Points to SHFLSTRING buffer. + */ + HGCMFunctionParameter path; + + /** pointer, in/out: + * Points to SHFLCREATEPARMS buffer. + */ + HGCMFunctionParameter parms; + +} VBoxSFCreate; + +/** Number of parameters */ +#define SHFL_CPARMS_CREATE (3) +/** @} */ + + +/** @name SHFL_FN_CLOSE + * @{ + */ + +/** SHFL_FN_CLOSE parameters. */ +typedef struct VBoxSFParmClose +{ + /** value32, in: SHFLROOT of the mapping with the handle. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of object to close. */ + HGCMFunctionParameter u64Handle; +} VBoxSFParmClose; + +/** Parameters structure. */ +typedef struct _VBoxSFClose +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + + /** value64, in: + * SHFLHANDLE of object to close. + */ + HGCMFunctionParameter handle; + +} VBoxSFClose; + +/** Number of parameters */ +#define SHFL_CPARMS_CLOSE (2) +/** @} */ + + +/** @name SHFL_FN_READ + * @{ + */ + +/** SHFL_FN_READ parameters. */ +typedef struct VBoxSFParmRead +{ + /** value32, in: SHFLROOT of the mapping with the handle. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of object to read from . */ + HGCMFunctionParameter u64Handle; + /** value64, in: Offset to start reading from. */ + HGCMFunctionParameter off64Read; + /** value32, in/out: How much to try read / Actually read. */ + HGCMFunctionParameter cb32Read; + /** pointer, out: Buffer to return the data in. */ + HGCMFunctionParameter pBuf; +} VBoxSFParmRead; + +/** Parameters structure. */ +typedef struct _VBoxSFRead +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** value64, in: + * SHFLHANDLE of object to read from. + */ + HGCMFunctionParameter handle; + + /** value64, in: + * Offset to read from. + */ + HGCMFunctionParameter offset; + + /** value64, in/out: + * Bytes to read/How many were read. + */ + HGCMFunctionParameter cb; + + /** pointer, out: + * Buffer to place data to. + */ + HGCMFunctionParameter buffer; + +} VBoxSFRead; + +/** Number of parameters */ +#define SHFL_CPARMS_READ (5) +/** @} */ + + +/** @name SHFL_FN_WRITE + * @{ + */ + +/** SHFL_FN_WRITE parameters. */ +typedef struct VBoxSFParmWrite +{ + /** value32, in: SHFLROOT of the mapping with the handle. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of object to write to. */ + HGCMFunctionParameter u64Handle; + /** value64, in/out: Offset to start writing at / New offset. + * @note The new offset isn't necessarily off + cb for files opened with + * SHFL_CF_ACCESS_APPEND since other parties (host programs, other VMs, + * other computers) could have extended the file since the last time the + * guest got a fresh size statistic. So, this helps the guest avoiding + * a stat call to check the actual size. */ + HGCMFunctionParameter off64Write; + /** value32, in/out: How much to try write / Actually written. */ + HGCMFunctionParameter cb32Write; + /** pointer, out: Buffer to return the data in. */ + HGCMFunctionParameter pBuf; +} VBoxSFParmWrite; + +/** Parameters structure. */ +typedef struct _VBoxSFWrite +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** value64, in: + * SHFLHANDLE of object to write to. + */ + HGCMFunctionParameter handle; + + /** value64, in/out: + * Offset to write to/New offset. + * @note The new offset isn't necessarily off + cb for files opened with + * SHFL_CF_ACCESS_APPEND since other parties (host programs, other VMs, + * other computers) could have extended the file since the last time the + * guest got a fresh size statistic. So, this helps the guest avoiding + * a stat call to check the actual size. + */ + HGCMFunctionParameter offset; + + /** value64, in/out: + * Bytes to write/How many were written. + */ + HGCMFunctionParameter cb; + + /** pointer, in: + * Data to write. + */ + HGCMFunctionParameter buffer; + +} VBoxSFWrite; + +/** Number of parameters */ +#define SHFL_CPARMS_WRITE (5) +/** @} */ + + +/** @name SHFL_FN_LOCK + * @remarks Lock owner is the HGCM client. + * @{ + */ + +/** Lock mode bit mask. */ +#define SHFL_LOCK_MODE_MASK (0x3) +/** Cancel lock on the given range. */ +#define SHFL_LOCK_CANCEL (0x0) +/** Acquire read only lock. Prevent write to the range. */ +#define SHFL_LOCK_SHARED (0x1) +/** Acquire write lock. Prevent both write and read to the range. */ +#define SHFL_LOCK_EXCLUSIVE (0x2) + +/** Do not wait for lock if it can not be acquired at the time. */ +#define SHFL_LOCK_NOWAIT (0x0) +/** Wait and acquire lock. */ +#define SHFL_LOCK_WAIT (0x4) + +/** Lock the specified range. */ +#define SHFL_LOCK_PARTIAL (0x0) +/** Lock entire object. */ +#define SHFL_LOCK_ENTIRE (0x8) + +/** Parameters structure. */ +typedef struct _VBoxSFLock +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** value64, in: + * SHFLHANDLE of object to be locked. + */ + HGCMFunctionParameter handle; + + /** value64, in: + * Starting offset of lock range. + */ + HGCMFunctionParameter offset; + + /** value64, in: + * Length of range. + */ + HGCMFunctionParameter length; + + /** value32, in: + * Lock flags SHFL_LOCK_*. + */ + HGCMFunctionParameter flags; + +} VBoxSFLock; + +/** Number of parameters */ +#define SHFL_CPARMS_LOCK (5) +/** @} */ + + +/** @name SHFL_FN_FLUSH + * @{ + */ + +/** SHFL_FN_FLUSH parameters. */ +typedef struct VBoxSFParmFlush +{ + /** value32, in: SHFLROOT of the mapping with the handle. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of object to flush. */ + HGCMFunctionParameter u64Handle; +} VBoxSFParmFlush; + +/** Parameters structure. */ +typedef struct _VBoxSFFlush +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** value64, in: + * SHFLHANDLE of object to be locked. + */ + HGCMFunctionParameter handle; + +} VBoxSFFlush; + +/** Number of parameters */ +#define SHFL_CPARMS_FLUSH (2) +/** @} */ + + +/** @name SHFL_FN_SET_UTF8 + * @{ */ +/** NUmber of parameters for SHFL_FN_SET_UTF8. */ +#define SHFL_CPARMS_SET_UTF8 (0) +/** @} */ + + +/** @name SHFL_FN_LIST + * @remarks Listing information includes variable length RTDIRENTRY[EX] + * structures. + * @{ + */ + +/** @todo might be necessary for future. */ +#define SHFL_LIST_NONE 0 +#define SHFL_LIST_RETURN_ONE 1 +#define SHFL_LIST_RESTART 2 + +/** SHFL_FN_LIST parameters. */ +typedef struct VBoxSFParmList +{ + /** value32, in: SHFLROOT of the mapping the handle belongs to. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of the directory. */ + HGCMFunctionParameter u64Handle; + /** value32, in: List flags SHFL_LIST_XXX. */ + HGCMFunctionParameter f32Flags; + /** value32, in/out: Input buffer size / Returned bytes count. */ + HGCMFunctionParameter cb32Buffer; + /** pointer, in[optional]: SHFLSTRING filter string (full path). */ + HGCMFunctionParameter pStrFilter; + /** pointer, out: Buffer to return listing information in (SHFLDIRINFO). + * When SHFL_LIST_RETURN_ONE is not specfied, multiple record may be + * returned, deriving the entry size using SHFLDIRINFO::name.u16Size. */ + HGCMFunctionParameter pBuffer; + /** value32, out: Set to 0 if the listing is done, 1 if there are more entries. + * @note Must be set to zero on call as it was declared in/out parameter and + * may be used as such again. */ + HGCMFunctionParameter f32More; + /** value32, out: Number of entries returned. */ + HGCMFunctionParameter c32Entries; +} VBoxSFParmList; + + +/** Parameters structure. */ +typedef struct _VBoxSFList +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** value64, in: + * SHFLHANDLE of object to be listed. + */ + HGCMFunctionParameter handle; + + /** value32, in: + * List flags SHFL_LIST_*. + */ + HGCMFunctionParameter flags; + + /** value32, in/out: + * Bytes to be used for listing information/How many bytes were used. + */ + HGCMFunctionParameter cb; + + /** pointer, in/optional + * Points to SHFLSTRING buffer that specifies a search path. + */ + HGCMFunctionParameter path; + + /** pointer, out: + * Buffer to place listing information to. (SHFLDIRINFO) + */ + HGCMFunctionParameter buffer; + + /** value32, in/out: + * Indicates a key where the listing must be resumed. + * in: 0 means start from begin of object. + * out: 0 means listing completed. + */ + HGCMFunctionParameter resumePoint; + + /** pointer, out: + * Number of files returned + */ + HGCMFunctionParameter cFiles; + +} VBoxSFList; + +/** Number of parameters */ +#define SHFL_CPARMS_LIST (8) +/** @} */ + + +/** @name SHFL_FN_READLINK + * @{ + */ + +/** SHFL_FN_READLINK parameters. */ +typedef struct VBoxSFParmReadLink +{ + /** value32, in: SHFLROOT of the mapping which the symlink is read. */ + HGCMFunctionParameter id32Root; + /** pointer, in: SHFLSTRING full path to the symlink. */ + HGCMFunctionParameter pStrPath; + /** pointer, out: Buffer to place the symlink target into. + * @note Buffer contains UTF-8 characters on success, regardless of the + * UTF-8/UTF-16 setting of the connection. Will be zero terminated. + * + * @todo r=bird: This should've been a string! + * @todo r=bird: There should've been a byte count returned! */ + HGCMFunctionParameter pBuffer; +} VBoxSFParmReadLink; + +/** Parameters structure. */ +typedef struct _VBoxSFReadLink +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: + * Points to SHFLSTRING buffer. + */ + HGCMFunctionParameter path; + + /** pointer, out: + * Buffer to place data to. + * @note Buffer contains UTF-8 characters on success, regardless of the + * UTF-8/UTF-16 setting of the connection. Will be zero terminated. + */ + HGCMFunctionParameter buffer; + +} VBoxSFReadLink; + +/** Number of parameters */ +#define SHFL_CPARMS_READLINK (3) +/** @} */ + + +/** @name SHFL_FN_INFORMATION + * @{ + */ + +/** Mask of Set/Get bit. */ +#define SHFL_INFO_MODE_MASK (0x1) +/** Get information */ +#define SHFL_INFO_GET (0x0) +/** Set information */ +#define SHFL_INFO_SET (0x1) + +/** Get name of the object. */ +#define SHFL_INFO_NAME (0x2) +/** Set size of object (extend/trucate); only applies to file objects */ +#define SHFL_INFO_SIZE (0x4) +/** Get/Set file object info. */ +#define SHFL_INFO_FILE (0x8) +/** Get volume information. */ +#define SHFL_INFO_VOLUME (0x10) + +/** @todo different file info structures */ + +/** SHFL_FN_INFORMATION parameters. */ +typedef struct VBoxSFParmInformation +{ + /** value32, in: SHFLROOT of the mapping the handle belongs to. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of object to be queried/set. */ + HGCMFunctionParameter u64Handle; + /** value32, in: SHFL_INFO_XXX */ + HGCMFunctionParameter f32Flags; + /** value32, in/out: Bytes to be used for information/How many bytes were used. */ + HGCMFunctionParameter cb32; + /** pointer, in/out: Information to be set/get (SHFLFSOBJINFO, SHFLVOLINFO, or SHFLSTRING). + * Do not forget to set the SHFLFSOBJINFO::Attr::enmAdditional for Get operation as well. */ + HGCMFunctionParameter pInfo; +} VBoxSFParmInformation; + + +/** Parameters structure. */ +typedef struct _VBoxSFInformation +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** value64, in: + * SHFLHANDLE of object to be listed. + */ + HGCMFunctionParameter handle; + + /** value32, in: + * SHFL_INFO_* + */ + HGCMFunctionParameter flags; + + /** value32, in/out: + * Bytes to be used for information/How many bytes were used. + */ + HGCMFunctionParameter cb; + + /** pointer, in/out: + * Information to be set/get (SHFLFSOBJINFO or SHFLSTRING). Do not forget + * to set the SHFLFSOBJINFO::Attr::enmAdditional for Get operation as well. + */ + HGCMFunctionParameter info; + +} VBoxSFInformation; + +/** Number of parameters */ +#define SHFL_CPARMS_INFORMATION (5) +/** @} */ + + +/** @name SHFL_FN_REMOVE + * @{ + */ + +#define SHFL_REMOVE_FILE (0x1) +#define SHFL_REMOVE_DIR (0x2) +#define SHFL_REMOVE_SYMLINK (0x4) + +/** SHFL_FN_REMOVE parameters. */ +typedef struct VBoxSFParmRemove +{ + /** value32, in: SHFLROOT of the mapping the path is relative to. */ + HGCMFunctionParameter id32Root; + /** pointer, in: Points to SHFLSTRING buffer. */ + HGCMFunctionParameter pStrPath; + /** value32, in: SHFL_REMOVE_XXX */ + HGCMFunctionParameter f32Flags; +} VBoxSFParmRemove; + +/** Parameters structure. */ +typedef struct _VBoxSFRemove +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: + * Points to SHFLSTRING buffer. + */ + HGCMFunctionParameter path; + + /** value32, in: + * remove flags (file/directory) + */ + HGCMFunctionParameter flags; + +} VBoxSFRemove; + +#define SHFL_CPARMS_REMOVE (3) +/** @} */ + + +/** @name SHFL_FN_CLOSE_AND_REMOVE + * Extends SHFL_FN_REMOVE with a 4th handle parameter that can be nil. + * @{ + */ +/** SHFL_FN_CLOSE_AND_REMOVE parameters. */ +typedef struct VBoxSFParmCloseAndRemove +{ + /** value32, in: SHFLROOT of the mapping the path is relative to. */ + HGCMFunctionParameter id32Root; + /** pointer, in: Points to SHFLSTRING buffer. */ + HGCMFunctionParameter pStrPath; + /** value32, in: SHFL_REMOVE_XXX */ + HGCMFunctionParameter f32Flags; + /** value64, in: SHFLHANDLE to the object to be removed & close, optional. */ + HGCMFunctionParameter u64Handle; +} VBoxSFParmCloseAndRemove; +/** Number of parameters */ +#define SHFL_CPARMS_CLOSE_AND_REMOVE (4) +AssertCompileSize(VBoxSFParmCloseAndRemove, SHFL_CPARMS_CLOSE_AND_REMOVE * sizeof(HGCMFunctionParameter)); +/** @} */ + + +/** @name SHFL_FN_RENAME + * @{ + */ + +#define SHFL_RENAME_FILE (0x1) +#define SHFL_RENAME_DIR (0x2) +#define SHFL_RENAME_REPLACE_IF_EXISTS (0x4) + +/** SHFL_FN_RENAME parameters. */ +typedef struct VBoxSFParmRename +{ + /** value32, in: SHFLROOT of the mapping the paths are relative to. */ + HGCMFunctionParameter id32Root; + /** pointer, in: SHFLSTRING giving the source (old) path. */ + HGCMFunctionParameter pStrSrcPath; + /** pointer, in: SHFLSTRING giving the destination (new) path. */ + HGCMFunctionParameter pStrDstPath; + /** value32, in: SHFL_RENAME_XXX */ + HGCMFunctionParameter f32Flags; +} VBoxSFParmRename; + +/** Parameters structure. */ +typedef struct _VBoxSFRename +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: + * Points to SHFLSTRING src. + */ + HGCMFunctionParameter src; + + /** pointer, in: + * Points to SHFLSTRING dest. + */ + HGCMFunctionParameter dest; + + /** value32, in: + * rename flags (file/directory) + */ + HGCMFunctionParameter flags; + +} VBoxSFRename; + +#define SHFL_CPARMS_RENAME (4) +/** @} */ + + +/** @name SHFL_FN_SYMLINK + * @{ + */ + +/** Parameters structure. */ +typedef struct VBoxSFParmCreateSymlink +{ + /** value32, in: SHFLROOT of the mapping the symlink should be created on. */ + HGCMFunctionParameter id32Root; + /** pointer, in: SHFLSTRING giving the path to the symlink. */ + HGCMFunctionParameter pStrSymlink; + /** pointer, in: SHFLSTRING giving the target. */ + HGCMFunctionParameter pStrTarget; + /** pointer, out: SHFLFSOBJINFO buffer to be filled with info about the created symlink. */ + HGCMFunctionParameter pInfo; +} VBoxSFParmCreateSymlink; + +/** Parameters structure. */ +typedef struct _VBoxSFSymlink +{ + VBGLIOCHGCMCALL callInfo; + + /** pointer, in: SHFLROOT + * Root handle of the mapping which name is queried. + */ + HGCMFunctionParameter root; + + /** pointer, in: + * Points to SHFLSTRING of path for the new symlink. + */ + HGCMFunctionParameter newPath; + + /** pointer, in: + * Points to SHFLSTRING of destination for symlink. + */ + HGCMFunctionParameter oldPath; + + /** pointer, out: + * Information about created symlink. + */ + HGCMFunctionParameter info; + +} VBoxSFSymlink; + +#define SHFL_CPARMS_SYMLINK (4) +/** @} */ + + +/** @name SHFL_FN_SET_SYMLINKS + * @{ */ +/** NUmber of parameters for SHFL_FN_SET_SYMLINKS. */ +#define SHFL_CPARMS_SET_SYMLINKS (0) +/** @} */ + + +/** @name SHFL_FN_QUERY_MAP_INFO + * @{ + */ +/** Query flag: Guest prefers drive letters as mount points. */ +#define SHFL_MIQF_DRIVE_LETTER RT_BIT_64(0) +/** Query flag: Guest prefers paths as mount points. */ +#define SHFL_MIQF_PATH RT_BIT_64(1) + +/** Set if writable. */ +#define SHFL_MIF_WRITABLE RT_BIT_64(0) +/** Indicates that the mapping should be auto-mounted. */ +#define SHFL_MIF_AUTO_MOUNT RT_BIT_64(1) +/** Set if host is case insensitive. */ +#define SHFL_MIF_HOST_ICASE RT_BIT_64(2) +/** Set if guest is case insensitive. */ +#define SHFL_MIF_GUEST_ICASE RT_BIT_64(3) +/** Symbolic link creation is allowed. */ +#define SHFL_MIF_SYMLINK_CREATION RT_BIT_64(4) + +/** Parameters structure. */ +typedef struct VBoxSFQueryMapInfo +{ + /** Common header. */ + VBGLIOCHGCMCALL callInfo; + /** 32-bit, in: SHFLROOT - root handle of the mapping to query. */ + HGCMFunctionParameter root; + /** pointer, in/out: SHFLSTRING buffer for the name. */ + HGCMFunctionParameter name; + /** pointer, in/out: SHFLSTRING buffer for the auto mount point. */ + HGCMFunctionParameter mountPoint; + /** 64-bit, in: SHFL_MIQF_XXX; out: SHFL_MIF_XXX. */ + HGCMFunctionParameter flags; + /** 32-bit, out: Root ID version number - root handle reuse guard. */ + HGCMFunctionParameter rootIdVersion; +} VBoxSFQueryMapInfo; +/** Number of parameters */ +#define SHFL_CPARMS_QUERY_MAP_INFO (5) +/** @} */ + + +/** @name SHFL_FN_WAIT_FOR_MAPPINGS_CHANGES + * + * Returns VINF_SUCCESS on change and VINF_TRY_AGAIN when restored from saved + * state. If the guest makes too many calls (max 64) VERR_OUT_OF_RESOURCES will + * be returned. + * + * @{ + */ +/** Parameters structure. */ +typedef struct VBoxSFWaitForMappingsChanges +{ + /** Common header. */ + VBGLIOCHGCMCALL callInfo; + /** 32-bit, in/out: The mappings configuration version. + * On input the client sets it to the last config it knows about, on return + * it holds the current version. */ + HGCMFunctionParameter version; +} VBoxSFWaitForMappingsChanges; +/** Number of parameters */ +#define SHFL_CPARMS_WAIT_FOR_MAPPINGS_CHANGES (1) +/** @} */ + + +/** @name SHFL_FN_CANCEL_MAPPINGS_CHANGES_WAITS + * @{ + */ +/** Number of parameters */ +#define SHFL_CPARMS_CANCEL_MAPPINGS_CHANGES_WAITS (0) +/** @} */ + + +/** @name SHFL_FN_SET_FILE_SIZE + * @{ + */ +/** SHFL_FN_SET_FILE_SIZE parameters. */ +typedef struct VBoxSFParmSetFileSize +{ + /** value32, in: SHFLROOT of the mapping the handle belongs to. */ + HGCMFunctionParameter id32Root; + /** value64, in: SHFLHANDLE of the file to change the size of. */ + HGCMFunctionParameter u64Handle; + /** value64, in: The new file size. */ + HGCMFunctionParameter cb64NewSize; +} VBoxSFParmSetFileSize; +/** Number of parameters */ +#define SHFL_CPARMS_SET_FILE_SIZE (3) +/** @} */ + + +/** @name SHFL_FN_QUERY_FEATURES + * @{ */ +/** SHFL_FN_QUERY_FEATURES parameters. */ +typedef struct VBoxSFParmQueryFeatures +{ + /** value64, out: Feature flags, SHFL_FEATURE_XXX. */ + HGCMFunctionParameter f64Features; + /** value32, out: The ordinal of the last valid function */ + HGCMFunctionParameter u32LastFunction; +} VBoxSFParmQueryFeatures; +/** Number of parameters for SHFL_FN_QUERY_FEATURES. */ +#define SHFL_CPARMS_QUERY_FEATURES (2) + +/** The write functions updates the file offset upon return. + * This can be helpful for files open in append mode. */ +#define SHFL_FEATURE_WRITE_UPDATES_OFFSET RT_BIT_64(0) +/** @} */ + + +/** @name SHFL_FN_COPY_FILE + * @{ */ +/** SHFL_FN_COPY_FILE parameters. */ +typedef struct VBoxSFParmCopyFile +{ + /** value32, in: SHFLROOT of the mapping the source handle belongs to. */ + HGCMFunctionParameter id32RootSrc; + /** pointer, in: SHFLSTRING giving the source file path. */ + HGCMFunctionParameter pStrPathSrc; + + /** value32, in: SHFLROOT of the mapping the destination handle belongs to. */ + HGCMFunctionParameter id32RootDst; + /** pointer, in: SHFLSTRING giving the destination file path. */ + HGCMFunctionParameter pStrPathDst; + + /** value32, in: Reserved for the future, must be zero. */ + HGCMFunctionParameter f32Flags; +} VBoxSFParmCopyFile; +/** Number of parameters for SHFL_FN_COPY_FILE. */ +#define SHFL_CPARMS_COPY_FILE (5) +/** @} */ + + +/** @name SHFL_FN_COPY_FILE_PART + * @{ */ +/** SHFL_FN_COPY_FILE_PART parameters. */ +typedef struct VBoxSFParmCopyFilePart +{ + /** value32, in: SHFLROOT of the mapping the source handle belongs to. */ + HGCMFunctionParameter id32RootSrc; + /** value64, in: SHFLHANDLE of the source file. */ + HGCMFunctionParameter u64HandleSrc; + /** value64, in: The source file offset. */ + HGCMFunctionParameter off64Src; + + /** value32, in: SHFLROOT of the mapping the destination handle belongs to. */ + HGCMFunctionParameter id32RootDst; + /** value64, in: SHFLHANDLE of the destination file. */ + HGCMFunctionParameter u64HandleDst; + /** value64, in: The destination file offset. */ + HGCMFunctionParameter off64Dst; + + /** value64, in/out: The number of bytes to copy on input / bytes actually copied. */ + HGCMFunctionParameter cb64ToCopy; + /** value32, in: Reserved for the future, must be zero. */ + HGCMFunctionParameter f32Flags; +} VBoxSFParmCopyFilePart; +/** Number of parameters for SHFL_FN_COPY_FILE_PART. */ +#define SHFL_CPARMS_COPY_FILE_PART (8) +/** @} */ + + +/** @name SHFL_FN_SET_ERROR_STYLE + * @{ */ +/** The defined error styles. */ +typedef enum SHFLERRORSTYLE +{ + kShflErrorStyle_Invalid = 0, + kShflErrorStyle_Windows, + kShflErrorStyle_Linux, + kShflErrorStyle_End, + kShflErrorStyle_32BitHack = 0x7fffffff +} SHFLERRORSTYLE; +/** The native error style. */ +#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2) +# define SHFLERRORSTYLE_NATIVE kShflErrorStyle_Windows +#else +# define SHFLERRORSTYLE_NATIVE kShflErrorStyle_Linux +#endif + +/** SHFL_FN_SET_ERROR_STYLE parameters. */ +typedef struct VBoxSFParmSetErrorStyle +{ + /** value32, in: The style, SHFLERRORSTYLE. */ + HGCMFunctionParameter u32Style; + /** value32, in: Reserved for the future, must be zero. */ + HGCMFunctionParameter u32Reserved; +} VBoxSFParmSetErrorStyle; +/** Number of parameters for SHFL_FN_SET_ERROR_STYLE. */ +#define SHFL_CPARMS_SET_ERROR_STYLE (2) +/** @} */ + + +/** @name SHFL_FN_ADD_MAPPING + * @note Host call, no guest structure is used. + * @{ + */ + +/** mapping is writable */ +#define SHFL_ADD_MAPPING_F_WRITABLE (RT_BIT_32(0)) +/** mapping is automounted by the guest */ +#define SHFL_ADD_MAPPING_F_AUTOMOUNT (RT_BIT_32(1)) +/** allow the guest to create symlinks */ +#define SHFL_ADD_MAPPING_F_CREATE_SYMLINKS (RT_BIT_32(2)) +/** mapping is actually missing on the host */ +#define SHFL_ADD_MAPPING_F_MISSING (RT_BIT_32(3)) + +#define SHFL_CPARMS_ADD_MAPPING (4) +/** @} */ + + +/** @name SHFL_FN_REMOVE_MAPPING + * @note Host call, no guest structure is used. + * @{ + */ + +#define SHFL_CPARMS_REMOVE_MAPPING (1) +/** @} */ + + +/** @name SHFL_FN_SET_STATUS_LED + * @note Host call, no guest structure is used. + * @{ + */ + +#define SHFL_CPARMS_SET_STATUS_LED (1) +/** @} */ + + +/** @} */ +/** @} */ + +#endif /* !VBOX_INCLUDED_shflsvc_h */ + diff --git a/include/VBox/sup.h b/include/VBox/sup.h new file mode 100644 index 00000000..258134fa --- /dev/null +++ b/include/VBox/sup.h @@ -0,0 +1,2832 @@ +/** @file + * SUP - Support Library. (HDrv) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_sup_h +#define VBOX_INCLUDED_sup_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# include +#elif defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM64) +# include +#endif + +RT_C_DECLS_BEGIN + +struct VTGOBJHDR; +struct VTGPROBELOC; + + +/** @defgroup grp_sup The Support Library API + * @{ + */ + +/** + * Physical page descriptor. + */ +#pragma pack(4) /* space is more important. */ +typedef struct SUPPAGE +{ + /** Physical memory address. */ + RTHCPHYS Phys; + /** Reserved entry for internal use by the caller. */ + RTHCUINTPTR uReserved; +} SUPPAGE; +#pragma pack() +/** Pointer to a page descriptor. */ +typedef SUPPAGE *PSUPPAGE; +/** Pointer to a const page descriptor. */ +typedef const SUPPAGE *PCSUPPAGE; + +/** + * The paging mode. + * + * @remarks Users are making assumptions about the order here! + */ +typedef enum SUPPAGINGMODE +{ + /** The usual invalid entry. + * This is returned by SUPR3GetPagingMode() */ + SUPPAGINGMODE_INVALID = 0, + /** Normal 32-bit paging, no global pages */ + SUPPAGINGMODE_32_BIT, + /** Normal 32-bit paging with global pages. */ + SUPPAGINGMODE_32_BIT_GLOBAL, + /** PAE mode, no global pages, no NX. */ + SUPPAGINGMODE_PAE, + /** PAE mode with global pages. */ + SUPPAGINGMODE_PAE_GLOBAL, + /** PAE mode with NX, no global pages. */ + SUPPAGINGMODE_PAE_NX, + /** PAE mode with global pages and NX. */ + SUPPAGINGMODE_PAE_GLOBAL_NX, + /** AMD64 mode, no global pages. */ + SUPPAGINGMODE_AMD64, + /** AMD64 mode with global pages, no NX. */ + SUPPAGINGMODE_AMD64_GLOBAL, + /** AMD64 mode with NX, no global pages. */ + SUPPAGINGMODE_AMD64_NX, + /** AMD64 mode with global pages and NX. */ + SUPPAGINGMODE_AMD64_GLOBAL_NX +} SUPPAGINGMODE; + + +/** @name Flags returned by SUPR0GetKernelFeatures(). + * @{ + */ +/** GDT is read-only. */ +#define SUPKERNELFEATURES_GDT_READ_ONLY RT_BIT(0) +/** SMAP is possibly enabled. */ +#define SUPKERNELFEATURES_SMAP RT_BIT(1) +/** GDT is read-only but the writable GDT can be fetched by SUPR0GetCurrentGdtRw(). */ +#define SUPKERNELFEATURES_GDT_NEED_WRITABLE RT_BIT(2) +/** @} */ + +/** + * An VT-x control MSR. + * @sa VMXCTLSMSR. + */ +typedef union SUPVMXCTLSMSR +{ + uint64_t u; + struct + { + /** Bits set here _must_ be set in the corresponding VM-execution controls. */ + uint32_t allowed0; + /** Bits cleared here _must_ be cleared in the corresponding VM-execution controls. */ + uint32_t allowed1; + } n; +} SUPVMXCTLSMSR; +AssertCompileSize(SUPVMXCTLSMSR, sizeof(uint64_t)); + +/** + * Hardware-virtualization MSRs. + */ +typedef struct SUPHWVIRTMSRS +{ + union + { + /** @sa VMXMSRS */ + struct + { + uint64_t u64FeatCtrl; + uint64_t u64Basic; + /** Pin-based VM-execution controls. */ + SUPVMXCTLSMSR PinCtls; + /** Processor-based VM-execution controls. */ + SUPVMXCTLSMSR ProcCtls; + /** Secondary processor-based VM-execution controls. */ + SUPVMXCTLSMSR ProcCtls2; + /** VM-exit controls. */ + SUPVMXCTLSMSR ExitCtls; + /** VM-entry controls. */ + SUPVMXCTLSMSR EntryCtls; + /** True pin-based VM-execution controls. */ + SUPVMXCTLSMSR TruePinCtls; + /** True processor-based VM-execution controls. */ + SUPVMXCTLSMSR TrueProcCtls; + /** True VM-entry controls. */ + SUPVMXCTLSMSR TrueEntryCtls; + /** True VM-exit controls. */ + SUPVMXCTLSMSR TrueExitCtls; + uint64_t u64Misc; + uint64_t u64Cr0Fixed0; + uint64_t u64Cr0Fixed1; + uint64_t u64Cr4Fixed0; + uint64_t u64Cr4Fixed1; + uint64_t u64VmcsEnum; + uint64_t u64VmFunc; + uint64_t u64EptVpidCaps; + uint64_t u64ProcCtls3; + uint64_t u64ExitCtls2; + uint64_t au64Reserved[7]; + } vmx; + struct + { + uint64_t u64MsrHwcr; + uint64_t u64MsrSmmAddr; + uint64_t u64MsrSmmMask; + uint64_t u64Padding[25]; + } svm; + } u; +} SUPHWVIRTMSRS; +AssertCompileSize(SUPHWVIRTMSRS, 224); +/** Pointer to a hardware-virtualization MSRs struct. */ +typedef SUPHWVIRTMSRS *PSUPHWVIRTMSRS; +/** Pointer to a hardware-virtualization MSRs struct. */ +typedef const SUPHWVIRTMSRS *PCSUPHWVIRTMSRS; + + +/** + * Usermode probe context information. + */ +typedef struct SUPDRVTRACERUSRCTX +{ + /** The probe ID from the VTG location record. */ + uint32_t idProbe; + /** 32 if X86, 64 if AMD64. */ + uint8_t cBits; + /** Reserved padding. */ + uint8_t abReserved[3]; + /** Data which format is dictated by the cBits member. */ + union + { + /** X86 context info. */ + struct + { + uint32_t uVtgProbeLoc; /**< Location record address. */ + uint32_t aArgs[20]; /**< Raw arguments. */ + uint32_t eip; + uint32_t eflags; + uint32_t eax; + uint32_t ecx; + uint32_t edx; + uint32_t ebx; + uint32_t esp; + uint32_t ebp; + uint32_t esi; + uint32_t edi; + uint16_t cs; + uint16_t ss; + uint16_t ds; + uint16_t es; + uint16_t fs; + uint16_t gs; + } X86; + + /** AMD64 context info. */ + struct + { + uint64_t uVtgProbeLoc; /**< Location record address. */ + uint64_t aArgs[10]; /**< Raw arguments. */ + uint64_t rip; + uint64_t rflags; + uint64_t rax; + uint64_t rcx; + uint64_t rdx; + uint64_t rbx; + uint64_t rsp; + uint64_t rbp; + uint64_t rsi; + uint64_t rdi; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + } Amd64; + } u; +} SUPDRVTRACERUSRCTX; +/** Pointer to the usermode probe context information. */ +typedef SUPDRVTRACERUSRCTX *PSUPDRVTRACERUSRCTX; +/** Pointer to the const usermode probe context information. */ +typedef SUPDRVTRACERUSRCTX const *PCSUPDRVTRACERUSRCTX; + +/** + * The result of a modification operation (SUPMSRPROBEROP_MODIFY or + * SUPMSRPROBEROP_MODIFY_FASTER). + */ +typedef struct SUPMSRPROBERMODIFYRESULT +{ + /** The MSR value prior to the modifications. Valid if fBeforeGp is false */ + uint64_t uBefore; + /** The value that was written. Valid if fBeforeGp is false */ + uint64_t uWritten; + /** The MSR value after the modifications. Valid if AfterGp is false. */ + uint64_t uAfter; + /** Set if we GPed reading the MSR before the modification. */ + bool fBeforeGp; + /** Set if we GPed while trying to write the modified value. + * This is set when fBeforeGp is true. */ + bool fModifyGp; + /** Set if we GPed while trying to read the MSR after the modification. + * This is set when fBeforeGp is true. */ + bool fAfterGp; + /** Set if we GPed while trying to restore the MSR after the modification. + * This is set when fBeforeGp is true. */ + bool fRestoreGp; + /** Structure size alignment padding. */ + bool afReserved[4]; +} SUPMSRPROBERMODIFYRESULT, *PSUPMSRPROBERMODIFYRESULT; + + +/** + * The CPU state. + */ +typedef enum SUPGIPCPUSTATE +{ + /** Invalid CPU state / unused CPU entry. */ + SUPGIPCPUSTATE_INVALID = 0, + /** The CPU is not present. */ + SUPGIPCPUSTATE_ABSENT, + /** The CPU is offline. */ + SUPGIPCPUSTATE_OFFLINE, + /** The CPU is online. */ + SUPGIPCPUSTATE_ONLINE, + /** Force 32-bit enum type. */ + SUPGIPCPUSTATE_32_BIT_HACK = 0x7fffffff +} SUPGIPCPUSTATE; + +/** + * Per CPU data. + */ +typedef struct SUPGIPCPU +{ + /** Update transaction number. + * This number is incremented at the start and end of each update. It follows + * thusly that odd numbers indicates update in progress, while even numbers + * indicate stable data. Use this to make sure that the data items you fetch + * are consistent. */ + volatile uint32_t u32TransactionId; + /** The interval in TSC ticks between two NanoTS updates. + * This is the average interval over the last 2, 4 or 8 updates + a little slack. + * The slack makes the time go a tiny tiny bit slower and extends the interval enough + * to avoid ending up with too many 1ns increments. */ + volatile uint32_t u32UpdateIntervalTSC; + /** Current nanosecond timestamp. */ + volatile uint64_t u64NanoTS; + /** The TSC at the time of u64NanoTS. */ + volatile uint64_t u64TSC; + /** Current CPU Frequency. */ + volatile uint64_t u64CpuHz; + /** The TSC delta with reference to the master TSC, subtract from RDTSC. */ + volatile int64_t i64TSCDelta; + /** Number of errors during updating. + * Typical errors are under/overflows. */ + volatile uint32_t cErrors; + /** Index of the head item in au32TSCHistory. */ + volatile uint32_t iTSCHistoryHead; + /** Array of recent TSC interval deltas. + * The most recent item is at index iTSCHistoryHead. + * This history is used to calculate u32UpdateIntervalTSC. + */ + volatile uint32_t au32TSCHistory[8]; + /** The interval between the last two NanoTS updates. (experiment for now) */ + volatile uint32_t u32PrevUpdateIntervalNS; + + /** Reserved for future per processor data. */ + volatile uint32_t u32Reserved; + /** The TSC value read while doing TSC delta measurements across CPUs. */ + volatile uint64_t u64TSCSample; + /** Reserved for future per processor data. */ + volatile uint32_t au32Reserved1[3]; + + /** The CPU state. */ + SUPGIPCPUSTATE volatile enmState; + /** The host CPU ID of this CPU (the SUPGIPCPU is indexed by APIC ID). */ + RTCPUID idCpu; + /** The CPU set index of this CPU. */ + int16_t iCpuSet; + /** CPU group number (always zero, except on windows). */ + uint16_t iCpuGroup; + /** CPU group member number (same as iCpuSet, except on windows). */ + uint16_t iCpuGroupMember; + /** The APIC ID of this CPU. */ + uint16_t idApic; + /** @todo Add topology/NUMA info. */ + uint32_t iReservedForNumaNode; +} SUPGIPCPU; +AssertCompileSize(RTCPUID, 4); +AssertCompileSize(SUPGIPCPU, 128); +AssertCompileMemberAlignment(SUPGIPCPU, u64NanoTS, 8); +AssertCompileMemberAlignment(SUPGIPCPU, u64TSC, 8); +AssertCompileMemberAlignment(SUPGIPCPU, u64TSCSample, 8); + +/** Pointer to per cpu data. + * @remark there is no const version of this typedef, see g_pSUPGlobalInfoPage for details. */ +typedef SUPGIPCPU *PSUPGIPCPU; + +/** + * CPU group information. + * @remarks Windows only. + */ +typedef struct SUPGIPCPUGROUP +{ + /** Current number of CPUs in this group. */ + uint16_t volatile cMembers; + /** Maximum number of CPUs in the group. */ + uint16_t cMaxMembers; + /** The CPU set index of the members. This table has cMaxMembers entries. + * @note For various reasons, entries from cMembers and up to cMaxMembers are + * may change as the host OS does set dynamic assignments during CPU + * hotplugging. */ + int16_t aiCpuSetIdxs[1]; +} SUPGIPCPUGROUP; +/** Pointer to a GIP CPU group structure. */ +typedef SUPGIPCPUGROUP *PSUPGIPCPUGROUP; +/** Pointer to a const GIP CPU group structure. */ +typedef SUPGIPCPUGROUP const *PCSUPGIPCPUGROUP; + +/** + * The rules concerning the applicability of SUPGIPCPU::i64TscDelta. + */ +typedef enum SUPGIPUSETSCDELTA +{ + /** Value for SUPGIPMODE_ASYNC_TSC. */ + SUPGIPUSETSCDELTA_NOT_APPLICABLE = 0, + /** The OS specific part of SUPDrv (or the user) claims the TSC is as + * good as zero. */ + SUPGIPUSETSCDELTA_ZERO_CLAIMED, + /** The differences in RDTSC output between the CPUs/cores/threads should + * be considered zero for all practical purposes. */ + SUPGIPUSETSCDELTA_PRACTICALLY_ZERO, + /** The differences in RDTSC output between the CPUs/cores/threads are a few + * hundred ticks or less. (Probably not worth calling ASMGetApicId two times + * just to apply deltas.) */ + SUPGIPUSETSCDELTA_ROUGHLY_ZERO, + /** Significant differences in RDTSC output between the CPUs/cores/threads, + * deltas must be applied. */ + SUPGIPUSETSCDELTA_NOT_ZERO, + /** End of valid values (exclusive). */ + SUPGIPUSETSCDELTA_END, + /** Make sure the type is 32-bit sized. */ + SUPGIPUSETSCDELTA_32BIT_HACK = 0x7fffffff +} SUPGIPUSETSCDELTA; + + +/** @name SUPGIPGETCPU_XXX - methods that aCPUs can be indexed. + * + * @note Linux offers information via selector 0x78, and Windows via selector + * 0x53. But since they both support RDTSCP as well, and because most + * CPUs now have RDTSCP, we prefer it over LSL. We can implement more + * alternatives if it becomes necessary. + * + * @{ + */ +/** Use ASMGetApicId (or equivalent) and translate the result via + * aiCpuFromApicId. */ +#define SUPGIPGETCPU_APIC_ID RT_BIT_32(0) +/** Use RDTSCP and translate the first RTCPUSET_MAX_CPUS of ECX via + * aiCpuFromCpuSetIdx. + * + * Linux stores the RTMpCpuId() value in ECX[11:0] and NUMA node number in + * ECX[12:31]. Solaris only stores RTMpCpuId() in ECX. On both systems + * RTMpCpuId() == RTMpCpuIdToSetIndex(RTMpCpuId()). RTCPUSET_MAX_CPUS is + * currently 64, 256 or 1024 in size, which lower than + * 4096, so there shouldn't be any range issues. */ +#define SUPGIPGETCPU_RDTSCP_MASK_MAX_SET_CPUS RT_BIT_32(1) +/** Subtract the max IDT size from IDTR.LIMIT, extract the + * first RTCPUSET_MAX_CPUS and translate it via aiCpuFromCpuSetIdx. + * + * Darwin stores the RTMpCpuId() (== RTMpCpuIdToSetIndex(RTMpCpuId())) + * value in the IDT limit. The masking is a precaution against what linux + * does with RDTSCP. */ +#define SUPGIPGETCPU_IDTR_LIMIT_MASK_MAX_SET_CPUS RT_BIT_32(2) +/** Windows specific RDTSCP variant, where CH gives you the group and CL gives + * you the CPU number within that group. + * + * Use SUPGLOBALINFOPAGE::aidFirstCpuFromCpuGroup to get the group base CPU set + * index, then translate the sum of thru aiCpuFromCpuSetIdx to find the aCPUs + * entry. + * + * @note The group number is actually 16-bit wide (ECX[23:8]), but we simplify + * it since we only support 256 CPUs/groups at the moment. + */ +#define SUPGIPGETCPU_RDTSCP_GROUP_IN_CH_NUMBER_IN_CL RT_BIT_32(3) +/** Can use CPUID[0xb].EDX and translate the result via aiCpuFromApicId. */ +#define SUPGIPGETCPU_APIC_ID_EXT_0B RT_BIT_32(4) +/** Can use CPUID[0x8000001e].EAX and translate the result via aiCpuFromApicId. */ +#define SUPGIPGETCPU_APIC_ID_EXT_8000001E RT_BIT_32(5) +/** @} */ + +/** @def SUPGIP_MAX_CPU_GROUPS + * Maximum number of CPU groups. */ +#if RTCPUSET_MAX_CPUS >= 256 +# define SUPGIP_MAX_CPU_GROUPS 256 +#else +# define SUPGIP_MAX_CPU_GROUPS RTCPUSET_MAX_CPUS +#endif + +/** + * Global Information Page. + * + * This page contains useful information and can be mapped into any + * process or VM. It can be accessed thru the g_pSUPGlobalInfoPage + * pointer when a session is open. + */ +typedef struct SUPGLOBALINFOPAGE +{ + /** Magic (SUPGLOBALINFOPAGE_MAGIC). */ + uint32_t u32Magic; + /** The GIP version. */ + uint32_t u32Version; + + /** The GIP update mode, see SUPGIPMODE. */ + uint32_t u32Mode; + /** The number of entries in the CPU table. + * (This can work as RTMpGetArraySize().) */ + uint16_t cCpus; + /** The size of the GIP in pages. */ + uint16_t cPages; + /** The update frequency of the of the NanoTS. */ + volatile uint32_t u32UpdateHz; + /** The update interval in nanoseconds. (10^9 / u32UpdateHz) */ + volatile uint32_t u32UpdateIntervalNS; + /** The timestamp of the last time we update the update frequency. */ + volatile uint64_t u64NanoTSLastUpdateHz; + /** The TSC frequency of the system. */ + uint64_t u64CpuHz; + /** The number of CPUs that are online. */ + volatile uint16_t cOnlineCpus; + /** The number of CPUs present in the system. */ + volatile uint16_t cPresentCpus; + /** The highest number of CPUs possible. */ + uint16_t cPossibleCpus; + /** The highest number of CPU groups possible. */ + uint16_t cPossibleCpuGroups; + /** The max CPU ID (RTMpGetMaxCpuId). */ + RTCPUID idCpuMax; + /** The applicability of SUPGIPCPU::i64TscDelta. */ + SUPGIPUSETSCDELTA enmUseTscDelta; + /** Mask of SUPGIPGETCPU_XXX values that indicates different ways that aCPU + * can be accessed from ring-3 and raw-mode context. */ + uint32_t fGetGipCpu; + /** GIP flags, see SUPGIP_FLAGS_XXX. */ + volatile uint32_t fFlags; + /** The set of online CPUs. */ + RTCPUSET OnlineCpuSet; +#if RTCPUSET_MAX_CPUS < 1024 + uint64_t abOnlineCpuSetPadding[(1024 - RTCPUSET_MAX_CPUS) / 64]; +#endif + /** The set of present CPUs. */ + RTCPUSET PresentCpuSet; +#if RTCPUSET_MAX_CPUS < 1024 + uint64_t abPresentCpuSetPadding[(1024 - RTCPUSET_MAX_CPUS) / 64]; +#endif + /** The set of possible CPUs. */ + RTCPUSET PossibleCpuSet; +#if RTCPUSET_MAX_CPUS < 1024 + uint64_t abPossibleCpuSetPadding[(1024 - RTCPUSET_MAX_CPUS) / 64]; +#endif + + /** Padding / reserved space for future data. */ + uint32_t au32Padding1[48]; + + /** Table indexed by the CPU APIC ID to get the CPU table index. */ + uint16_t aiCpuFromApicId[4096]; + /** CPU set index to CPU table index. */ + uint16_t aiCpuFromCpuSetIdx[1024]; + /** Table indexed by CPU group to containing offsets to SUPGIPCPUGROUP + * structures, invalid entries are set to UINT32_MAX. The offsets are relative + * to the start of this structure. + * @note Windows only. The other hosts sets all entries to UINT32_MAX! */ + uint32_t aoffCpuGroup[SUPGIP_MAX_CPU_GROUPS]; + + /** Array of per-cpu data. + * This is index by ApicId via the aiCpuFromApicId table. + * + * The clock and frequency information is updated for all CPUs if @c u32Mode + * is SUPGIPMODE_ASYNC_TSC. If @c u32Mode is SUPGIPMODE_SYNC_TSC only the first + * entry is updated. If @c u32Mode is SUPGIPMODE_SYNC_TSC the TSC frequency in + * @c u64CpuHz is copied to all CPUs. */ + SUPGIPCPU aCPUs[1]; +} SUPGLOBALINFOPAGE; +AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, u64NanoTSLastUpdateHz, 8); +AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, OnlineCpuSet, 64); +AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, PresentCpuSet, 64); +AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, PossibleCpuSet, 64); +#if defined(RT_ARCH_SPARC) || defined(RT_ARCH_SPARC64) /* ?? needed ?? */ +AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, aCPUs, 32); +#else +AssertCompileMemberAlignment(SUPGLOBALINFOPAGE, aCPUs, 128); +#endif + +/** Pointer to the global info page. + * @remark there is no const version of this typedef, see g_pSUPGlobalInfoPage for details. */ +typedef SUPGLOBALINFOPAGE *PSUPGLOBALINFOPAGE; + + +/** The value of the SUPGLOBALINFOPAGE::u32Magic field. (Soryo Fuyumi) */ +#define SUPGLOBALINFOPAGE_MAGIC 0x19590106 +/** The GIP version. + * Upper 16 bits is the major version. Major version is only changed with + * incompatible changes in the GIP. */ +#define SUPGLOBALINFOPAGE_VERSION 0x000a0000 + +/** + * SUPGLOBALINFOPAGE::u32Mode values. + */ +typedef enum SUPGIPMODE +{ + /** The usual invalid null entry. */ + SUPGIPMODE_INVALID = 0, + /** The TSC of the cores and cpus in the system is in sync. */ + SUPGIPMODE_SYNC_TSC, + /** Each core has it's own TSC. */ + SUPGIPMODE_ASYNC_TSC, + /** The TSC of the cores are non-stop and have a constant frequency. */ + SUPGIPMODE_INVARIANT_TSC, + /** End of valid GIP mode values (exclusive). */ + SUPGIPMODE_END, + /** The usual 32-bit hack. */ + SUPGIPMODE_32BIT_HACK = 0x7fffffff +} SUPGIPMODE; + +/** Pointer to the Global Information Page. + * + * This pointer is valid as long as SUPLib has a open session. Anyone using + * the page must treat this pointer as highly volatile and not trust it beyond + * one transaction. + * + * @remark The GIP page is read-only to everyone but the support driver and + * is actually mapped read only everywhere but in ring-0. However + * it is not marked 'const' as this might confuse compilers into + * thinking that values doesn't change even if members are marked + * as volatile. Thus, there is no PCSUPGLOBALINFOPAGE type. + */ +#if defined(IN_SUP_R3) || defined(IN_SUP_R0) +extern DECLEXPORT(PSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage; + +#elif !defined(IN_RING0) || defined(RT_OS_WINDOWS) || defined(RT_OS_SOLARIS) || defined(VBOX_WITH_KMOD_WRAPPED_R0_MODS) +extern DECLIMPORT(PSUPGLOBALINFOPAGE) g_pSUPGlobalInfoPage; + +#else /* IN_RING0 && !RT_OS_WINDOWS */ +# if !defined(__GNUC__) || defined(RT_OS_DARWIN) || !defined(RT_ARCH_AMD64) +# define g_pSUPGlobalInfoPage (&g_SUPGlobalInfoPage) +# else +# define g_pSUPGlobalInfoPage (SUPGetGIPHlp()) +/** Workaround for ELF+GCC problem on 64-bit hosts. + * (GCC emits a mov with a R_X86_64_32 reloc, we need R_X86_64_64.) */ +DECLINLINE(PSUPGLOBALINFOPAGE) SUPGetGIPHlp(void) +{ + PSUPGLOBALINFOPAGE pGIP; + __asm__ __volatile__ ("movabs $g_SUPGlobalInfoPage,%0\n\t" + : "=a" (pGIP)); + return pGIP; +} +# endif +/** The GIP. + * We save a level of indirection by exporting the GIP instead of a variable + * pointing to it. */ +extern DECLIMPORT(SUPGLOBALINFOPAGE) g_SUPGlobalInfoPage; +#endif + +/** + * Gets the GIP pointer. + * + * @returns Pointer to the GIP or NULL. + */ +SUPDECL(PSUPGLOBALINFOPAGE) SUPGetGIP(void); + +/** @name SUPGIP_FLAGS_XXX - SUPR3GipSetFlags flags. + * @{ */ +/** Enable GIP test mode. */ +#define SUPGIP_FLAGS_TESTING_ENABLE RT_BIT_32(0) +/** Valid mask of flags that can be set through the ioctl. */ +#define SUPGIP_FLAGS_VALID_MASK RT_BIT_32(0) +/** GIP test mode needs to be checked (e.g. when enabled or being disabled). */ +#define SUPGIP_FLAGS_TESTING RT_BIT_32(24) +/** Prepare to start GIP test mode. */ +#define SUPGIP_FLAGS_TESTING_START RT_BIT_32(25) +/** Prepare to stop GIP test mode. */ +#define SUPGIP_FLAGS_TESTING_STOP RT_BIT_32(26) +/** @} */ + +/** @internal */ +SUPDECL(PSUPGIPCPU) SUPGetGipCpuPtrForAsyncMode(PSUPGLOBALINFOPAGE pGip); +SUPDECL(uint64_t) SUPGetCpuHzFromGipForAsyncMode(PSUPGLOBALINFOPAGE pGip); +SUPDECL(bool) SUPIsTscFreqCompatible(uint64_t uCpuHz, uint64_t *puGipCpuHz, bool fRelax); +SUPDECL(bool) SUPIsTscFreqCompatibleEx(uint64_t uBaseCpuHz, uint64_t uCpuHz, bool fRelax); + + +/** + * Gets CPU entry of the calling CPU. + * + * @returns Pointer to the CPU entry on success, NULL on failure. + * @param pGip The GIP pointer. + */ +DECLINLINE(PSUPGIPCPU) SUPGetGipCpuPtr(PSUPGLOBALINFOPAGE pGip) +{ + if (RT_LIKELY( pGip + && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)) + { + switch (pGip->u32Mode) + { + case SUPGIPMODE_INVARIANT_TSC: + case SUPGIPMODE_SYNC_TSC: + return &pGip->aCPUs[0]; + case SUPGIPMODE_ASYNC_TSC: + return SUPGetGipCpuPtrForAsyncMode(pGip); + default: break; /* shut up gcc */ + } + } + AssertFailed(); + return NULL; +} + +/** + * Gets the TSC frequency of the calling CPU. + * + * @returns TSC frequency, UINT64_MAX on failure (asserted). + * @param pGip The GIP pointer. + */ +DECLINLINE(uint64_t) SUPGetCpuHzFromGip(PSUPGLOBALINFOPAGE pGip) +{ + if (RT_LIKELY( pGip + && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)) + { + switch (pGip->u32Mode) + { + case SUPGIPMODE_INVARIANT_TSC: + case SUPGIPMODE_SYNC_TSC: + return pGip->aCPUs[0].u64CpuHz; + case SUPGIPMODE_ASYNC_TSC: + return SUPGetCpuHzFromGipForAsyncMode(pGip); + default: break; /* shut up gcc */ + } + } + AssertFailed(); + return UINT64_MAX; +} + + +/** + * Gets the TSC frequency of the specified CPU. + * + * @returns TSC frequency, UINT64_MAX on failure (asserted). + * @param pGip The GIP pointer. + * @param iCpuSet The CPU set index of the CPU in question. + */ +DECLINLINE(uint64_t) SUPGetCpuHzFromGipBySetIndex(PSUPGLOBALINFOPAGE pGip, uint32_t iCpuSet) +{ + if (RT_LIKELY( pGip + && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)) + { + switch (pGip->u32Mode) + { + case SUPGIPMODE_INVARIANT_TSC: + case SUPGIPMODE_SYNC_TSC: + return pGip->aCPUs[0].u64CpuHz; + case SUPGIPMODE_ASYNC_TSC: + if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) + { + uint16_t iCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; + if (RT_LIKELY(iCpu < pGip->cCpus)) + return pGip->aCPUs[iCpu].u64CpuHz; + } + break; + default: break; /* shut up gcc */ + } + } + AssertFailed(); + return UINT64_MAX; +} + + +/** + * Gets the pointer to the per CPU data for a CPU given by its set index. + * + * @returns Pointer to the corresponding per CPU structure, or NULL if invalid. + * @param pGip The GIP pointer. + * @param iCpuSet The CPU set index of the CPU which we want. + */ +DECLINLINE(PSUPGIPCPU) SUPGetGipCpuBySetIndex(PSUPGLOBALINFOPAGE pGip, uint32_t iCpuSet) +{ + if (RT_LIKELY( pGip + && pGip->u32Magic == SUPGLOBALINFOPAGE_MAGIC)) + { + if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) + { + uint16_t iCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; + if (RT_LIKELY(iCpu < pGip->cCpus)) + return &pGip->aCPUs[iCpu]; + } + } + return NULL; +} + + +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) || defined(RT_ARCH_ARM64) ||defined(RT_ARCH_ARM32) + +/** @internal */ +SUPDECL(uint64_t) SUPReadTscWithDelta(PSUPGLOBALINFOPAGE pGip); + +/** + * Read the host TSC value and applies the TSC delta if appropriate. + * + * @returns the TSC value. + * @remarks Requires GIP to be initialized and valid. + */ +DECLINLINE(uint64_t) SUPReadTsc(void) +{ +# if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) /** @todo portme: ring-0 arm. */ + return ASMReadTSC(); +# else + PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; + if (!pGip || pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) + return ASMReadTSC(); + return SUPReadTscWithDelta(pGip); +# endif +} + +#endif /* X86 || AMD64 || ARM */ + +/** @internal */ +SUPDECL(int64_t) SUPGetTscDeltaSlow(PSUPGLOBALINFOPAGE pGip); + +/** + * Gets the TSC delta for the current CPU. + * + * @returns The TSC delta value (will not return the special INT64_MAX value). + * @param pGip The GIP, NULL is okay in ring-3. + * @remarks Requires GIP to be initialized and valid if pGip isn't NULL. + */ +DECLINLINE(int64_t) SUPGetTscDelta(PSUPGLOBALINFOPAGE pGip) +{ +#ifdef IN_RING3 + if (!pGip || pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) +#else + if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) +#endif + return 0; + return SUPGetTscDeltaSlow(pGip); +} + + +/** + * Gets the TSC delta for a given CPU. + * + * @returns The TSC delta value (will not return the special INT64_MAX value). + * @param iCpuSet The CPU set index of the CPU which TSC delta we want. + * @remarks Requires GIP to be initialized and valid. + */ +DECLINLINE(int64_t) SUPGetTscDeltaByCpuSetIndex(uint32_t iCpuSet) +{ + PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; + if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) + return 0; + if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) + { + uint16_t iCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; + if (RT_LIKELY(iCpu < pGip->cCpus)) + { + int64_t iTscDelta = pGip->aCPUs[iCpu].i64TSCDelta; + if (iTscDelta != INT64_MAX) + return iTscDelta; + } + } + AssertFailed(); + return 0; +} + + +/** + * Checks if the TSC delta is available for a given CPU (if TSC-deltas are + * relevant). + * + * @returns true if it's okay to read the TSC, false otherwise. + * + * @param iCpuSet The CPU set index of the CPU which TSC delta we check. + * @remarks Requires GIP to be initialized and valid. + */ +DECLINLINE(bool) SUPIsTscDeltaAvailableForCpuSetIndex(uint32_t iCpuSet) +{ + PSUPGLOBALINFOPAGE pGip = g_pSUPGlobalInfoPage; + if (pGip->enmUseTscDelta <= SUPGIPUSETSCDELTA_ROUGHLY_ZERO) + return true; + if (RT_LIKELY(iCpuSet < RT_ELEMENTS(pGip->aiCpuFromCpuSetIdx))) + { + uint16_t iCpu = pGip->aiCpuFromCpuSetIdx[iCpuSet]; + if (RT_LIKELY(iCpu < pGip->cCpus)) + { + int64_t iTscDelta = pGip->aCPUs[iCpu].i64TSCDelta; + if (iTscDelta != INT64_MAX) + return true; + } + } + return false; +} + + +/** + * Gets the descriptive GIP mode name. + * + * @returns The name. + * @param pGip Pointer to the GIP. + */ +DECLINLINE(const char *) SUPGetGIPModeName(PSUPGLOBALINFOPAGE pGip) +{ + AssertReturn(pGip, NULL); + switch (pGip->u32Mode) + { + case SUPGIPMODE_INVARIANT_TSC: return "Invariant"; + case SUPGIPMODE_SYNC_TSC: return "Synchronous"; + case SUPGIPMODE_ASYNC_TSC: return "Asynchronous"; + case SUPGIPMODE_INVALID: return "Invalid"; + default: return "???"; + } +} + + +/** + * Gets the descriptive TSC-delta enum name. + * + * @returns The name. + * @param pGip Pointer to the GIP. + */ +DECLINLINE(const char *) SUPGetGIPTscDeltaModeName(PSUPGLOBALINFOPAGE pGip) +{ + AssertReturn(pGip, NULL); + switch (pGip->enmUseTscDelta) + { + case SUPGIPUSETSCDELTA_NOT_APPLICABLE: return "Not Applicable"; + case SUPGIPUSETSCDELTA_ZERO_CLAIMED: return "Zero Claimed"; + case SUPGIPUSETSCDELTA_PRACTICALLY_ZERO: return "Practically Zero"; + case SUPGIPUSETSCDELTA_ROUGHLY_ZERO: return "Roughly Zero"; + case SUPGIPUSETSCDELTA_NOT_ZERO: return "Not Zero"; + default: return "???"; + } +} + + +/** + * Request for generic VMMR0Entry calls. + */ +typedef struct SUPVMMR0REQHDR +{ + /** The magic. (SUPVMMR0REQHDR_MAGIC) */ + uint32_t u32Magic; + /** The size of the request. */ + uint32_t cbReq; +} SUPVMMR0REQHDR; +/** Pointer to a ring-0 request header. */ +typedef SUPVMMR0REQHDR *PSUPVMMR0REQHDR; +/** the SUPVMMR0REQHDR::u32Magic value (Ethan Iverson - The Bad Plus). */ +#define SUPVMMR0REQHDR_MAGIC UINT32_C(0x19730211) + + +/** For the fast ioctl path. + * @{ + */ +/** @see VMMR0_DO_HM_RUN. */ +#define SUP_VMMR0_DO_HM_RUN 0 +/** @see VMMR0_DO_NEM_RUN */ +#define SUP_VMMR0_DO_NEM_RUN 1 +/** @see VMMR0_DO_NOP */ +#define SUP_VMMR0_DO_NOP 2 +/** @} */ + +/** SUPR3QueryVTCaps capability flags. + * @{ + */ +/** AMD-V support. */ +#define SUPVTCAPS_AMD_V RT_BIT(0) +/** VT-x support. */ +#define SUPVTCAPS_VT_X RT_BIT(1) +/** Nested paging is supported. */ +#define SUPVTCAPS_NESTED_PAGING RT_BIT(2) +/** VT-x: Unrestricted guest execution is supported. */ +#define SUPVTCAPS_VTX_UNRESTRICTED_GUEST RT_BIT(3) +/** VT-x: VMCS shadowing is supported. */ +#define SUPVTCAPS_VTX_VMCS_SHADOWING RT_BIT(4) +/** AMD-V: Virtualized VMSAVE/VMLOAD is supported. */ +#define SUPVTCAPS_AMDV_VIRT_VMSAVE_VMLOAD RT_BIT(5) +/** @} */ + +/** + * Request for generic FNSUPR0SERVICEREQHANDLER calls. + */ +typedef struct SUPR0SERVICEREQHDR +{ + /** The magic. (SUPR0SERVICEREQHDR_MAGIC) */ + uint32_t u32Magic; + /** The size of the request. */ + uint32_t cbReq; +} SUPR0SERVICEREQHDR; +/** Pointer to a ring-0 service request header. */ +typedef SUPR0SERVICEREQHDR *PSUPR0SERVICEREQHDR; +/** the SUPVMMR0REQHDR::u32Magic value (Esbjoern Svensson - E.S.P.). */ +#define SUPR0SERVICEREQHDR_MAGIC UINT32_C(0x19640416) + + +/** + * Creates a single release event semaphore. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param phEvent Where to return the handle to the event semaphore. + */ +SUPDECL(int) SUPSemEventCreate(PSUPDRVSESSION pSession, PSUPSEMEVENT phEvent); + +/** + * Closes a single release event semaphore handle. + * + * @returns VBox status code. + * @retval VINF_OBJECT_DESTROYED if the semaphore was destroyed. + * @retval VINF_SUCCESS if the handle was successfully closed but the semaphore + * object remained alive because of other references. + * + * @param pSession The session handle of the caller. + * @param hEvent The handle. Nil is quietly ignored. + */ +SUPDECL(int) SUPSemEventClose(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent); + +/** + * Signals a single release event semaphore. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEvent The semaphore handle. + */ +SUPDECL(int) SUPSemEventSignal(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent); + +#ifdef IN_RING0 +/** + * Waits on a single release event semaphore, not interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEvent The semaphore handle. + * @param cMillies The number of milliseconds to wait. + * @remarks Not available in ring-3. + */ +SUPDECL(int) SUPSemEventWait(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies); +#endif + +/** + * Waits on a single release event semaphore, interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEvent The semaphore handle. + * @param cMillies The number of milliseconds to wait. + */ +SUPDECL(int) SUPSemEventWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint32_t cMillies); + +/** + * Waits on a single release event semaphore, interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEvent The semaphore handle. + * @param uNsTimeout The deadline given on the RTTimeNanoTS() clock. + */ +SUPDECL(int) SUPSemEventWaitNsAbsIntr(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint64_t uNsTimeout); + +/** + * Waits on a single release event semaphore, interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEvent The semaphore handle. + * @param cNsTimeout The number of nanoseconds to wait. + */ +SUPDECL(int) SUPSemEventWaitNsRelIntr(PSUPDRVSESSION pSession, SUPSEMEVENT hEvent, uint64_t cNsTimeout); + +/** + * Gets the best timeout resolution that SUPSemEventWaitNsAbsIntr and + * SUPSemEventWaitNsAbsIntr can do. + * + * @returns The resolution in nanoseconds. + * @param pSession The session handle of the caller. + */ +SUPDECL(uint32_t) SUPSemEventGetResolution(PSUPDRVSESSION pSession); + + +/** + * Creates a multiple release event semaphore. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param phEventMulti Where to return the handle to the event semaphore. + */ +SUPDECL(int) SUPSemEventMultiCreate(PSUPDRVSESSION pSession, PSUPSEMEVENTMULTI phEventMulti); + +/** + * Closes a multiple release event semaphore handle. + * + * @returns VBox status code. + * @retval VINF_OBJECT_DESTROYED if the semaphore was destroyed. + * @retval VINF_SUCCESS if the handle was successfully closed but the semaphore + * object remained alive because of other references. + * + * @param pSession The session handle of the caller. + * @param hEventMulti The handle. Nil is quietly ignored. + */ +SUPDECL(int) SUPSemEventMultiClose(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti); + +/** + * Signals a multiple release event semaphore. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEventMulti The semaphore handle. + */ +SUPDECL(int) SUPSemEventMultiSignal(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti); + +/** + * Resets a multiple release event semaphore. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEventMulti The semaphore handle. + */ +SUPDECL(int) SUPSemEventMultiReset(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti); + +#ifdef IN_RING0 +/** + * Waits on a multiple release event semaphore, not interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEventMulti The semaphore handle. + * @param cMillies The number of milliseconds to wait. + * @remarks Not available in ring-3. + */ +SUPDECL(int) SUPSemEventMultiWait(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies); +#endif + +/** + * Waits on a multiple release event semaphore, interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEventMulti The semaphore handle. + * @param cMillies The number of milliseconds to wait. + */ +SUPDECL(int) SUPSemEventMultiWaitNoResume(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies); + +/** + * Waits on a multiple release event semaphore, interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEventMulti The semaphore handle. + * @param uNsTimeout The deadline given on the RTTimeNanoTS() clock. + */ +SUPDECL(int) SUPSemEventMultiWaitNsAbsIntr(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint64_t uNsTimeout); + +/** + * Waits on a multiple release event semaphore, interruptible. + * + * @returns VBox status code. + * @param pSession The session handle of the caller. + * @param hEventMulti The semaphore handle. + * @param cNsTimeout The number of nanoseconds to wait. + */ +SUPDECL(int) SUPSemEventMultiWaitNsRelIntr(PSUPDRVSESSION pSession, SUPSEMEVENTMULTI hEventMulti, uint64_t cNsTimeout); + +/** + * Gets the best timeout resolution that SUPSemEventMultiWaitNsAbsIntr and + * SUPSemEventMultiWaitNsRelIntr can do. + * + * @returns The resolution in nanoseconds. + * @param pSession The session handle of the caller. + */ +SUPDECL(uint32_t) SUPSemEventMultiGetResolution(PSUPDRVSESSION pSession); + + +#ifdef IN_RING3 + +/** @defgroup grp_sup_r3 SUP Host Context Ring-3 API + * @{ + */ + +/** + * Installs the support library. + * + * @returns VBox status code. + */ +SUPR3DECL(int) SUPR3Install(void); + +/** + * Uninstalls the support library. + * + * @returns VBox status code. + */ +SUPR3DECL(int) SUPR3Uninstall(void); + +/** + * Trusted main entry point. + * + * This is exported as "TrustedMain" by the dynamic libraries which contains the + * "real" application binary for which the hardened stub is built. The entry + * point is invoked upon successful initialization of the support library and + * runtime. + * + * @returns main kind of exit code. + * @param argc The argument count. + * @param argv The argument vector. + * @param envp The environment vector. + */ +typedef DECLCALLBACKTYPE(int, FNSUPTRUSTEDMAIN,(int argc, char **argv, char **envp)); +/** Pointer to FNSUPTRUSTEDMAIN(). */ +typedef FNSUPTRUSTEDMAIN *PFNSUPTRUSTEDMAIN; + +/** Which operation failed. */ +typedef enum SUPINITOP +{ + /** Invalid. */ + kSupInitOp_Invalid = 0, + /** Installation integrity error. */ + kSupInitOp_Integrity, + /** Setuid related. */ + kSupInitOp_RootCheck, + /** Driver related. */ + kSupInitOp_Driver, + /** IPRT init related. */ + kSupInitOp_IPRT, + /** Miscellaneous. */ + kSupInitOp_Misc, + /** Place holder. */ + kSupInitOp_End +} SUPINITOP; + +/** + * Trusted error entry point, optional. + * + * This is exported as "TrustedError" by the dynamic libraries which contains + * the "real" application binary for which the hardened stub is built. The + * hardened main() must specify SUPSECMAIN_FLAGS_TRUSTED_ERROR when calling + * SUPR3HardenedMain. + * + * @param pszWhere Where the error occurred (function name). + * @param enmWhat Which operation went wrong. + * @param rc The status code. + * @param pszMsgFmt Error message format string. + * @param va The message format arguments. + */ +typedef DECLCALLBACKTYPE(void, FNSUPTRUSTEDERROR,(const char *pszWhere, SUPINITOP enmWhat, int rc, + const char *pszMsgFmt, va_list va)) RT_IPRT_FORMAT_ATTR(4, 0); +/** Pointer to FNSUPTRUSTEDERROR. */ +typedef FNSUPTRUSTEDERROR *PFNSUPTRUSTEDERROR; + +/** + * Secure main. + * + * This is used for the set-user-ID-on-execute binaries on unixy systems + * and when using the open-vboxdrv-via-root-service setup on Windows. + * + * This function will perform the integrity checks of the VirtualBox + * installation, open the support driver, open the root service (later), + * and load the DLL corresponding to \a pszProgName and execute its main + * function. + * + * @returns Return code appropriate for main(). + * + * @param pszProgName The program name. This will be used to figure out which + * DLL/SO/DYLIB to load and execute. + * @param fFlags SUPSECMAIN_FLAGS_XXX. + * @param argc The argument count. + * @param argv The argument vector. + * @param envp The environment vector. + */ +DECLHIDDEN(int) SUPR3HardenedMain(const char *pszProgName, uint32_t fFlags, int argc, char **argv, char **envp); + +/** @name SUPSECMAIN_FLAGS_XXX - SUPR3HardenedMain flags. + * @{ */ +/** Don't open the device. (Intended for VirtualBox without -startvm.) */ +#define SUPSECMAIN_FLAGS_DONT_OPEN_DEV RT_BIT_32(0) +/** The hardened DLL has a "TrustedError" function (see FNSUPTRUSTEDERROR). */ +#define SUPSECMAIN_FLAGS_TRUSTED_ERROR RT_BIT_32(1) +/** Hack for making VirtualBoxVM use VirtualBox.dylib on Mac OS X. + * @note Not used since 6.0 */ +#define SUPSECMAIN_FLAGS_OSX_VM_APP RT_BIT_32(2) +/** The first process. + * @internal */ +#define SUPSECMAIN_FLAGS_FIRST_PROCESS RT_BIT_32(3) +/** Program binary location mask. */ +#define SUPSECMAIN_FLAGS_LOC_MASK UINT32_C(0x00000030) +/** Default binary location is the application binary directory. Does + * not need to be given explicitly (it's 0). */ +#define SUPSECMAIN_FLAGS_LOC_APP_BIN UINT32_C(0x00000000) +/** The binary is located in the testcase directory instead of the + * default application binary directory. */ +#define SUPSECMAIN_FLAGS_LOC_TESTCASE UINT32_C(0x00000010) +/** The binary is located in a nested application bundle under Resources/ in the + * main Mac OS X application (think Resources/VirtualBoxVM.app). */ +#define SUPSECMAIN_FLAGS_LOC_OSX_HLP_APP UINT32_C(0x00000020) +/** Force driverless mode. */ +#define SUPSECMAIN_FLAGS_DRIVERLESS RT_BIT_32(8) +/** Driverless IEM-only mode is allowed, so don't fail fatally just because + * the VBox support driver is unavailable. */ +#define SUPSECMAIN_FLAGS_DRIVERLESS_IEM_ALLOWED RT_BIT_32(9) +#ifdef VBOX_WITH_DRIVERLESS_NEM_FALLBACK +/** Driverless NEM is a fallback posibility, so don't fail fatally just + * because the VBox support driver is unavailable. + * This may imply checking NEM requirements, depending on the host. + * @note Not supported on Windows. */ +# define SUPSECMAIN_FLAGS_DRIVERLESS_NEM_FALLBACK RT_BIT_32(10) +#endif + +/** @} */ + +/** + * Initializes the support library. + * + * Each successful call to SUPR3Init() or SUPR3InitEx must be countered by a + * call to SUPR3Term(false). + * + * @returns VBox status code. + * @param ppSession Where to store the session handle. Defaults to NULL. + */ +SUPR3DECL(int) SUPR3Init(PSUPDRVSESSION *ppSession); + +/** + * Initializes the support library, extended version. + * + * Each successful call to SUPR3Init() or SUPR3InitEx must be countered by a + * call to SUPR3Term(false). + * + * @returns VBox status code. + * @param fFlags SUPR3INIT_F_XXX + * @param ppSession Where to store the session handle. Defaults to NULL. + */ +SUPR3DECL(int) SUPR3InitEx(uint32_t fFlags, PSUPDRVSESSION *ppSession); +/** @name SUPR3INIT_F_XXX - Flags for SUPR3InitEx + * @{ */ +/** Unrestricted access. */ +#define SUPR3INIT_F_UNRESTRICTED RT_BIT_32(0) +/** Limited access (for Main). */ +#define SUPR3INIT_F_LIMITED RT_BIT_32(1) +/** Force driverless mode. */ +#define SUPR3INIT_F_DRIVERLESS RT_BIT_32(2) +/** Allow driverless IEM mode if the VBox support driver is unavailable. + * @see SUPSECMAIN_FLAGS_DRIVERLESS_IEM_ALLOWED */ +#define SUPR3INIT_F_DRIVERLESS_IEM_ALLOWED RT_BIT_32(3) +#ifdef VBOX_WITH_DRIVERLESS_NEM_FALLBACK +/** Allow driverless NEM mode as fallback if the VBox support driver is unavailable. + * @see SUPSECMAIN_FLAGS_DRIVERLESS_NEM_FALLBACK */ +# define SUPR3INIT_F_DRIVERLESS_NEM_FALLBACK RT_BIT_32(4) +#endif +/** Mask with all the flags that may trigger driverless mode. */ +#ifdef VBOX_WITH_DRIVERLESS_NEM_FALLBACK +# define SUPR3INIT_F_DRIVERLESS_MASK UINT32_C(0x0000001c) +#else +# define SUPR3INIT_F_DRIVERLESS_MASK UINT32_C(0x0000000c) +#endif +/** @} */ + +/** + * Terminates the support library. + * + * @returns VBox status code. + * @param fForced Forced termination. This means to ignore the + * init call count and just terminated. + */ +#ifdef __cplusplus +SUPR3DECL(int) SUPR3Term(bool fForced = false); +#else +SUPR3DECL(int) SUPR3Term(int fForced); +#endif + +/** + * Check if the support library is operating in driverless mode. + * + * @returns true/false accordingly. + * @see SUPR3INIT_F_DRIVERLESS_IEM_ALLOWED, + * SUPR3INIT_F_DRIVERLESS_NEM_FALLBACK + */ +SUPR3DECL(bool) SUPR3IsDriverless(void); + +/** + * Sets the ring-0 VM handle for use with fast IOCtls. + * + * @returns VBox status code. + * @param pVMR0 The ring-0 VM handle. + * NIL_RTR0PTR can be used to unset the handle when the + * VM is about to be destroyed. + */ +SUPR3DECL(int) SUPR3SetVMForFastIOCtl(PVMR0 pVMR0); + +/** + * Calls the HC R0 VMM entry point. + * See VMMR0Entry() for more details. + * + * @returns error code specific to uFunction. + * @param pVMR0 Pointer to the Ring-0 (Host Context) mapping of the VM structure. + * @param idCpu The virtual CPU ID. + * @param uOperation Operation to execute. + * @param pvArg Argument. + */ +SUPR3DECL(int) SUPR3CallVMMR0(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, void *pvArg); + +/** + * Variant of SUPR3CallVMMR0, except that this takes the fast ioclt path + * regardsless of compile-time defaults. + * + * @returns VBox status code. + * @param pVMR0 The ring-0 VM handle. + * @param uOperation The operation; only the SUP_VMMR0_DO_* ones are valid. + * @param idCpu The virtual CPU ID. + */ +SUPR3DECL(int) SUPR3CallVMMR0Fast(PVMR0 pVMR0, unsigned uOperation, VMCPUID idCpu); + +/** + * Calls the HC R0 VMM entry point, in a safer but slower manner than + * SUPR3CallVMMR0. When entering using this call the R0 components can call + * into the host kernel (i.e. use the SUPR0 and RT APIs). + * + * See VMMR0Entry() for more details. + * + * @returns error code specific to uFunction. + * @param pVMR0 Pointer to the Ring-0 (Host Context) mapping of the VM structure. + * @param idCpu The virtual CPU ID. + * @param uOperation Operation to execute. + * @param u64Arg Constant argument. + * @param pReqHdr Pointer to a request header. Optional. + * This will be copied in and out of kernel space. There currently is a size + * limit on this, just below 4KB. + */ +SUPR3DECL(int) SUPR3CallVMMR0Ex(PVMR0 pVMR0, VMCPUID idCpu, unsigned uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr); + +/** + * Calls a ring-0 service. + * + * The operation and the request packet is specific to the service. + * + * @returns error code specific to uFunction. + * @param pszService The service name. + * @param cchService The length of the service name. + * @param uOperation The request number. + * @param u64Arg Constant argument. + * @param pReqHdr Pointer to a request header. Optional. + * This will be copied in and out of kernel space. There currently is a size + * limit on this, just below 4KB. + */ +SUPR3DECL(int) SUPR3CallR0Service(const char *pszService, size_t cchService, uint32_t uOperation, uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr); + +/** Which logger. */ +typedef enum SUPLOGGER +{ + SUPLOGGER_DEBUG = 1, + SUPLOGGER_RELEASE +} SUPLOGGER; + +/** + * Changes the settings of the specified ring-0 logger. + * + * @returns VBox status code. + * @param enmWhich Which logger. + * @param pszFlags The flags settings. + * @param pszGroups The groups settings. + * @param pszDest The destination specificier. + */ +SUPR3DECL(int) SUPR3LoggerSettings(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest); + +/** + * Creates a ring-0 logger instance. + * + * @returns VBox status code. + * @param enmWhich Which logger to create. + * @param pszFlags The flags settings. + * @param pszGroups The groups settings. + * @param pszDest The destination specificier. + */ +SUPR3DECL(int) SUPR3LoggerCreate(SUPLOGGER enmWhich, const char *pszFlags, const char *pszGroups, const char *pszDest); + +/** + * Destroys a ring-0 logger instance. + * + * @returns VBox status code. + * @param enmWhich Which logger. + */ +SUPR3DECL(int) SUPR3LoggerDestroy(SUPLOGGER enmWhich); + +/** + * Queries the paging mode of the host OS. + * + * @returns The paging mode. + */ +SUPR3DECL(SUPPAGINGMODE) SUPR3GetPagingMode(void); + +/** + * Allocate zero-filled pages. + * + * Use this to allocate a number of pages suitable for seeding / locking. + * Call SUPR3PageFree() to free the pages once done with them. + * + * @returns VBox status. + * @param cPages Number of pages to allocate. + * @param fFlags SUP_PAGE_ALLOC_F_XXX + * @param ppvPages Where to store the base pointer to the allocated pages. + */ +SUPR3DECL(int) SUPR3PageAlloc(size_t cPages, uint32_t fFlags, void **ppvPages); + +/** @name SUP_PAGE_ALLOC_F_XXX - SUPR3PageAlloc flags. + * @{ */ +/** Use large pages if available. */ +#define SUP_PAGE_ALLOC_F_LARGE_PAGES RT_BIT_32(0) +/** Advice that the allocated pages will probably be locked by + * RTR0MemObjLockUser later, so play nice if needed. */ +#define SUP_PAGE_ALLOC_F_FOR_LOCKING RT_BIT_32(1) +/** Mask of valid flags. */ +#define SUP_PAGE_ALLOC_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** + * Frees pages allocated with SUPR3PageAlloc(). + * + * @returns VBox status. + * @param pvPages Pointer returned by SUPR3PageAlloc(). + * @param cPages Number of pages that was allocated. + */ +SUPR3DECL(int) SUPR3PageFree(void *pvPages, size_t cPages); + +/** + * Allocate non-zeroed, locked, pages with user and, optionally, kernel + * mappings. + * + * Use SUPR3PageFreeEx() to free memory allocated with this function. + * + * @returns VBox status code. + * @param cPages The number of pages to allocate. + * @param fFlags Flags, reserved. Must be zero. + * @param ppvPages Where to store the address of the user mapping. + * @param pR0Ptr Where to store the address of the kernel mapping. + * NULL if no kernel mapping is desired. + * @param paPages Where to store the physical addresses of each page. + * Optional. + */ +SUPR3DECL(int) SUPR3PageAllocEx(size_t cPages, uint32_t fFlags, void **ppvPages, PRTR0PTR pR0Ptr, PSUPPAGE paPages); + +/** + * Maps a portion of a ring-3 only allocation into kernel space. + * + * @returns VBox status code. + * + * @param pvR3 The address SUPR3PageAllocEx return. + * @param off Offset to start mapping at. Must be page aligned. + * @param cb Number of bytes to map. Must be page aligned. + * @param fFlags Flags, must be zero. + * @param pR0Ptr Where to store the address on success. + * + */ +SUPR3DECL(int) SUPR3PageMapKernel(void *pvR3, uint32_t off, uint32_t cb, uint32_t fFlags, PRTR0PTR pR0Ptr); + +/** + * Changes the protection of + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if the OS doesn't allow us to change page level + * protection. See also RTR0MemObjProtect. + * + * @param pvR3 The ring-3 address SUPR3PageAllocEx returned. + * @param R0Ptr The ring-0 address SUPR3PageAllocEx returned if it + * is desired that the corresponding ring-0 page + * mappings should change protection as well. Pass + * NIL_RTR0PTR if the ring-0 pages should remain + * unaffected. + * @param off Offset to start at which to start chagning the page + * level protection. Must be page aligned. + * @param cb Number of bytes to change. Must be page aligned. + * @param fProt The new page level protection, either a combination + * of RTMEM_PROT_READ, RTMEM_PROT_WRITE and + * RTMEM_PROT_EXEC, or just RTMEM_PROT_NONE. + */ +SUPR3DECL(int) SUPR3PageProtect(void *pvR3, RTR0PTR R0Ptr, uint32_t off, uint32_t cb, uint32_t fProt); + +/** + * Free pages allocated by SUPR3PageAllocEx. + * + * @returns VBox status code. + * @param pvPages The address of the user mapping. + * @param cPages The number of pages. + */ +SUPR3DECL(int) SUPR3PageFreeEx(void *pvPages, size_t cPages); + +/** + * Allocated memory with page aligned memory with a contiguous and locked physical + * memory backing below 4GB. + * + * @returns Pointer to the allocated memory (virtual address). + * *pHCPhys is set to the physical address of the memory. + * If ppvR0 isn't NULL, *ppvR0 is set to the ring-0 mapping. + * The returned memory must be freed using SUPR3ContFree(). + * @returns NULL on failure. + * @param cPages Number of pages to allocate. + * @param pR0Ptr Where to store the ring-0 mapping of the allocation. (optional) + * @param pHCPhys Where to store the physical address of the memory block. + * + * @remark This 2nd version of this API exists because we're not able to map the + * ring-3 mapping executable on WIN64. This is a serious problem in regard to + * the world switchers. + */ +SUPR3DECL(void *) SUPR3ContAlloc(size_t cPages, PRTR0PTR pR0Ptr, PRTHCPHYS pHCPhys); + +/** + * Frees memory allocated with SUPR3ContAlloc(). + * + * @returns VBox status code. + * @param pv Pointer to the memory block which should be freed. + * @param cPages Number of pages to be freed. + */ +SUPR3DECL(int) SUPR3ContFree(void *pv, size_t cPages); + +/** + * Allocated non contiguous physical memory below 4GB. + * + * The memory isn't zeroed. + * + * @returns VBox status code. + * @returns NULL on failure. + * @param cPages Number of pages to allocate. + * @param ppvPages Where to store the pointer to the allocated memory. + * The pointer stored here on success must be passed to + * SUPR3LowFree when the memory should be released. + * @param ppvPagesR0 Where to store the ring-0 pointer to the allocated memory. optional. + * @param paPages Where to store the physical addresses of the individual pages. + */ +SUPR3DECL(int) SUPR3LowAlloc(size_t cPages, void **ppvPages, PRTR0PTR ppvPagesR0, PSUPPAGE paPages); + +/** + * Frees memory allocated with SUPR3LowAlloc(). + * + * @returns VBox status code. + * @param pv Pointer to the memory block which should be freed. + * @param cPages Number of pages that was allocated. + */ +SUPR3DECL(int) SUPR3LowFree(void *pv, size_t cPages); + +/** + * Load a module into R0 HC. + * + * This will verify the file integrity in a similar manner as + * SUPR3HardenedVerifyFile before loading it. + * + * @returns VBox status code. + * @param pszFilename The path to the image file. + * @param pszModule The module name. Max 32 bytes. + * @param ppvImageBase Where to store the image address. + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3LoadModule(const char *pszFilename, const char *pszModule, void **ppvImageBase, PRTERRINFO pErrInfo); + +/** + * Load a module into R0 HC. + * + * This will verify the file integrity in a similar manner as + * SUPR3HardenedVerifyFile before loading it. + * + * @returns VBox status code. + * @param pszFilename The path to the image file. + * @param pszModule The module name. Max 32 bytes. + * @param pszSrvReqHandler The name of the service request handler entry + * point. See FNSUPR0SERVICEREQHANDLER. + * @param ppvImageBase Where to store the image address. + */ +SUPR3DECL(int) SUPR3LoadServiceModule(const char *pszFilename, const char *pszModule, + const char *pszSrvReqHandler, void **ppvImageBase); + +/** + * Frees a R0 HC module. + * + * @returns VBox status code. + * @param pvImageBase The base address of the image to free. + * @remark This will not actually 'free' the module, there are of course usage counting. + */ +SUPR3DECL(int) SUPR3FreeModule(void *pvImageBase); + +/** + * Lock down the module loader interface. + * + * This will lock down the module loader interface. No new modules can be + * loaded and all loaded modules can no longer be freed. + * + * @returns VBox status code. + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3LockDownLoader(PRTERRINFO pErrInfo); + +/** + * Get the address of a symbol in a ring-0 module. + * + * @returns VBox status code. + * @param pvImageBase The base address of the image to search. + * @param pszSymbol Symbol name. If it's value is less than 64k it's treated like a + * ordinal value rather than a string pointer. + * @param ppvValue Where to store the symbol value. + */ +SUPR3DECL(int) SUPR3GetSymbolR0(void *pvImageBase, const char *pszSymbol, void **ppvValue); + +/** + * Load R0 HC VMM code. + * + * @returns VBox status code. + * @deprecated Use SUPR3LoadModule(pszFilename, "VMMR0.r0", &pvImageBase) + * @param pszFilename Full path to the VMMR0.r0 file (silly). + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3LoadVMM(const char *pszFilename, PRTERRINFO pErrInfo); + +/** + * Unloads R0 HC VMM code. + * + * @returns VBox status code. + * @deprecated Use SUPR3FreeModule(). + */ +SUPR3DECL(int) SUPR3UnloadVMM(void); + +/** + * Get the physical address of the GIP. + * + * @returns VBox status code. + * @param pHCPhys Where to store the physical address of the GIP. + */ +SUPR3DECL(int) SUPR3GipGetPhys(PRTHCPHYS pHCPhys); + +/** + * Initializes only the bits relevant for the SUPR3HardenedVerify* APIs. + * + * This is for users that don't necessarily need to initialize the whole of + * SUPLib. There is no harm in calling this one more time. + * + * @returns VBox status code. + * @remarks Currently not counted, so only call once. + */ +SUPR3DECL(int) SUPR3HardenedVerifyInit(void); + +/** + * Reverses the effect of SUPR3HardenedVerifyInit if SUPR3InitEx hasn't been + * called. + * + * Ignored if the support library was initialized using SUPR3Init or + * SUPR3InitEx. + * + * @returns VBox status code. + */ +SUPR3DECL(int) SUPR3HardenedVerifyTerm(void); + +/** + * Verifies the integrity of a file, and optionally opens it. + * + * The integrity check is for whether the file is suitable for loading into + * the hypervisor or VM process. The integrity check may include verifying + * the authenticode/elfsign/whatever signature of the file, which can take + * a little while. + * + * @returns VBox status code. On failure it will have printed a LogRel message. + * + * @param pszFilename The file. + * @param pszWhat For the LogRel on failure. + * @param phFile Where to store the handle to the opened file. This is optional, pass NULL + * if the file should not be opened. + * @deprecated Write a new one. + */ +SUPR3DECL(int) SUPR3HardenedVerifyFile(const char *pszFilename, const char *pszWhat, PRTFILE phFile); + +/** + * Verifies the integrity of a the current process, including the image + * location and that the invocation was absolute. + * + * This must currently be called after initializing the runtime. The intended + * audience is set-uid-to-root applications, root services and similar. + * + * @returns VBox status code. On failure + * message. + * @param pszArgv0 The first argument to main(). + * @param fInternal Set this to @c true if this is an internal + * VirtualBox application. Otherwise pass @c false. + * @param pErrInfo Where to return extended error information. + */ +SUPR3DECL(int) SUPR3HardenedVerifySelf(const char *pszArgv0, bool fInternal, PRTERRINFO pErrInfo); + +/** + * Verifies the integrity of an installation directory. + * + * The integrity check verifies that the directory cannot be tampered with by + * normal users on the system. On Unix this translates to root ownership and + * no symbolic linking. + * + * @returns VBox status code. On failure a message will be stored in @a pszErr. + * + * @param pszDirPath The directory path. + * @param fRecursive Whether the check should be recursive or + * not. When set, all sub-directores will be checked, + * including files (@a fCheckFiles is ignored). + * @param fCheckFiles Whether to apply the same basic integrity check to + * the files in the directory as the directory itself. + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3HardenedVerifyDir(const char *pszDirPath, bool fRecursive, bool fCheckFiles, PRTERRINFO pErrInfo); + +/** + * Verifies the integrity of a plug-in module. + * + * This is similar to SUPR3HardenedLdrLoad, except it does not load the module + * and that the module does not have to be shipped with VirtualBox. + * + * @returns VBox status code. On failure a message will be stored in @a pszErr. + * + * @param pszFilename The filename of the plug-in module (nothing can be + * omitted here). + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3HardenedVerifyPlugIn(const char *pszFilename, PRTERRINFO pErrInfo); + +/** + * Same as RTLdrLoad() but will verify the files it loads (hardened builds). + * + * Will add dll suffix if missing and try load the file. + * + * @returns iprt status code. + * @param pszFilename Image filename. This must have a path. + * @param phLdrMod Where to store the handle to the loaded module. + * @param fFlags See RTLDRLOAD_FLAGS_XXX. + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3HardenedLdrLoad(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** + * Same as RTLdrLoadAppPriv() but it will verify the files it loads (hardened + * builds). + * + * Will add dll suffix to the file if missing, then look for it in the + * architecture dependent application directory. + * + * @returns iprt status code. + * @param pszFilename Image filename. + * @param phLdrMod Where to store the handle to the loaded module. + * @param fFlags See RTLDRLOAD_FLAGS_XXX. + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3HardenedLdrLoadAppPriv(const char *pszFilename, PRTLDRMOD phLdrMod, uint32_t fFlags, PRTERRINFO pErrInfo); + +/** + * Same as RTLdrLoad() but will verify the files it loads (hardened builds). + * + * This differs from SUPR3HardenedLdrLoad() in that it can load modules from + * extension packs and anything else safely installed on the system, provided + * they pass the hardening tests. + * + * @returns iprt status code. + * @param pszFilename The full path to the module, with extension. + * @param phLdrMod Where to store the handle to the loaded module. + * @param pErrInfo Where to return extended error information. + * Optional. + */ +SUPR3DECL(int) SUPR3HardenedLdrLoadPlugIn(const char *pszFilename, PRTLDRMOD phLdrMod, PRTERRINFO pErrInfo); + +/** + * Check if the host kernel can run in VMX root mode. + * + * @returns VINF_SUCCESS if supported, error code indicating why if not. + * @param ppszWhy Where to return an explanatory message on failure. + */ +SUPR3DECL(int) SUPR3QueryVTxSupported(const char **ppszWhy); + +/** + * Return VT-x/AMD-V capabilities. + * + * @returns VINF_SUCCESS if supported, error code indicating why if not. + * @param pfCaps Pointer to capability dword (out). + * @todo Intended for main, which means we need to relax the privilege requires + * when accessing certain vboxdrv functions. + */ +SUPR3DECL(int) SUPR3QueryVTCaps(uint32_t *pfCaps); + +/** + * Check if NEM is supported when no VT-x/AMD-V is indicated by the CPU. + * + * This is really only for the windows case where we're running in a root + * partition and isn't allowed to use the hardware directly. + * + * @returns True if NEM API support, false if not. + */ +SUPR3DECL(bool) SUPR3IsNemSupportedWhenNoVtxOrAmdV(void); + +/** + * Open the tracer. + * + * @returns VBox status code. + * @param uCookie Cookie identifying the tracer we expect to talk to. + * @param uArg Tracer specific open argument. + */ +SUPR3DECL(int) SUPR3TracerOpen(uint32_t uCookie, uintptr_t uArg); + +/** + * Closes the tracer. + * + * @returns VBox status code. + */ +SUPR3DECL(int) SUPR3TracerClose(void); + +/** + * Perform an I/O request on the tracer. + * + * @returns VBox status. + * @param uCmd The tracer command. + * @param uArg The argument. + * @param piRetVal Where to store the tracer return value. + */ +SUPR3DECL(int) SUPR3TracerIoCtl(uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal); + +/** + * Registers the user module with the tracer. + * + * @returns VBox status code. + * @param hModNative Native module handle. Pass ~(uintptr_t)0 if not + * at hand. + * @param pszModule The module name. + * @param pVtgHdr The VTG header. + * @param uVtgHdrAddr The address to which the VTG header is loaded + * in the relevant execution context. + * @param fFlags See SUP_TRACER_UMOD_FLAGS_XXX + */ +SUPR3DECL(int) SUPR3TracerRegisterModule(uintptr_t hModNative, const char *pszModule, struct VTGOBJHDR *pVtgHdr, + RTUINTPTR uVtgHdrAddr, uint32_t fFlags); + +/** + * Deregisters the user module. + * + * @returns VBox status code. + * @param pVtgHdr The VTG header. + */ +SUPR3DECL(int) SUPR3TracerDeregisterModule(struct VTGOBJHDR *pVtgHdr); + +/** + * Fire the probe. + * + * @param pVtgProbeLoc The probe location record. + * @param uArg0 Raw probe argument 0. + * @param uArg1 Raw probe argument 1. + * @param uArg2 Raw probe argument 2. + * @param uArg3 Raw probe argument 3. + * @param uArg4 Raw probe argument 4. + */ +SUPDECL(void) SUPTracerFireProbe(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2, + uintptr_t uArg3, uintptr_t uArg4); + +/** + * Attempts to read the value of an MSR. + * + * @returns VBox status code. + * @param uMsr The MSR to read. + * @param idCpu The CPU to read it on, NIL_RTCPUID if it doesn't + * matter which CPU. + * @param puValue Where to return the value. + * @param pfGp Where to store the \#GP indicator for the read + * operation. + */ +SUPR3DECL(int) SUPR3MsrProberRead(uint32_t uMsr, RTCPUID idCpu, uint64_t *puValue, bool *pfGp); + +/** + * Attempts to write to an MSR. + * + * @returns VBox status code. + * @param uMsr The MSR to write to. + * @param idCpu The CPU to wrtie it on, NIL_RTCPUID if it + * doesn't matter which CPU. + * @param uValue The value to write. + * @param pfGp Where to store the \#GP indicator for the write + * operation. + */ +SUPR3DECL(int) SUPR3MsrProberWrite(uint32_t uMsr, RTCPUID idCpu, uint64_t uValue, bool *pfGp); + +/** + * Attempts to modify the value of an MSR. + * + * @returns VBox status code. + * @param uMsr The MSR to modify. + * @param idCpu The CPU to modify it on, NIL_RTCPUID if it + * doesn't matter which CPU. + * @param fAndMask The bits to keep in the current MSR value. + * @param fOrMask The bits to set before writing. + * @param pResult The result buffer. + */ +SUPR3DECL(int) SUPR3MsrProberModify(uint32_t uMsr, RTCPUID idCpu, uint64_t fAndMask, uint64_t fOrMask, + PSUPMSRPROBERMODIFYRESULT pResult); + +/** + * Attempts to modify the value of an MSR, extended version. + * + * @returns VBox status code. + * @param uMsr The MSR to modify. + * @param idCpu The CPU to modify it on, NIL_RTCPUID if it + * doesn't matter which CPU. + * @param fAndMask The bits to keep in the current MSR value. + * @param fOrMask The bits to set before writing. + * @param fFaster If set to @c true some cache/tlb invalidation is + * skipped, otherwise behave like + * SUPR3MsrProberModify. + * @param pResult The result buffer. + */ +SUPR3DECL(int) SUPR3MsrProberModifyEx(uint32_t uMsr, RTCPUID idCpu, uint64_t fAndMask, uint64_t fOrMask, bool fFaster, + PSUPMSRPROBERMODIFYRESULT pResult); + +/** + * Resume built-in keyboard on MacBook Air and Pro hosts. + * + * @returns VBox status code. + */ +SUPR3DECL(int) SUPR3ResumeSuspendedKeyboards(void); + +/** + * Measure the TSC-delta for the specified CPU. + * + * @returns VBox status code. + * @param idCpu The CPU to measure the TSC-delta for. + * @param fAsync Whether the measurement is asynchronous, returns + * immediately after signalling a measurement + * request. + * @param fForce Whether to perform a measurement even if the + * specified CPU has a (possibly) valid TSC delta. + * @param cRetries Number of times to retry failed delta + * measurements. + * @param cMsWaitRetry Number of milliseconds to wait between retries. + */ +SUPR3DECL(int) SUPR3TscDeltaMeasure(RTCPUID idCpu, bool fAsync, bool fForce, uint8_t cRetries, uint8_t cMsWaitRetry); + +/** + * Reads the delta-adjust TSC value. + * + * @returns VBox status code. + * @param puTsc Where to store the read TSC value. + * @param pidApic Where to store the APIC ID of the CPU where the TSC + * was read (optional, can be NULL). + */ +SUPR3DECL(int) SUPR3ReadTsc(uint64_t *puTsc, uint16_t *pidApic); + +/** + * Modifies the GIP flags. + * + * @returns VBox status code. + * @param fOrMask The OR mask of the GIP flags, see SUPGIP_FLAGS_XXX. + * @param fAndMask The AND mask of the GIP flags, see SUPGIP_FLAGS_XXX. + */ +SUPR3DECL(int) SUPR3GipSetFlags(uint32_t fOrMask, uint32_t fAndMask); + +/** + * Return processor microcode revision, if applicable. + * + * @returns VINF_SUCCESS if supported, error code indicating why if not. + * @param puMicrocodeRev Pointer to microcode revision dword (out). + */ +SUPR3DECL(int) SUPR3QueryMicrocodeRev(uint32_t *puMicrocodeRev); + +/** + * Gets hardware-virtualization MSRs of the CPU, if available. + * + * @returns VINF_SUCCESS if available, error code indicating why if not. + * @param pHwvirtMsrs Where to store the hardware-virtualization MSRs. + * @param fForceRequery Whether to force complete re-querying of MSRs (rather + * than fetching cached values when available). + */ +SUPR3DECL(int) SUPR3GetHwvirtMsrs(PSUPHWVIRTMSRS pHwvirtMsrs, bool fForceRequery); + +/** @} */ +#endif /* IN_RING3 */ + + +/** @name User mode module flags (SUPR3TracerRegisterModule & SUP_IOCTL_TRACER_UMOD_REG). + * @{ */ +/** Executable image. */ +#define SUP_TRACER_UMOD_FLAGS_EXE UINT32_C(1) +/** Shared library (DLL, DYLIB, SO, etc). */ +#define SUP_TRACER_UMOD_FLAGS_SHARED UINT32_C(2) +/** Image type mask. */ +#define SUP_TRACER_UMOD_FLAGS_TYPE_MASK UINT32_C(3) +/** @} */ + + +#ifdef IN_RING0 +/** @defgroup grp_sup_r0 SUP Host Context Ring-0 API + * @{ + */ + +/** + * Security objectype. + */ +typedef enum SUPDRVOBJTYPE +{ + /** The usual invalid object. */ + SUPDRVOBJTYPE_INVALID = 0, + /** A Virtual Machine instance. */ + SUPDRVOBJTYPE_VM, + /** Internal network. */ + SUPDRVOBJTYPE_INTERNAL_NETWORK, + /** Internal network interface. */ + SUPDRVOBJTYPE_INTERNAL_NETWORK_INTERFACE, + /** Single release event semaphore. */ + SUPDRVOBJTYPE_SEM_EVENT, + /** Multiple release event semaphore. */ + SUPDRVOBJTYPE_SEM_EVENT_MULTI, + /** Raw PCI device. */ + SUPDRVOBJTYPE_RAW_PCI_DEVICE, + /** The first invalid object type in this end. */ + SUPDRVOBJTYPE_END, + /** The usual 32-bit type size hack. */ + SUPDRVOBJTYPE_32_BIT_HACK = 0x7ffffff +} SUPDRVOBJTYPE; + +/** + * Object destructor callback. + * This is called for reference counted objectes when the count reaches 0. + * + * @param pvObj The object pointer. + * @param pvUser1 The first user argument. + * @param pvUser2 The second user argument. + */ +typedef DECLCALLBACKTYPE(void, FNSUPDRVDESTRUCTOR,(void *pvObj, void *pvUser1, void *pvUser2)); +/** Pointer to a FNSUPDRVDESTRUCTOR(). */ +typedef FNSUPDRVDESTRUCTOR *PFNSUPDRVDESTRUCTOR; + +/** + * Service request callback function. + * + * @returns VBox status code. + * @param pSession The caller's session. + * @param uOperation The operation identifier. + * @param u64Arg 64-bit integer argument. + * @param pReqHdr The request header. Input / Output. Optional. + */ +typedef DECLCALLBACKTYPE(int, FNSUPR0SERVICEREQHANDLER,(PSUPDRVSESSION pSession, uint32_t uOperation, + uint64_t u64Arg, PSUPR0SERVICEREQHDR pReqHdr)); +/** Pointer to a FNR0SERVICEREQHANDLER(). */ +typedef R0PTRTYPE(FNSUPR0SERVICEREQHANDLER *) PFNSUPR0SERVICEREQHANDLER; + +/** + * Symbol entry for a wrapped module (SUPLDRWRAPPEDMODULE). + */ +typedef struct SUPLDRWRAPMODSYMBOL +{ + /** The symbol namel. */ + const char *pszSymbol; + /** The symbol address/value. */ + PFNRT pfnValue; +} SUPLDRWRAPMODSYMBOL; +/** Pointer to a symbol entry for a wrapped module. */ +typedef SUPLDRWRAPMODSYMBOL const *PCSUPLDRWRAPMODSYMBOL; + +/** + * Registration structure for SUPR0LdrRegisterWrapperModule. + * + * This is used to register a .r0 module when loaded manually as a native kernel + * module/extension/driver/whatever. + */ +typedef struct SUPLDRWRAPPEDMODULE +{ + /** Magic value (SUPLDRWRAPPEDMODULE_MAGIC). */ + uint32_t uMagic; + /** The structure version. */ + uint16_t uVersion; + /** SUPLDRWRAPPEDMODULE_F_XXX. */ + uint16_t fFlags; + + /** As close as possible to the start of the image. */ + void *pvImageStart; + /** As close as possible to the end of the image. */ + void *pvImageEnd; + + /** @name Standar entry points + * @{ */ + /** Pointer to the module initialization function (optional). */ + DECLCALLBACKMEMBER(int, pfnModuleInit,(void *hMod)); + /** Pointer to the module termination function (optional). */ + DECLCALLBACKMEMBER(void, pfnModuleTerm,(void *hMod)); + /** The VMMR0EntryFast entry point for VMMR0. */ + PFNRT pfnVMMR0EntryFast; + /** The VMMR0EntryEx entry point for VMMR0. */ + PFNRT pfnVMMR0EntryEx; + /** The service request handler entry point. */ + PFNSUPR0SERVICEREQHANDLER pfnServiceReqHandler; + /** @} */ + + /** The symbol table. */ + PCSUPLDRWRAPMODSYMBOL paSymbols; + /** Number of symbols. */ + uint32_t cSymbols; + + /** The normal VBox module name. */ + char szName[32]; + /** Repeating the magic value here (SUPLDRWRAPPEDMODULE_MAGIC). */ + uint32_t uEndMagic; +} SUPLDRWRAPPEDMODULE; +/** Pointer to the wrapped module registration structure. */ +typedef SUPLDRWRAPPEDMODULE const *PCSUPLDRWRAPPEDMODULE; + +/** Magic value for the wrapped module structure (Doris lessing). */ +#define SUPLDRWRAPPEDMODULE_MAGIC UINT32_C(0x19191117) +/** Current SUPLDRWRAPPEDMODULE structure version. */ +#define SUPLDRWRAPPEDMODULE_VERSION UINT16_C(0x0001) + +/** Set if this is the VMMR0 module. */ +#define SUPLDRWRAPPEDMODULE_F_VMMR0 UINT16_C(0x0001) + + +SUPR0DECL(void *) SUPR0ObjRegister(PSUPDRVSESSION pSession, SUPDRVOBJTYPE enmType, PFNSUPDRVDESTRUCTOR pfnDestructor, void *pvUser1, void *pvUser2); +SUPR0DECL(int) SUPR0ObjAddRef(void *pvObj, PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0ObjAddRefEx(void *pvObj, PSUPDRVSESSION pSession, bool fNoBlocking); +SUPR0DECL(int) SUPR0ObjRelease(void *pvObj, PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0ObjVerifyAccess(void *pvObj, PSUPDRVSESSION pSession, const char *pszObjName); + +SUPR0DECL(PVM) SUPR0GetSessionVM(PSUPDRVSESSION pSession); +SUPR0DECL(PGVM) SUPR0GetSessionGVM(PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0SetSessionVM(PSUPDRVSESSION pSession, PGVM pGVM, PVM pVM); +SUPR0DECL(RTUID) SUPR0GetSessionUid(PSUPDRVSESSION pSession); + +SUPR0DECL(int) SUPR0LockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t cPages, PRTHCPHYS paPages); +SUPR0DECL(int) SUPR0UnlockMem(PSUPDRVSESSION pSession, RTR3PTR pvR3); +SUPR0DECL(int) SUPR0ContAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS pHCPhys); +SUPR0DECL(int) SUPR0ContFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr); +SUPR0DECL(int) SUPR0LowAlloc(PSUPDRVSESSION pSession, uint32_t cPages, PRTR0PTR ppvR0, PRTR3PTR ppvR3, PRTHCPHYS paPages); +SUPR0DECL(int) SUPR0LowFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr); +SUPR0DECL(int) SUPR0MemAlloc(PSUPDRVSESSION pSession, uint32_t cb, PRTR0PTR ppvR0, PRTR3PTR ppvR3); +SUPR0DECL(int) SUPR0MemGetPhys(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr, PSUPPAGE paPages); +SUPR0DECL(int) SUPR0MemFree(PSUPDRVSESSION pSession, RTHCUINTPTR uPtr); +SUPR0DECL(int) SUPR0PageAllocEx(PSUPDRVSESSION pSession, uint32_t cPages, uint32_t fFlags, PRTR3PTR ppvR3, PRTR0PTR ppvR0, PRTHCPHYS paPages); +SUPR0DECL(int) SUPR0PageMapKernel(PSUPDRVSESSION pSession, RTR3PTR pvR3, uint32_t offSub, uint32_t cbSub, uint32_t fFlags, PRTR0PTR ppvR0); +SUPR0DECL(int) SUPR0PageProtect(PSUPDRVSESSION pSession, RTR3PTR pvR3, RTR0PTR pvR0, uint32_t offSub, uint32_t cbSub, uint32_t fProt); +SUPR0DECL(int) SUPR0PageFree(PSUPDRVSESSION pSession, RTR3PTR pvR3); +SUPR0DECL(int) SUPR0GipMap(PSUPDRVSESSION pSession, PRTR3PTR ppGipR3, PRTHCPHYS pHCPhysGip); +SUPR0DECL(int) SUPR0LdrLock(PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0LdrUnlock(PSUPDRVSESSION pSession); +SUPR0DECL(bool) SUPR0LdrIsLockOwnerByMod(void *hMod, bool fWantToHear); +SUPR0DECL(int) SUPR0LdrModByName(PSUPDRVSESSION pSession, const char *pszName, void **phMod); +SUPR0DECL(int) SUPR0LdrModRetain(PSUPDRVSESSION pSession, void *hMod); +SUPR0DECL(int) SUPR0LdrModRelease(PSUPDRVSESSION pSession, void *hMod); +#ifdef RT_OS_LINUX +SUPR0DECL(int) SUPDrvLinuxLdrRegisterWrappedModule(PCSUPLDRWRAPPEDMODULE pWrappedModInfo, const char *pszLnxModName, void **phMod); +SUPR0DECL(int) SUPDrvLinuxLdrDeregisterWrappedModule(PCSUPLDRWRAPPEDMODULE pWrappedModInfo, void **phMod); +#endif +SUPR0DECL(int) SUPR0GetVTSupport(uint32_t *pfCaps); +SUPR0DECL(int) SUPR0GetHwvirtMsrs(PSUPHWVIRTMSRS pMsrs, uint32_t fCaps, bool fForce); +SUPR0DECL(int) SUPR0GetSvmUsability(bool fInitSvm); +SUPR0DECL(int) SUPR0GetVmxUsability(bool *pfIsSmxModeAmbiguous); +SUPR0DECL(int) SUPR0GetCurrentGdtRw(RTHCUINTPTR *pGdtRw); +SUPR0DECL(int) SUPR0QueryVTCaps(PSUPDRVSESSION pSession, uint32_t *pfCaps); +SUPR0DECL(int) SUPR0GipUnmap(PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0QueryUcodeRev(PSUPDRVSESSION pSession, uint32_t *puMicrocodeRev); +SUPR0DECL(SUPPAGINGMODE) SUPR0GetPagingMode(void); +SUPR0DECL(RTCCUINTREG) SUPR0ChangeCR4(RTCCUINTREG fOrMask, RTCCUINTREG fAndMask); +SUPR0DECL(int) SUPR0EnableVTx(bool fEnable); +SUPR0DECL(bool) SUPR0SuspendVTxOnCpu(void); +SUPR0DECL(void) SUPR0ResumeVTxOnCpu(bool fSuspended); +#define SUP_TSCDELTA_MEASURE_F_FORCE RT_BIT_32(0) +#define SUP_TSCDELTA_MEASURE_F_ASYNC RT_BIT_32(1) +#define SUP_TSCDELTA_MEASURE_F_VALID_MASK UINT32_C(0x00000003) +SUPR0DECL(int) SUPR0TscDeltaMeasureBySetIndex(PSUPDRVSESSION pSession, uint32_t iCpuSet, uint32_t fFlags, + RTMSINTERVAL cMsWaitRetry, RTMSINTERVAL cMsWaitThread, uint32_t cTries); + +SUPR0DECL(void) SUPR0BadContext(PSUPDRVSESSION pSession, const char *pszFile, uint32_t uLine, const char *pszExpr); + +#if defined(RT_OS_LINUX) || defined(RT_OS_SOLARIS) || defined(RT_OS_FREEBSD) +/** + * Translates a physical address to a virtual mapping (valid up to end of page). + * @returns VBox status code. + * @param HCPhys The physical address, must be page aligned. + * @param ppv Where to store the mapping address on success. + */ +SUPR0DECL(int) SUPR0HCPhysToVirt(RTHCPHYS HCPhys, void **ppv); +#endif + +/** Context structure returned by SUPR0IoCtlSetup for use with + * SUPR0IoCtlPerform and cleaned up by SUPR0IoCtlCleanup. */ +typedef struct SUPR0IOCTLCTX *PSUPR0IOCTLCTX; + +/** + * Sets up a I/O control context for the given handle. + * + * @returns VBox status code. + * @param pSession The support driver session. + * @param hHandle The handle. + * @param fFlags Flag, MBZ. + * @param ppCtx Where the context is returned. + */ +SUPR0DECL(int) SUPR0IoCtlSetupForHandle(PSUPDRVSESSION pSession, intptr_t hHandle, uint32_t fFlags, PSUPR0IOCTLCTX *ppCtx); + +/** + * Cleans up the I/O control context when done. + * + * This won't close the handle passed to SUPR0IoCtlSetupForHandle. + * + * @returns VBox status code. + * @param pCtx The I/O control context to cleanup. + */ +SUPR0DECL(int) SUPR0IoCtlCleanup(PSUPR0IOCTLCTX pCtx); + +/** + * Performs an I/O control operation. + * + * @returns VBox status code. + * @param pCtx The I/O control context returned by + * SUPR0IoCtlSetupForHandle. + * @param uFunction The I/O control function to perform. + * @param pvInput Pointer to input buffer (ring-0). + * @param pvInputUser Ring-3 pointer corresponding to @a pvInput. + * @param cbInput The amount of input. If zero, both input pointers + * are expected to be NULL. + * @param pvOutput Pointer to output buffer (ring-0). + * @param pvOutputUser Ring-3 pointer corresponding to @a pvInput. + * @param cbOutput The amount of input. If zero, both input pointers + * are expected to be NULL. + * @param piNativeRc Where to return the native return code. When + * specified the VBox status code will typically be + * VINF_SUCCESS and the caller have to consult this for + * the actual result of the operation. (This saves + * pointless status code conversion.) Optional. + * + * @note On unix systems where there is only one set of buffers possible, + * pass the same pointers as input and output. + */ +SUPR0DECL(int) SUPR0IoCtlPerform(PSUPR0IOCTLCTX pCtx, uintptr_t uFunction, + void *pvInput, RTR3PTR pvInputUser, size_t cbInput, + void *pvOutput, RTR3PTR pvOutputUser, size_t cbOutput, + int32_t *piNativeRc); + +/** + * Writes to the debugger and/or kernel log, va_list version. + * + * The length of the formatted message is somewhat limited, so keep things short + * and to the point. + * + * @returns Number of bytes written, mabye. + * @param pszFormat IPRT format string. + * @param va Arguments referenced by the format string. + */ +SUPR0DECL(int) SUPR0PrintfV(const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(1, 0); + +/** + * Writes to the debugger and/or kernel log. + * + * The length of the formatted message is somewhat limited, so keep things short + * and to the point. + * + * @returns Number of bytes written, mabye. + * @param pszFormat IPRT format string. + * @param ... Arguments referenced by the format string. + */ +#if defined(__GNUC__) && defined(__inline__) +/* Define it as static for GCC as it cannot inline functions using va_start() anyway, + and linux redefines __inline__ to always inlining forcing gcc to issue an error. */ +static int __attribute__((__unused__)) +#else +DECLINLINE(int) +#endif +RT_IPRT_FORMAT_ATTR(1, 2) SUPR0Printf(const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + SUPR0PrintfV(pszFormat, va); + va_end(va); + return 0; +} + +/* HACK ALERT! See above. */ +#ifdef SUPR0PRINTF_UNDO_INLINE_HACK +# define __inline__ inline +#endif + +#ifdef IN_RING0 +/** Debug printf macro. This also exist in SUPLib, see SUPLibInternal.h. */ +# ifdef DEBUG +# define SUP_DPRINTF(a) SUPR0Printf a +# else +# define SUP_DPRINTF(a) do { } while (0) +# endif +#endif + +/** + * Returns configuration flags of the host kernel. + * + * @returns Combination of SUPKERNELFEATURES_XXX flags. + */ +SUPR0DECL(uint32_t) SUPR0GetKernelFeatures(void); + +/** + * Notification from R0 VMM prior to loading the guest-FPU register state. + * + * @returns Whether the host-FPU register state has been saved by the host kernel. + * @param fCtxHook Whether thread-context hooks are enabled. + * + * @remarks Called with preemption disabled. + */ +SUPR0DECL(bool) SUPR0FpuBegin(bool fCtxHook); + +/** + * Notification from R0 VMM after saving the guest-FPU register state (and + * potentially restoring the host-FPU register state) in ring-0. + * + * @param fCtxHook Whether thread-context hooks are enabled. + * + * @remarks Called with preemption disabled. + */ +SUPR0DECL(void) SUPR0FpuEnd(bool fCtxHook); + +/** @copydoc RTLogDefaultInstanceEx + * @remarks To allow overriding RTLogDefaultInstanceEx locally. */ +SUPR0DECL(struct RTLOGGER *) SUPR0DefaultLogInstanceEx(uint32_t fFlagsAndGroup); +/** @copydoc RTLogGetDefaultInstanceEx + * @remarks To allow overriding RTLogGetDefaultInstanceEx locally. */ +SUPR0DECL(struct RTLOGGER *) SUPR0GetDefaultLogInstanceEx(uint32_t fFlagsAndGroup); +/** @copydoc RTLogRelGetDefaultInstanceEx + * @remarks To allow overriding RTLogRelGetDefaultInstanceEx locally. */ +SUPR0DECL(struct RTLOGGER *) SUPR0GetDefaultLogRelInstanceEx(uint32_t fFlagsAndGroup); + + +/** @name Absolute symbols + * Take the address of these, don't try call them. + * @{ */ +SUPR0DECL(void) SUPR0AbsIs64bit(void); +SUPR0DECL(void) SUPR0Abs64bitKernelCS(void); +SUPR0DECL(void) SUPR0Abs64bitKernelSS(void); +SUPR0DECL(void) SUPR0Abs64bitKernelDS(void); +SUPR0DECL(void) SUPR0AbsKernelCS(void); +SUPR0DECL(void) SUPR0AbsKernelSS(void); +SUPR0DECL(void) SUPR0AbsKernelDS(void); +SUPR0DECL(void) SUPR0AbsKernelES(void); +SUPR0DECL(void) SUPR0AbsKernelFS(void); +SUPR0DECL(void) SUPR0AbsKernelGS(void); +/** @} */ + +/** + * Support driver component factory. + * + * Component factories are registered by drivers that provides services + * such as the host network interface filtering and access to the host + * TCP/IP stack. + * + * @remark Module dependencies and making sure that a component doesn't + * get unloaded while in use, is the sole responsibility of the + * driver/kext/whatever implementing the component. + */ +typedef struct SUPDRVFACTORY +{ + /** The (unique) name of the component factory. */ + char szName[56]; + /** + * Queries a factory interface. + * + * The factory interface is specific to each component and will be be + * found in the header(s) for the component alongside its UUID. + * + * @returns Pointer to the factory interfaces on success, NULL on failure. + * + * @param pSupDrvFactory Pointer to this structure. + * @param pSession The SUPDRV session making the query. + * @param pszInterfaceUuid The UUID of the factory interface. + */ + DECLR0CALLBACKMEMBER(void *, pfnQueryFactoryInterface,(struct SUPDRVFACTORY const *pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)); +} SUPDRVFACTORY; +/** Pointer to a support driver factory. */ +typedef SUPDRVFACTORY *PSUPDRVFACTORY; +/** Pointer to a const support driver factory. */ +typedef SUPDRVFACTORY const *PCSUPDRVFACTORY; + +SUPR0DECL(int) SUPR0ComponentRegisterFactory(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory); +SUPR0DECL(int) SUPR0ComponentDeregisterFactory(PSUPDRVSESSION pSession, PCSUPDRVFACTORY pFactory); +SUPR0DECL(int) SUPR0ComponentQueryFactory(PSUPDRVSESSION pSession, const char *pszName, const char *pszInterfaceUuid, void **ppvFactoryIf); + + +/** @name Tracing + * @{ */ + +/** + * Tracer data associated with a provider. + */ +typedef union SUPDRVTRACERDATA +{ + /** Generic */ + uint64_t au64[2]; + + /** DTrace data. */ + struct + { + /** Provider ID. */ + uintptr_t idProvider; + /** The number of trace points provided. */ + uint32_t volatile cProvidedProbes; + /** Whether we've invalidated this bugger. */ + bool fZombie; + } DTrace; +} SUPDRVTRACERDATA; +/** Pointer to the tracer data associated with a provider. */ +typedef SUPDRVTRACERDATA *PSUPDRVTRACERDATA; + +/** + * Probe location info for ring-0. + * + * Since we cannot trust user tracepoint modules, we need to duplicate the probe + * ID and enabled flag in ring-0. + */ +typedef struct SUPDRVPROBELOC +{ + /** The probe ID. */ + uint32_t idProbe; + /** Whether it's enabled or not. */ + bool fEnabled; +} SUPDRVPROBELOC; +/** Pointer to a ring-0 probe location record. */ +typedef SUPDRVPROBELOC *PSUPDRVPROBELOC; + +/** + * Probe info for ring-0. + * + * Since we cannot trust user tracepoint modules, we need to duplicate the + * probe enable count. + */ +typedef struct SUPDRVPROBEINFO +{ + /** The number of times this probe has been enabled. */ + uint32_t volatile cEnabled; +} SUPDRVPROBEINFO; +/** Pointer to a ring-0 probe info record. */ +typedef SUPDRVPROBEINFO *PSUPDRVPROBEINFO; + +/** + * Support driver tracepoint provider core. + */ +typedef struct SUPDRVVDTPROVIDERCORE +{ + /** The tracer data member. */ + SUPDRVTRACERDATA TracerData; + /** Pointer to the provider name (a copy that's always available). */ + const char *pszName; + /** Pointer to the module name (a copy that's always available). */ + const char *pszModName; + + /** The provider descriptor. */ + struct VTGDESCPROVIDER *pDesc; + /** The VTG header. */ + struct VTGOBJHDR *pHdr; + + /** The size of the entries in the pvProbeLocsEn table. */ + uint8_t cbProbeLocsEn; + /** The actual module bit count (corresponds to cbProbeLocsEn). */ + uint8_t cBits; + /** Set if this is a Umod, otherwise clear. */ + bool fUmod; + /** Explicit alignment padding (paranoia). */ + uint8_t abAlignment[ARCH_BITS == 32 ? 1 : 5]; + + /** The probe locations used for descriptive purposes. */ + struct VTGPROBELOC const *paProbeLocsRO; + /** Pointer to the probe location array where the enable flag needs + * flipping. For kernel providers, this will always be SUPDRVPROBELOC, + * while user providers can either be 32-bit or 64-bit. Use + * cbProbeLocsEn to calculate the address of an entry. */ + void *pvProbeLocsEn; + /** Pointer to the probe array containing the enabled counts. */ + uint32_t *pacProbeEnabled; + + /** The ring-0 probe location info for user tracepoint modules. + * This is NULL if fUmod is false. */ + PSUPDRVPROBELOC paR0ProbeLocs; + /** The ring-0 probe info for user tracepoint modules. + * This is NULL if fUmod is false. */ + PSUPDRVPROBEINFO paR0Probes; + +} SUPDRVVDTPROVIDERCORE; +/** Pointer to a tracepoint provider core structure. */ +typedef SUPDRVVDTPROVIDERCORE *PSUPDRVVDTPROVIDERCORE; + +/** Pointer to a tracer registration record. */ +typedef struct SUPDRVTRACERREG const *PCSUPDRVTRACERREG; +/** + * Support driver tracer registration record. + */ +typedef struct SUPDRVTRACERREG +{ + /** Magic value (SUPDRVTRACERREG_MAGIC). */ + uint32_t u32Magic; + /** Version (SUPDRVTRACERREG_VERSION). */ + uint32_t u32Version; + + /** + * Fire off a kernel probe. + * + * @param pVtgProbeLoc The probe location record. + * @param uArg0 The first raw probe argument. + * @param uArg1 The second raw probe argument. + * @param uArg2 The third raw probe argument. + * @param uArg3 The fourth raw probe argument. + * @param uArg4 The fifth raw probe argument. + * + * @remarks SUPR0TracerFireProbe will do a tail jump thru this member, so + * no extra stack frames will be added. + * @remarks This does not take a 'this' pointer argument because it doesn't map + * well onto VTG or DTrace. + * + */ + DECLR0CALLBACKMEMBER(void, pfnProbeFireKernel, (struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2, + uintptr_t uArg3, uintptr_t uArg4)); + + /** + * Fire off a user-mode probe. + * + * @param pThis Pointer to the registration record. + * + * @param pVtgProbeLoc The probe location record. + * @param pSession The user session. + * @param pCtx The usermode context info. + * @param pVtgHdr The VTG header (read-only). + * @param pProbeLocRO The read-only probe location record . + */ + DECLR0CALLBACKMEMBER(void, pfnProbeFireUser, (PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, PCSUPDRVTRACERUSRCTX pCtx, + struct VTGOBJHDR const *pVtgHdr, struct VTGPROBELOC const *pProbeLocRO)); + + /** + * Opens up the tracer. + * + * @returns VBox status code. + * @param pThis Pointer to the registration record. + * @param pSession The session doing the opening. + * @param uCookie A cookie (magic) unique to the tracer, so it can + * fend off incompatible clients. + * @param uArg Tracer specific argument. + * @param puSessionData Pointer to the session data variable. This must be + * set to a non-zero value on success. + */ + DECLR0CALLBACKMEMBER(int, pfnTracerOpen, (PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uint32_t uCookie, uintptr_t uArg, + uintptr_t *puSessionData)); + + /** + * I/O control style tracer communication method. + * + * + * @returns VBox status code. + * @param pThis Pointer to the registration record. + * @param pSession The session. + * @param uSessionData The session data value. + * @param uCmd The tracer specific command. + * @param uArg The tracer command specific argument. + * @param piRetVal The tracer specific return value. + */ + DECLR0CALLBACKMEMBER(int, pfnTracerIoCtl, (PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData, + uintptr_t uCmd, uintptr_t uArg, int32_t *piRetVal)); + + /** + * Cleans up data the tracer has associated with a session. + * + * @param pThis Pointer to the registration record. + * @param pSession The session handle. + * @param uSessionData The data assoicated with the session. + */ + DECLR0CALLBACKMEMBER(void, pfnTracerClose, (PCSUPDRVTRACERREG pThis, PSUPDRVSESSION pSession, uintptr_t uSessionData)); + + /** + * Registers a provider. + * + * @returns VBox status code. + * @param pThis Pointer to the registration record. + * @param pCore The provider core data. + * + * @todo Kernel vs. Userland providers. + */ + DECLR0CALLBACKMEMBER(int, pfnProviderRegister, (PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)); + + /** + * Attempts to deregisters a provider. + * + * @returns VINF_SUCCESS or VERR_TRY_AGAIN. If the latter, the provider + * should be made as harmless as possible before returning as the + * VTG object and associated code will be unloaded upon return. + * + * @param pThis Pointer to the registration record. + * @param pCore The provider core data. + */ + DECLR0CALLBACKMEMBER(int, pfnProviderDeregister, (PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)); + + /** + * Make another attempt at unregister a busy provider. + * + * @returns VINF_SUCCESS or VERR_TRY_AGAIN. + * @param pThis Pointer to the registration record. + * @param pCore The provider core data. + */ + DECLR0CALLBACKMEMBER(int, pfnProviderDeregisterZombie, (PCSUPDRVTRACERREG pThis, PSUPDRVVDTPROVIDERCORE pCore)); + + /** End marker (SUPDRVTRACERREG_MAGIC). */ + uintptr_t uEndMagic; +} SUPDRVTRACERREG; + +/** Tracer magic (Kenny Garrett). */ +#define SUPDRVTRACERREG_MAGIC UINT32_C(0x19601009) +/** Tracer registration structure version. */ +#define SUPDRVTRACERREG_VERSION RT_MAKE_U32(0, 1) + +/** Pointer to a trace helper structure. */ +typedef struct SUPDRVTRACERHLP const *PCSUPDRVTRACERHLP; +/** + * Helper structure. + */ +typedef struct SUPDRVTRACERHLP +{ + /** The structure version (SUPDRVTRACERHLP_VERSION). */ + uintptr_t uVersion; + + /** @todo ... */ + + /** End marker (SUPDRVTRACERHLP_VERSION) */ + uintptr_t uEndVersion; +} SUPDRVTRACERHLP; +/** Tracer helper structure version. */ +#define SUPDRVTRACERHLP_VERSION RT_MAKE_U32(0, 1) + +SUPR0DECL(int) SUPR0TracerRegisterImpl(void *hMod, PSUPDRVSESSION pSession, PCSUPDRVTRACERREG pReg, PCSUPDRVTRACERHLP *ppHlp); +SUPR0DECL(int) SUPR0TracerDeregisterImpl(void *hMod, PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0TracerRegisterDrv(PSUPDRVSESSION pSession, struct VTGOBJHDR *pVtgHdr, const char *pszName); +SUPR0DECL(void) SUPR0TracerDeregisterDrv(PSUPDRVSESSION pSession); +SUPR0DECL(int) SUPR0TracerRegisterModule(void *hMod, struct VTGOBJHDR *pVtgHdr); +SUPR0DECL(void) SUPR0TracerFireProbe(struct VTGPROBELOC *pVtgProbeLoc, uintptr_t uArg0, uintptr_t uArg1, uintptr_t uArg2, + uintptr_t uArg3, uintptr_t uArg4); +SUPR0DECL(void) SUPR0TracerUmodProbeFire(PSUPDRVSESSION pSession, PSUPDRVTRACERUSRCTX pCtx); +/** @} */ + + +/** @defgroup grp_sup_r0_idc The IDC Interface + * @{ + */ + +/** The current SUPDRV IDC version. + * This follows the usual high word / low word rules, i.e. high word is the + * major number and it signifies incompatible interface changes. */ +#define SUPDRV_IDC_VERSION UINT32_C(0x00010000) + +/** + * Inter-Driver Communication Handle. + */ +typedef union SUPDRVIDCHANDLE +{ + /** Padding for opaque usage. + * Must be greater or equal in size than the private struct. */ + void *apvPadding[4]; +#ifdef SUPDRVIDCHANDLEPRIVATE_DECLARED + /** The private view. */ + struct SUPDRVIDCHANDLEPRIVATE s; +#endif +} SUPDRVIDCHANDLE; +/** Pointer to a handle. */ +typedef SUPDRVIDCHANDLE *PSUPDRVIDCHANDLE; + +SUPR0DECL(int) SUPR0IdcOpen(PSUPDRVIDCHANDLE pHandle, uint32_t uReqVersion, uint32_t uMinVersion, + uint32_t *puSessionVersion, uint32_t *puDriverVersion, uint32_t *puDriverRevision); +SUPR0DECL(int) SUPR0IdcCall(PSUPDRVIDCHANDLE pHandle, uint32_t iReq, void *pvReq, uint32_t cbReq); +SUPR0DECL(int) SUPR0IdcClose(PSUPDRVIDCHANDLE pHandle); +SUPR0DECL(PSUPDRVSESSION) SUPR0IdcGetSession(PSUPDRVIDCHANDLE pHandle); +SUPR0DECL(int) SUPR0IdcComponentRegisterFactory(PSUPDRVIDCHANDLE pHandle, PCSUPDRVFACTORY pFactory); +SUPR0DECL(int) SUPR0IdcComponentDeregisterFactory(PSUPDRVIDCHANDLE pHandle, PCSUPDRVFACTORY pFactory); + +/** @} */ + +/** @name Ring-0 module entry points. + * + * These can be exported by ring-0 modules SUP are told to load. + * + * @{ */ +DECLEXPORT(int) ModuleInit(void *hMod); +DECLEXPORT(void) ModuleTerm(void *hMod); +/** @} */ + + +/** @} */ +#endif + + +/** @name Trust Anchors and Certificates + * @{ */ + +/** + * Trust anchor table entry (in generated Certificates.cpp). + */ +typedef struct SUPTAENTRY +{ + /** Pointer to the raw bytes. */ + const unsigned char *pch; + /** Number of bytes. */ + unsigned cb; +} SUPTAENTRY; +/** Pointer to a trust anchor table entry. */ +typedef SUPTAENTRY const *PCSUPTAENTRY; + +/** Macro for simplifying generating the trust anchor tables. */ +#define SUPTAENTRY_GEN(a_abTA) { &a_abTA[0], sizeof(a_abTA) } + +/** All certificates we know. */ +extern SUPTAENTRY const g_aSUPAllTAs[]; +/** Number of entries in g_aSUPAllTAs. */ +extern unsigned const g_cSUPAllTAs; + +/** Software publisher certificate roots (Authenticode). */ +extern SUPTAENTRY const g_aSUPSpcRootTAs[]; +/** Number of entries in g_aSUPSpcRootTAs. */ +extern unsigned const g_cSUPSpcRootTAs; + +/** Kernel root certificates used by Windows. */ +extern SUPTAENTRY const g_aSUPNtKernelRootTAs[]; +/** Number of entries in g_aSUPNtKernelRootTAs. */ +extern unsigned const g_cSUPNtKernelRootTAs; + +/** Timestamp root certificates trusted by Windows. */ +extern SUPTAENTRY const g_aSUPTimestampTAs[]; +/** Number of entries in g_aSUPTimestampTAs. */ +extern unsigned const g_cSUPTimestampTAs; + +/** Root certificates trusted by Apple code signing. */ +extern SUPTAENTRY const g_aSUPAppleRootTAs[]; +/** Number of entries in g_cSUPAppleRootTAs. */ +extern unsigned const g_cSUPAppleRootTAs; + +/** TAs we trust (the build certificate, Oracle VirtualBox). */ +extern SUPTAENTRY const g_aSUPTrustedTAs[]; +/** Number of entries in g_aSUPTrustedTAs. */ +extern unsigned const g_cSUPTrustedTAs; + +/** Supplemental certificates, like cross signing certificates. */ +extern SUPTAENTRY const g_aSUPSupplementalTAs[]; +/** Number of entries in g_aSUPTrustedTAs. */ +extern unsigned const g_cSUPSupplementalTAs; + +/** The build certificate. */ +extern const unsigned char g_abSUPBuildCert[]; +/** The size of the build certificate. */ +extern const unsigned g_cbSUPBuildCert; + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_sup_h */ + diff --git a/include/VBox/sup.mac b/include/VBox/sup.mac new file mode 100644 index 00000000..5b1b5f00 --- /dev/null +++ b/include/VBox/sup.mac @@ -0,0 +1,157 @@ +; $Id: sup.mac $ +;; @file +; SUP - Support Library, assembly definitions. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_sup_mac +%define ___VBox_sup_mac + +struc SUPGIPCPU + .u32TransactionId resd 1 + .u32UpdateIntervalTSC resd 1 + .u64NanoTS resq 1 + .u64TSC resq 1 + .u64CpuHz resq 1 + .i64TSCDelta resq 1 + .cErrors resd 1 + .iTSCHistoryHead resd 1 + .au32TSCHistory resd 8 + .u32PrevUpdateIntervalNS resd 1 + .u32Reserved resd 1 + .u64TSCSample resq 1 + .au32Reserved1 resd 3 + .enmState resd 1 + .idCpu resd 1 + .iCpuSet resw 1 + .iCpuGroup resw 1 + .iCpuGroupMember resw 1 + .idApic resw 1 + .iReservedForNumaNode resd 1 +endstruc + +%define SUPGIPUSETSCDELTA_NOT_APPLICABLE 0 +%define SUPGIPUSETSCDELTA_ZERO_CLAIMED 1 +%define SUPGIPUSETSCDELTA_PRACTICALLY_ZERO 2 +%define SUPGIPUSETSCDELTA_ROUGHLY_ZERO 3 +%define SUPGIPUSETSCDELTA_NOT_ZERO 4 + +%define SUPGIPGETCPU_APIC_ID 1 +%define SUPGIPGETCPU_RDTSCP_MASK_MAX_SET_CPUS 2 +%define SUPGIPGETCPU_IDTR_LIMIT_MASK_MAX_SET_CPUS 4 +%define SUPGIPGETCPU_RDTSCP_GROUP_IN_CH_NUMBER_IN_CL 8 +%define SUPGIPGETCPU_APIC_ID_EXT_0B 16 +%define SUPGIPGETCPU_APIC_ID_EXT_8000001E 32 + + +%define SUPGLOBALINFOPAGE_MAGIC 0x19590106 +struc SUPGLOBALINFOPAGE + .u32Magic resd 1 + .u32Version resd 1 + .u32Mode resd 1 + .cCpus resw 1 + .cPages resw 1 + .u32UpdateHz resd 1 + .u32UpdateIntervalNS resd 1 + .u64NanoTSLastUpdateHz resq 1 + .u64CpuHz resq 1 + .cOnlineCpus resw 1 + .cPresentCpus resw 1 + .cPossibleCpus resw 1 + .cPossibleCpuGroups resw 1 + .idCpuMax resd 1 + .enmUseTscDelta resd 1 + .fGetGipCpu resd 1 + .fFlags resd 1 + .OnlineCpuSet resq 16 + .PresentCpuSet resq 16 + .PossibleCpuSet resq 16 + .au32Padding1 resd 48 + .aiCpuFromApicId resw 4096 + .aiCpuFromCpuSetIdx resw 1024 + .aoffCpuGroup resd 256 + .aCPUs resb SUPGIPCPU_size +endstruc + +struc SUPDRVTRACERUSRCTX32 + .idProbe resd 1 + .cBits resb 1 + .abReserved resb 3 + .u.X86.uVtgProbeLoc resd 1 + .u.X86.aArgs resd 20 + .u.X86.eip resd 1 + .u.X86.eflags resd 1 + .u.X86.eax resd 1 + .u.X86.ecx resd 1 + .u.X86.edx resd 1 + .u.X86.ebx resd 1 + .u.X86.esp resd 1 + .u.X86.ebp resd 1 + .u.X86.esi resd 1 + .u.X86.edi resd 1 + .u.X86.cs resw 1 + .u.X86.ss resw 1 + .u.X86.ds resw 1 + .u.X86.es resw 1 + .u.X86.fs resw 1 + .u.X86.gs resw 1 +endstruc + +struc SUPDRVTRACERUSRCTX64 + .idProbe resd 1 + .cBits resb 1 + .abReserved resb 3 + .u.Amd64.uVtgProbeLoc resq 1 + .u.Amd64.aArgs resq 10 + .u.Amd64.rip resq 1 + .u.Amd64.rflags resq 1 + .u.Amd64.rax resq 1 + .u.Amd64.rcx resq 1 + .u.Amd64.rdx resq 1 + .u.Amd64.rbx resq 1 + .u.Amd64.rsp resq 1 + .u.Amd64.rbp resq 1 + .u.Amd64.rsi resq 1 + .u.Amd64.rdi resq 1 + .u.Amd64.r8 resq 1 + .u.Amd64.r9 resq 1 + .u.Amd64.r10 resq 1 + .u.Amd64.r11 resq 1 + .u.Amd64.r12 resq 1 + .u.Amd64.r13 resq 1 + .u.Amd64.r14 resq 1 + .u.Amd64.r15 resq 1 +endstruc + +%endif + diff --git a/include/VBox/types.h b/include/VBox/types.h new file mode 100644 index 00000000..9b7e1cf5 --- /dev/null +++ b/include/VBox/types.h @@ -0,0 +1,1258 @@ +/** @file + * VirtualBox - Types. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_types_h +#define VBOX_INCLUDED_types_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_types VBox Basic Types + * @{ + */ + + +/** @defgroup grp_types_both Common Guest and Host Context Basic Types + * @{ + */ + + +/** @defgroup grp_types_hc Host Context Basic Types + * @{ + */ + +/** @} */ + + +/** @defgroup grp_types_gc Guest Context Basic Types + * @{ + */ + +/** @} */ + + +/** Pointer to per support driver session data. + * (The data is a R0 entity and private to the the R0 SUP part. All + * other should consider this a sort of handle.) */ +typedef R0PTRTYPE(struct SUPDRVSESSION *) PSUPDRVSESSION; + +/** Event semaphore handle. Ring-0 / ring-3. */ +typedef R0PTRTYPE(struct SUPSEMEVENTHANDLE *) SUPSEMEVENT; +/** Pointer to an event semaphore handle. */ +typedef SUPSEMEVENT *PSUPSEMEVENT; +/** Nil event semaphore handle. */ +#define NIL_SUPSEMEVENT ((SUPSEMEVENT)0) + +/** Multiple release event semaphore handle. Ring-0 / ring-3. */ +typedef R0PTRTYPE(struct SUPSEMEVENTMULTIHANDLE *) SUPSEMEVENTMULTI; +/** Pointer to an multiple release event semaphore handle. */ +typedef SUPSEMEVENTMULTI *PSUPSEMEVENTMULTI; +/** Nil multiple release event semaphore handle. */ +#define NIL_SUPSEMEVENTMULTI ((SUPSEMEVENTMULTI)0) + + +/** Pointer to a ring-3 VMM API vtable. */ +typedef R3PTRTYPE(const struct VMMR3VTABLE *) PCVMMR3VTABLE; + +/** Pointer to a VM. */ +typedef struct VM *PVM; +/** Pointer to a const VM. */ +typedef const struct VM *PCVM; +/** Pointer to a VM - Ring-0 Ptr. */ +typedef R0PTRTYPE(struct VM *) PVMR0; +/** Pointer to a VM - Ring-3 Ptr. */ +typedef R3PTRTYPE(struct VM *) PVMR3; +/** Pointer to a VM - RC Ptr. */ +typedef RCPTRTYPE(struct VM *) PVMRC; + +/** Pointer to a virtual CPU structure. */ +typedef struct VMCPU * PVMCPU; +/** Pointer to a const virtual CPU structure. */ +typedef const struct VMCPU * PCVMCPU; +/** Pointer to a virtual CPU structure - Ring-3 Ptr. */ +typedef R3PTRTYPE(struct VMCPU *) PVMCPUR3; +/** Pointer to a virtual CPU structure - Ring-0 Ptr. */ +typedef R0PTRTYPE(struct VMCPU *) PVMCPUR0; +/** Pointer to a virtual CPU structure - RC Ptr. */ +typedef RCPTRTYPE(struct VMCPU *) PVMCPURC; + +/** Pointer to a ring-0 (global) VM structure. */ +typedef R0PTRTYPE(struct GVM *) PGVM; +/** Pointer to a const ring-0 (global) VM structure. */ +typedef R0PTRTYPE(const struct GVM *) PCGVM; +/** Pointer to a GVMCPU structure. */ +typedef R0PTRTYPE(struct GVMCPU *) PGVMCPU; +/** Pointer to a const GVMCPU structure. */ +typedef R0PTRTYPE(struct GVMCPU const *) PCGVMCPU; + +/** Pointer to a ring-3 (user mode) VM structure. */ +typedef R3PTRTYPE(struct UVM *) PUVM; + +/** Pointer to a ring-3 (user mode) VMCPU structure. */ +typedef R3PTRTYPE(struct UVMCPU *) PUVMCPU; + +/** Pointer to a context specific VM derived structure. + * This is PGVM in ring-0 and plain PVM in ring-3. */ +#ifdef IN_RING0 +typedef PGVM PVMCC; +#else +typedef PVM PVMCC; +#endif +/** Pointer to a const context specific VM derived structure. + * This is PCGVM in ring-0 and plain PCVM in ring-3. */ +#ifdef IN_RING0 +typedef PCGVM PCVMCC; +#else +typedef PCVM PCVMCC; +#endif +/** Pointer to a context specific VMCPUM derived structure. + * This is PGVMCPU in ring-0 and plain PVMCPU in ring-3. */ +#ifdef IN_RING0 +typedef PGVMCPU PVMCPUCC; +#else +typedef PVMCPU PVMCPUCC; +#endif +/** Pointer to a const context specific VMCPU derived structure. + * This is PCGVMCPU in ring-0 and plain PCVMCPU in ring-3. */ +#ifdef IN_RING0 +typedef PCGVMCPU PCVMCPUCC; +#else +typedef PCVMCPU PCVMCPUCC; +#endif + +/** Virtual CPU ID. */ +typedef uint32_t VMCPUID; +/** Pointer to a virtual CPU ID. */ +typedef VMCPUID *PVMCPUID; +/** @name Special CPU ID values. + * Most of these are for request scheduling. + * + * @{ */ +/** All virtual CPUs. */ +#define VMCPUID_ALL UINT32_C(0xfffffff2) +/** All virtual CPUs, descending order. */ +#define VMCPUID_ALL_REVERSE UINT32_C(0xfffffff3) +/** Any virtual CPU. + * Intended for scheduling a VM request or some other task. */ +#define VMCPUID_ANY UINT32_C(0xfffffff4) +/** Any virtual CPU; always queue for future execution. + * Intended for scheduling a VM request or some other task. */ +#define VMCPUID_ANY_QUEUE UINT32_C(0xfffffff5) +/** The NIL value. */ +#define NIL_VMCPUID UINT32_C(0xfffffffd) +/** @} */ + +/** + * Virtual CPU set. + */ +typedef struct VMCPUSET +{ + /** The bitmap data. */ + uint32_t au32Bitmap[8 /*256/32*/]; +} VMCPUSET; +/** Pointer to a Virtual CPU set. */ +typedef VMCPUSET *PVMCPUSET; +/** Pointer to a const Virtual CPU set. */ +typedef VMCPUSET const *PCVMCPUSET; + + +/** + * VM State + */ +typedef enum VMSTATE +{ + /** The VM is being created. */ + VMSTATE_CREATING = 0, + /** The VM is created. */ + VMSTATE_CREATED, + /** The VM state is being loaded from file. */ + VMSTATE_LOADING, + /** The VM is being powered on */ + VMSTATE_POWERING_ON, + /** The VM is being resumed. */ + VMSTATE_RESUMING, + /** The VM is runnning. */ + VMSTATE_RUNNING, + /** Live save: The VM is running and the state is being saved. */ + VMSTATE_RUNNING_LS, + /** Fault Tolerance: The VM is running and the state is being synced. */ + VMSTATE_RUNNING_FT, + /** The VM is being reset. */ + VMSTATE_RESETTING, + /** Live save: The VM is being reset and immediately suspended. */ + VMSTATE_RESETTING_LS, + /** The VM is being soft/warm reset. */ + VMSTATE_SOFT_RESETTING, + /** Live save: The VM is being soft/warm reset (not suspended afterwards). */ + VMSTATE_SOFT_RESETTING_LS, + /** The VM is being suspended. */ + VMSTATE_SUSPENDING, + /** Live save: The VM is being suspended during a live save operation, either as + * part of the normal flow or VMR3Reset. */ + VMSTATE_SUSPENDING_LS, + /** Live save: The VM is being suspended by VMR3Suspend during live save. */ + VMSTATE_SUSPENDING_EXT_LS, + /** The VM is suspended. */ + VMSTATE_SUSPENDED, + /** Live save: The VM has been suspended and is waiting for the live save + * operation to move on. */ + VMSTATE_SUSPENDED_LS, + /** Live save: The VM has been suspended by VMR3Suspend during a live save. */ + VMSTATE_SUSPENDED_EXT_LS, + /** The VM is suspended and its state is being saved by EMT(0). (See SSM) */ + VMSTATE_SAVING, + /** The VM is being debugged. (See DBGF.) */ + VMSTATE_DEBUGGING, + /** Live save: The VM is being debugged while the live phase is going on. */ + VMSTATE_DEBUGGING_LS, + /** The VM is being powered off. */ + VMSTATE_POWERING_OFF, + /** Live save: The VM is being powered off and the save cancelled. */ + VMSTATE_POWERING_OFF_LS, + /** The VM is switched off, awaiting destruction. */ + VMSTATE_OFF, + /** Live save: Waiting for cancellation and transition to VMSTATE_OFF. */ + VMSTATE_OFF_LS, + /** The VM is powered off because of a fatal error. */ + VMSTATE_FATAL_ERROR, + /** Live save: Waiting for cancellation and transition to FatalError. */ + VMSTATE_FATAL_ERROR_LS, + /** The VM is in guru meditation over a fatal failure. */ + VMSTATE_GURU_MEDITATION, + /** Live save: Waiting for cancellation and transition to GuruMeditation. */ + VMSTATE_GURU_MEDITATION_LS, + /** The VM is screwed because of a failed state loading. */ + VMSTATE_LOAD_FAILURE, + /** The VM is being destroyed. */ + VMSTATE_DESTROYING, + /** Terminated. */ + VMSTATE_TERMINATED, + /** hack forcing the size of the enum to 32-bits. */ + VMSTATE_MAKE_32BIT_HACK = 0x7fffffff +} VMSTATE; + +/** @def VBOXSTRICTRC_STRICT_ENABLED + * Indicates that VBOXSTRICTRC is in strict mode. + */ +#if defined(__cplusplus) \ + && ARCH_BITS == 64 /* cdecl requires classes and structs as hidden params. */ \ + && !defined(_MSC_VER) /* trouble similar to 32-bit gcc. */ \ + && ( defined(RT_STRICT) \ + || defined(VBOX_STRICT) \ + || defined(DEBUG) \ + || defined(DOXYGEN_RUNNING) ) +# define VBOXSTRICTRC_STRICT_ENABLED 1 +#endif + +/** We need RTERR_STRICT_RC. */ +#if defined(VBOXSTRICTRC_STRICT_ENABLED) && !defined(RTERR_STRICT_RC) +# define RTERR_STRICT_RC 1 +#endif + +/** + * Strict VirtualBox status code. + * + * This is normally an 32-bit integer and the only purpose of the type is to + * highlight the special handling that is required. But in strict build it is a + * class that causes compilation and runtime errors for some of the incorrect + * handling. + */ +#ifdef VBOXSTRICTRC_STRICT_ENABLED +struct VBOXSTRICTRC +{ +protected: + /** The status code. */ + int32_t m_rc; + +public: + /** Default constructor setting the status to VERR_IPE_UNINITIALIZED_STATUS. */ + VBOXSTRICTRC() +#ifdef VERR_IPE_UNINITIALIZED_STATUS + : m_rc(VERR_IPE_UNINITIALIZED_STATUS) +#else + : m_rc(-233 /*VERR_IPE_UNINITIALIZED_STATUS*/) +#endif + { + } + + /** Constructor for normal integer status codes. */ + VBOXSTRICTRC(int32_t const rc) + : m_rc(rc) + { + } + + /** Getter that VBOXSTRICTRC_VAL can use. */ + int32_t getValue() const { return m_rc; } + + /** @name Comparison operators + * @{ */ + bool operator==(int32_t rc) const { return m_rc == rc; } + bool operator!=(int32_t rc) const { return m_rc != rc; } + bool operator<=(int32_t rc) const { return m_rc <= rc; } + bool operator>=(int32_t rc) const { return m_rc >= rc; } + bool operator<(int32_t rc) const { return m_rc < rc; } + bool operator>(int32_t rc) const { return m_rc > rc; } + + bool operator==(const VBOXSTRICTRC &rRc) const { return m_rc == rRc.m_rc; } + bool operator!=(const VBOXSTRICTRC &rRc) const { return m_rc != rRc.m_rc; } + bool operator<=(const VBOXSTRICTRC &rRc) const { return m_rc <= rRc.m_rc; } + bool operator>=(const VBOXSTRICTRC &rRc) const { return m_rc >= rRc.m_rc; } + bool operator<(const VBOXSTRICTRC &rRc) const { return m_rc < rRc.m_rc; } + bool operator>(const VBOXSTRICTRC &rRc) const { return m_rc > rRc.m_rc; } + /** @} */ + + /** Special automatic cast for RT_SUCCESS_NP. */ + operator RTErrStrictType2() const { return RTErrStrictType2(m_rc); } + +private: + /** @name Constructors that will prevent some of the bad types. + * @{ */ + VBOXSTRICTRC(uint8_t rc) : m_rc(-999) { NOREF(rc); } + VBOXSTRICTRC(uint16_t rc) : m_rc(-999) { NOREF(rc); } + VBOXSTRICTRC(uint32_t rc) : m_rc(-999) { NOREF(rc); } + VBOXSTRICTRC(uint64_t rc) : m_rc(-999) { NOREF(rc); } + + VBOXSTRICTRC(int8_t rc) : m_rc(-999) { NOREF(rc); } + VBOXSTRICTRC(int16_t rc) : m_rc(-999) { NOREF(rc); } + VBOXSTRICTRC(int64_t rc) : m_rc(-999) { NOREF(rc); } + /** @} */ +}; +# ifdef _MSC_VER +# pragma warning(disable:4190) +# endif +#else +typedef int32_t VBOXSTRICTRC; +#endif + +/** @def VBOXSTRICTRC_VAL + * Explicit getter. + * @param rcStrict The strict VirtualBox status code. + */ +#ifdef VBOXSTRICTRC_STRICT_ENABLED +# define VBOXSTRICTRC_VAL(rcStrict) ( (rcStrict).getValue() ) +#else +# define VBOXSTRICTRC_VAL(rcStrict) (rcStrict) +#endif + +/** @def VBOXSTRICTRC_TODO + * Returns that needs dealing with. + * @param rcStrict The strict VirtualBox status code. + */ +#define VBOXSTRICTRC_TODO(rcStrict) VBOXSTRICTRC_VAL(rcStrict) + + +/** A cross context I/O port range handle. */ +typedef uint64_t IOMIOPORTHANDLE; +/** Pointer to a cross context I/O port handle. */ +typedef IOMIOPORTHANDLE *PIOMIOPORTHANDLE; +/** A NIL I/O port handle. */ +#define NIL_IOMIOPORTHANDLE ((uint64_t)UINT64_MAX) + +/** A cross context MMIO range handle. */ +typedef uint64_t IOMMMIOHANDLE; +/** Pointer to a cross context MMIO handle. */ +typedef IOMMMIOHANDLE *PIOMMMIOHANDLE; +/** A NIL MMIO handle. */ +#define NIL_IOMMMIOHANDLE ((uint64_t)UINT64_MAX) + +/** A cross context MMIO2 range handle. */ +typedef uint64_t PGMMMIO2HANDLE; +/** Pointer to a cross context MMIO2 handle. */ +typedef PGMMMIO2HANDLE *PPGMMMIO2HANDLE; +/** A NIL MMIO2 handle. */ +#define NIL_PGMMMIO2HANDLE ((uint64_t)UINT64_MAX) + +/** Pointer to a PDM Base Interface. */ +typedef struct PDMIBASE *PPDMIBASE; +/** Pointer to a pointer to a PDM Base Interface. */ +typedef PPDMIBASE *PPPDMIBASE; + +/** Pointer to a PDM device instance for the current context. */ +#ifdef IN_RING3 +typedef struct PDMDEVINSR3 *PPDMDEVINS; +#elif defined(IN_RING0) || defined(DOXYGEN_RUNNING) +typedef struct PDMDEVINSR0 *PPDMDEVINS; +#else +typedef struct PDMDEVINSRC *PPDMDEVINS; +#endif +/** Pointer to a pointer a PDM device instance for the current context. */ +typedef PPDMDEVINS *PPPDMDEVINS; +/** R3 pointer to a PDM device instance. */ +typedef R3PTRTYPE(struct PDMDEVINSR3 *) PPDMDEVINSR3; +/** R0 pointer to a PDM device instance. */ +typedef R0PTRTYPE(struct PDMDEVINSR0 *) PPDMDEVINSR0; +/** RC pointer to a PDM device instance. */ +typedef RCPTRTYPE(struct PDMDEVINSRC *) PPDMDEVINSRC; + +/** Pointer to a PDM PCI device structure. */ +typedef struct PDMPCIDEV *PPDMPCIDEV; +/** Pointer to a const PDM PCI device structure. */ +typedef const struct PDMPCIDEV *PCPDMPCIDEV; + +/** Pointer to a PDM USB Device Instance. */ +typedef struct PDMUSBINS *PPDMUSBINS; +/** Pointer to a pointer to a PDM USB Device Instance. */ +typedef PPDMUSBINS *PPPDMUSBINS; + +/** Pointer to a PDM Driver Instance. */ +typedef struct PDMDRVINS *PPDMDRVINS; +/** Pointer to a pointer to a PDM Driver Instance. */ +typedef PPDMDRVINS *PPPDMDRVINS; +/** R3 pointer to a PDM Driver Instance. */ +typedef R3PTRTYPE(PPDMDRVINS) PPDMDRVINSR3; +/** R0 pointer to a PDM Driver Instance. */ +typedef R0PTRTYPE(PPDMDRVINS) PPDMDRVINSR0; +/** RC pointer to a PDM Driver Instance. */ +typedef RCPTRTYPE(PPDMDRVINS) PPDMDRVINSRC; + +/** Pointer to a PDM Service Instance. */ +typedef struct PDMSRVINS *PPDMSRVINS; +/** Pointer to a pointer to a PDM Service Instance. */ +typedef PPDMSRVINS *PPPDMSRVINS; + +/** Pointer to a PDM critical section. */ +typedef union PDMCRITSECT *PPDMCRITSECT; +/** Pointer to a const PDM critical section. */ +typedef const union PDMCRITSECT *PCPDMCRITSECT; + +/** Pointer to a PDM read/write critical section. */ +typedef union PDMCRITSECTRW *PPDMCRITSECTRW; +/** Pointer to a const PDM read/write critical section. */ +typedef union PDMCRITSECTRW const *PCPDMCRITSECTRW; + +/** PDM queue handle. */ +typedef uint64_t PDMQUEUEHANDLE; +/** Pointer to a PDM queue handle. */ +typedef PDMQUEUEHANDLE *PPDMQUEUEHANDLE; +/** NIL PDM queue handle. */ +#define NIL_PDMQUEUEHANDLE ((PDMQUEUEHANDLE)UINT64_MAX) + +/** R3 pointer to a timer. */ +typedef R3PTRTYPE(struct TMTIMER *) PTMTIMERR3; +/** Pointer to a R3 pointer to a timer. */ +typedef PTMTIMERR3 *PPTMTIMERR3; + +/** R0 pointer to a timer. */ +typedef R0PTRTYPE(struct TMTIMER *) PTMTIMERR0; +/** Pointer to a R3 pointer to a timer. */ +typedef PTMTIMERR0 *PPTMTIMERR0; + +/** RC pointer to a timer. */ +typedef RCPTRTYPE(struct TMTIMER *) PTMTIMERRC; +/** Pointer to a RC pointer to a timer. */ +typedef PTMTIMERRC *PPTMTIMERRC; + +/** Pointer to a timer. */ +typedef CTX_SUFF(PTMTIMER) PTMTIMER; +/** Pointer to a pointer to a timer. */ +typedef PTMTIMER *PPTMTIMER; + +/** A cross context timer handle. */ +typedef uint64_t TMTIMERHANDLE; +/** Pointer to a cross context timer handle. */ +typedef TMTIMERHANDLE *PTMTIMERHANDLE; +/** A NIL timer handle. */ +#define NIL_TMTIMERHANDLE ((uint64_t)UINT64_MAX) + +/** SSM Operation handle. */ +typedef struct SSMHANDLE *PSSMHANDLE; +/** Pointer to a const SSM stream method table. */ +typedef struct SSMSTRMOPS const *PCSSMSTRMOPS; + +/** Pointer to a CPUMCTX. */ +typedef struct CPUMCTX *PCPUMCTX; +/** Pointer to a const CPUMCTX. */ +typedef const struct CPUMCTX *PCCPUMCTX; + +/** Pointer to a selector register. */ +typedef struct CPUMSELREG *PCPUMSELREG; +/** Pointer to a const selector register. */ +typedef const struct CPUMSELREG *PCCPUMSELREG; + +/** Pointer to selector hidden registers. + * @deprecated Replaced by PCPUMSELREG */ +typedef struct CPUMSELREG *PCPUMSELREGHID; +/** Pointer to const selector hidden registers. + * @deprecated Replaced by PCCPUMSELREG */ +typedef const struct CPUMSELREG *PCCPUMSELREGHID; + +/** A cross context DBGF tracer event source handle. */ +typedef uint64_t DBGFTRACEREVTSRC; +/** Pointer to a cross context DBGF tracer event source handle. */ +typedef DBGFTRACEREVTSRC *PDBGFTRACEREVTSRC; +/** A NIL DBGF tracer event source handle. */ +#define NIL_DBGFTRACEREVTSRC ((uint64_t)UINT64_MAX) + +/** Pointer to a DBGF tracer instance for the current context. */ +#ifdef IN_RING3 +typedef struct DBGFTRACERINSR3 *PDBGFTRACERINSCC; +#elif defined(IN_RING0) || defined(DOXYGEN_RUNNING) +typedef struct DBGFTRACERINSR0 *PDBGFTRACERINSCC; +#else +typedef struct DBGFTRACERINSRC *PDBGFTRACERINSCC; +#endif +/** Pointer to a pointer a DBGF tracer instance for the current context. */ +typedef PDBGFTRACERINSCC *PPDBGFTRACERINSCC; +/** R3 pointer to a DBGF tracer instance. */ +typedef R3PTRTYPE(struct DBGFTRACERINSR3 *) PDBGFTRACERINSR3; +/** R0 pointer to a DBGF tracer instance. */ +typedef R0PTRTYPE(struct DBGFTRACERINSR0 *) PDBGFTRACERINSR0; +/** RC pointer to a DBGF tracer instance. */ +typedef RCPTRTYPE(struct DBGFTRACERINSRC *) PDBGFTRACERINSRC; + +/** A cross context DBGF breakpoint owner handle. */ +typedef uint32_t DBGFBPOWNER; +/** Pointer to a cross context DBGF breakpoint owner handle. */ +typedef DBGFBPOWNER *PDBGFBPOWNER; +/** A NIL DBGF breakpoint owner handle. */ +#define NIL_DBGFBPOWNER ((uint32_t)UINT32_MAX) + +/** A cross context DBGF breakpoint handle. */ +typedef uint32_t DBGFBP; +/** Pointer to a cross context DBGF breakpoint handle. */ +typedef DBGFBP *PDBGFBP; +/** A NIL DBGF breakpoint handle. */ +#define NIL_DBGFBP ((uint32_t)UINT32_MAX) + +/** A sample report handle. */ +typedef struct DBGFSAMPLEREPORTINT *DBGFSAMPLEREPORT; +/** Pointer to a sample report handle. */ +typedef DBGFSAMPLEREPORT *PDBGFSAMPLEREPORT; +/** @} */ + + +/** @defgroup grp_types_idt Interrupt Descriptor Table Entry. + * @todo This all belongs in x86.h! + * @{ */ + +/** @todo VBOXIDT -> VBOXDESCIDT, skip the complex variations. We'll never use them. */ + +/** IDT Entry, Task Gate view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE_TASKGATE +{ + /** Reserved. */ + unsigned u16Reserved1 : 16; + /** Task Segment Selector. */ + unsigned u16TSS : 16; + /** More reserved. */ + unsigned u8Reserved2 : 8; + /** Fixed value bit 0 - Set to 1. */ + unsigned u1Fixed0 : 1; + /** Busy bit. */ + unsigned u1Busy : 1; + /** Fixed value bit 2 - Set to 1. */ + unsigned u1Fixed1 : 1; + /** Fixed value bit 3 - Set to 0. */ + unsigned u1Fixed2 : 1; + /** Fixed value bit 4 - Set to 0. */ + unsigned u1Fixed3 : 1; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** Reserved. */ + unsigned u16Reserved3 : 16; +} VBOXIDTE_TASKGATE; +#pragma pack() +/** Pointer to IDT Entry, Task gate view. */ +typedef VBOXIDTE_TASKGATE *PVBOXIDTE_TASKGATE; + + +/** IDT Entry, Intertupt gate view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE_INTERRUPTGATE +{ + /** Low offset word. */ + unsigned u16OffsetLow : 16; + /** Segment Selector. */ + unsigned u16SegSel : 16; + /** Reserved. */ + unsigned u5Reserved2 : 5; + /** Fixed value bit 0 - Set to 0. */ + unsigned u1Fixed0 : 1; + /** Fixed value bit 1 - Set to 0. */ + unsigned u1Fixed1 : 1; + /** Fixed value bit 2 - Set to 0. */ + unsigned u1Fixed2 : 1; + /** Fixed value bit 3 - Set to 0. */ + unsigned u1Fixed3 : 1; + /** Fixed value bit 4 - Set to 1. */ + unsigned u1Fixed4 : 1; + /** Fixed value bit 5 - Set to 1. */ + unsigned u1Fixed5 : 1; + /** Gate size, 1 = 32 bits, 0 = 16 bits. */ + unsigned u132BitGate : 1; + /** Fixed value bit 5 - Set to 0. */ + unsigned u1Fixed6 : 1; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** High offset word. */ + unsigned u16OffsetHigh : 16; +} VBOXIDTE_INTERRUPTGATE; +#pragma pack() +/** Pointer to IDT Entry, Interrupt gate view. */ +typedef VBOXIDTE_INTERRUPTGATE *PVBOXIDTE_INTERRUPTGATE; + +/** IDT Entry, Trap Gate view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE_TRAPGATE +{ + /** Low offset word. */ + unsigned u16OffsetLow : 16; + /** Segment Selector. */ + unsigned u16SegSel : 16; + /** Reserved. */ + unsigned u5Reserved2 : 5; + /** Fixed value bit 0 - Set to 0. */ + unsigned u1Fixed0 : 1; + /** Fixed value bit 1 - Set to 0. */ + unsigned u1Fixed1 : 1; + /** Fixed value bit 2 - Set to 0. */ + unsigned u1Fixed2 : 1; + /** Fixed value bit 3 - Set to 1. */ + unsigned u1Fixed3 : 1; + /** Fixed value bit 4 - Set to 1. */ + unsigned u1Fixed4 : 1; + /** Fixed value bit 5 - Set to 1. */ + unsigned u1Fixed5 : 1; + /** Gate size, 1 = 32 bits, 0 = 16 bits. */ + unsigned u132BitGate : 1; + /** Fixed value bit 5 - Set to 0. */ + unsigned u1Fixed6 : 1; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** High offset word. */ + unsigned u16OffsetHigh : 16; +} VBOXIDTE_TRAPGATE; +#pragma pack() +/** Pointer to IDT Entry, Trap Gate view. */ +typedef VBOXIDTE_TRAPGATE *PVBOXIDTE_TRAPGATE; + +/** IDT Entry Generic view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE_GENERIC +{ + /** Low offset word. */ + unsigned u16OffsetLow : 16; + /** Segment Selector. */ + unsigned u16SegSel : 16; + /** Reserved. */ + unsigned u5Reserved : 5; + /** IDT Type part one (not used for task gate). */ + unsigned u3Type1 : 3; + /** IDT Type part two. */ + unsigned u5Type2 : 5; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** High offset word. */ + unsigned u16OffsetHigh : 16; +} VBOXIDTE_GENERIC; +#pragma pack() +/** Pointer to IDT Entry Generic view. */ +typedef VBOXIDTE_GENERIC *PVBOXIDTE_GENERIC; + +/** IDT Type1 value. (Reserved for task gate!) */ +#define VBOX_IDTE_TYPE1 0 +/** IDT Type2 value - Task gate. */ +#define VBOX_IDTE_TYPE2_TASK 0x5 +/** IDT Type2 value - 16 bit interrupt gate. */ +#define VBOX_IDTE_TYPE2_INT_16 0x6 +/** IDT Type2 value - 32 bit interrupt gate. */ +#define VBOX_IDTE_TYPE2_INT_32 0xe +/** IDT Type2 value - 16 bit trap gate. */ +#define VBOX_IDTE_TYPE2_TRAP_16 0x7 +/** IDT Type2 value - 32 bit trap gate. */ +#define VBOX_IDTE_TYPE2_TRAP_32 0xf + +/** IDT Entry. */ +#pragma pack(1) /* paranoia */ +typedef union VBOXIDTE +{ + /** Task gate view. */ + VBOXIDTE_TASKGATE Task; + /** Trap gate view. */ + VBOXIDTE_TRAPGATE Trap; + /** Interrupt gate view. */ + VBOXIDTE_INTERRUPTGATE Int; + /** Generic IDT view. */ + VBOXIDTE_GENERIC Gen; + + /** 8 bit unsigned integer view. */ + uint8_t au8[8]; + /** 16 bit unsigned integer view. */ + uint16_t au16[4]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; + /** 64 bit unsigned integer view. */ + uint64_t au64; +} VBOXIDTE; +#pragma pack() +/** Pointer to IDT Entry. */ +typedef VBOXIDTE *PVBOXIDTE; +/** Pointer to IDT Entry. */ +typedef VBOXIDTE const *PCVBOXIDTE; + +/** IDT Entry, 64-bit mode, Intertupt gate view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE64_INTERRUPTGATE +{ + /** Low offset word. */ + unsigned u16OffsetLow : 16; + /** Segment Selector. */ + unsigned u16SegSel : 16; + /** Interrupt Stack Table Index. */ + unsigned u3Ist : 3; + /** Fixed value bit 0 - Set to 0. */ + unsigned u1Fixed0 : 1; + /** Fixed value bit 1 - Set to 0. */ + unsigned u1Fixed1 : 1; + /** Fixed value bit 2 - Set to 0. */ + unsigned u1Fixed2 : 1; + /** Fixed value bit 3 - Set to 0. */ + unsigned u1Fixed3 : 1; + /** Fixed value bit 4 - Set to 0. */ + unsigned u1Fixed4 : 1; + /** Fixed value bit 5 - Set to 0. */ + unsigned u1Fixed5 : 1; + /** Fixed value bit 6 - Set to 1. */ + unsigned u1Fixed6 : 1; + /** Fixed value bit 7 - Set to 1. */ + unsigned u1Fixed7 : 1; + /** Gate size, 1 = 32 bits, 0 = 16 bits. */ + unsigned u132BitGate : 1; + /** Fixed value bit 5 - Set to 0. */ + unsigned u1Fixed8 : 1; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** High offset word. */ + unsigned u16OffsetHigh : 16; + /** Offset bits 32..63. */ + unsigned u32OffsetHigh64; + /** Reserved. */ + unsigned u32Reserved; +} VBOXIDTE64_INTERRUPTGATE; +#pragma pack() +/** Pointer to IDT Entry, 64-bit mode, Interrupt gate view. */ +typedef VBOXIDTE64_INTERRUPTGATE *PVBOXIDTE64_INTERRUPTGATE; + +/** IDT Entry, 64-bit mode, Trap gate view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE64_TRAPGATE +{ + /** Low offset word. */ + unsigned u16OffsetLow : 16; + /** Segment Selector. */ + unsigned u16SegSel : 16; + /** Interrupt Stack Table Index. */ + unsigned u3Ist : 3; + /** Fixed value bit 0 - Set to 0. */ + unsigned u1Fixed0 : 1; + /** Fixed value bit 1 - Set to 0. */ + unsigned u1Fixed1 : 1; + /** Fixed value bit 2 - Set to 0. */ + unsigned u1Fixed2 : 1; + /** Fixed value bit 3 - Set to 0. */ + unsigned u1Fixed3 : 1; + /** Fixed value bit 4 - Set to 0. */ + unsigned u1Fixed4 : 1; + /** Fixed value bit 5 - Set to 1. */ + unsigned u1Fixed5 : 1; + /** Fixed value bit 6 - Set to 1. */ + unsigned u1Fixed6 : 1; + /** Fixed value bit 7 - Set to 1. */ + unsigned u1Fixed7 : 1; + /** Gate size, 1 = 32 bits, 0 = 16 bits. */ + unsigned u132BitGate : 1; + /** Fixed value bit 5 - Set to 0. */ + unsigned u1Fixed8 : 1; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** High offset word. */ + unsigned u16OffsetHigh : 16; + /** Offset bits 32..63. */ + unsigned u32OffsetHigh64; + /** Reserved. */ + unsigned u32Reserved; +} VBOXIDTE64_TRAPGATE; +#pragma pack() +/** Pointer to IDT Entry, 64-bit mode, Trap gate view. */ +typedef VBOXIDTE64_TRAPGATE *PVBOXIDTE64_TRAPGATE; + +/** IDT Entry, 64-bit mode, Generic view. */ +#pragma pack(1) /* paranoia */ +typedef struct VBOXIDTE64_GENERIC +{ + /** Low offset word. */ + unsigned u16OffsetLow : 16; + /** Segment Selector. */ + unsigned u16SegSel : 16; + /** Reserved. */ + unsigned u3Ist : 3; + /** Fixed value bit 0 - Set to 0. */ + unsigned u1Fixed0 : 1; + /** Fixed value bit 1 - Set to 0. */ + unsigned u1Fixed1 : 1; + /** IDT Type part one (not used for task gate). */ + unsigned u3Type1 : 3; + /** IDT Type part two. */ + unsigned u5Type2 : 5; + /** Descriptor Privilege level. */ + unsigned u2DPL : 2; + /** Present flag. */ + unsigned u1Present : 1; + /** High offset word. */ + unsigned u16OffsetHigh : 16; + /** Offset bits 32..63. */ + unsigned u32OffsetHigh64; + /** Reserved. */ + unsigned u32Reserved; +} VBOXIDTE64_GENERIC; +#pragma pack() +/** Pointer to IDT Entry, 64-bit mode, Generic view. */ +typedef VBOXIDTE64_GENERIC *PVBOXIDTE64_GENERIC; + +/** IDT Entry, 64-bit mode. */ +#pragma pack(1) /* paranoia */ +typedef union VBOXIDTE64 +{ + /** Trap gate view. */ + VBOXIDTE64_TRAPGATE Trap; + /** Interrupt gate view. */ + VBOXIDTE64_INTERRUPTGATE Int; + /** Generic IDT view. */ + VBOXIDTE64_GENERIC Gen; + + /** 8 bit unsigned integer view. */ + uint8_t au8[16]; + /** 16 bit unsigned integer view. */ + uint16_t au16[8]; + /** 32 bit unsigned integer view. */ + uint32_t au32[4]; + /** 64 bit unsigned integer view. */ + uint64_t au64[2]; +} VBOXIDTE64; +#pragma pack() +/** Pointer to IDT Entry. */ +typedef VBOXIDTE64 *PVBOXIDTE64; +/** Pointer to IDT Entry. */ +typedef VBOXIDTE64 const *PCVBOXIDTE64; + +#pragma pack(1) +/** IDTR */ +typedef struct VBOXIDTR +{ + /** Size of the IDT. */ + uint16_t cbIdt; + /** Address of the IDT. */ + uint64_t pIdt; +} VBOXIDTR, *PVBOXIDTR; +#pragma pack() + + +/** @def VBOXIDTE_OFFSET + * Return the offset of an IDT entry. + */ +#define VBOXIDTE_OFFSET(desc) \ + ( ((uint32_t)((desc).Gen.u16OffsetHigh) << 16) \ + | ( (desc).Gen.u16OffsetLow ) ) + +/** @def VBOXIDTE64_OFFSET + * Return the offset of an IDT entry. + */ +#define VBOXIDTE64_OFFSET(desc) \ + ( ((uint64_t)((desc).Gen.u32OffsetHigh64) << 32) \ + | ((uint32_t)((desc).Gen.u16OffsetHigh) << 16) \ + | ( (desc).Gen.u16OffsetLow ) ) + +#pragma pack(1) +/** GDTR */ +typedef struct VBOXGDTR +{ + /** Size of the GDT. */ + uint16_t cbGdt; + /** Address of the GDT. */ + uint64_t pGdt; +} VBOXGDTR; +#pragma pack() +/** Pointer to GDTR. */ +typedef VBOXGDTR *PVBOXGDTR; + +/** @} */ + + +/** + * 32-bit Task Segment used in raw mode. + * @todo Move this to SELM! Use X86TSS32 instead. + */ +#pragma pack(1) +typedef struct VBOXTSS +{ + /** 0x00 - Back link to previous task. (static) */ + RTSEL selPrev; + uint16_t padding1; + /** 0x04 - Ring-0 stack pointer. (static) */ + uint32_t esp0; + /** 0x08 - Ring-0 stack segment. (static) */ + RTSEL ss0; + uint16_t padding_ss0; + /** 0x0c - Ring-1 stack pointer. (static) */ + uint32_t esp1; + /** 0x10 - Ring-1 stack segment. (static) */ + RTSEL ss1; + uint16_t padding_ss1; + /** 0x14 - Ring-2 stack pointer. (static) */ + uint32_t esp2; + /** 0x18 - Ring-2 stack segment. (static) */ + RTSEL ss2; + uint16_t padding_ss2; + /** 0x1c - Page directory for the task. (static) */ + uint32_t cr3; + /** 0x20 - EIP before task switch. */ + uint32_t eip; + /** 0x24 - EFLAGS before task switch. */ + uint32_t eflags; + /** 0x28 - EAX before task switch. */ + uint32_t eax; + /** 0x2c - ECX before task switch. */ + uint32_t ecx; + /** 0x30 - EDX before task switch. */ + uint32_t edx; + /** 0x34 - EBX before task switch. */ + uint32_t ebx; + /** 0x38 - ESP before task switch. */ + uint32_t esp; + /** 0x3c - EBP before task switch. */ + uint32_t ebp; + /** 0x40 - ESI before task switch. */ + uint32_t esi; + /** 0x44 - EDI before task switch. */ + uint32_t edi; + /** 0x48 - ES before task switch. */ + RTSEL es; + uint16_t padding_es; + /** 0x4c - CS before task switch. */ + RTSEL cs; + uint16_t padding_cs; + /** 0x50 - SS before task switch. */ + RTSEL ss; + uint16_t padding_ss; + /** 0x54 - DS before task switch. */ + RTSEL ds; + uint16_t padding_ds; + /** 0x58 - FS before task switch. */ + RTSEL fs; + uint16_t padding_fs; + /** 0x5c - GS before task switch. */ + RTSEL gs; + uint16_t padding_gs; + /** 0x60 - LDTR before task switch. */ + RTSEL selLdt; + uint16_t padding_ldt; + /** 0x64 - Debug trap flag */ + uint16_t fDebugTrap; + /** 0x66 - Offset relative to the TSS of the start of the I/O Bitmap + * and the end of the interrupt redirection bitmap. */ + uint16_t offIoBitmap; + /** 0x68 - 32 bytes for the virtual interrupt redirection bitmap. (VME) */ + uint8_t IntRedirBitmap[32]; +} VBOXTSS; +#pragma pack() +/** Pointer to task segment. */ +typedef VBOXTSS *PVBOXTSS; +/** Pointer to const task segment. */ +typedef const VBOXTSS *PCVBOXTSS; + + +/** Pointer to a callback method table provided by the VM API user. */ +typedef struct VMM2USERMETHODS const *PCVMM2USERMETHODS; + + +/** + * Data transport buffer (scatter/gather) + */ +typedef struct PDMDATASEG +{ + /** Length of buffer in entry. */ + size_t cbSeg; + /** Pointer to the start of the buffer. */ + void *pvSeg; +} PDMDATASEG; +/** Pointer to a data transport segment. */ +typedef PDMDATASEG *PPDMDATASEG; +/** Pointer to a const data transport segment. */ +typedef PDMDATASEG const *PCPDMDATASEG; + + +/** + * Forms of generic segment offloading. + */ +typedef enum PDMNETWORKGSOTYPE +{ + /** Invalid zero value. */ + PDMNETWORKGSOTYPE_INVALID = 0, + /** TCP/IPv4 - no CWR/ECE encoding. */ + PDMNETWORKGSOTYPE_IPV4_TCP, + /** TCP/IPv6 - no CWR/ECE encoding. */ + PDMNETWORKGSOTYPE_IPV6_TCP, + /** UDP/IPv4. */ + PDMNETWORKGSOTYPE_IPV4_UDP, + /** UDP/IPv6. */ + PDMNETWORKGSOTYPE_IPV6_UDP, + /** TCP/IPv6 over IPv4 tunneling - no CWR/ECE encoding. + * The header offsets and sizes relates to IPv4 and TCP, the IPv6 header is + * figured out as needed. + * @todo Needs checking against facts, this is just an outline of the idea. */ + PDMNETWORKGSOTYPE_IPV4_IPV6_TCP, + /** UDP/IPv6 over IPv4 tunneling. + * The header offsets and sizes relates to IPv4 and UDP, the IPv6 header is + * figured out as needed. + * @todo Needs checking against facts, this is just an outline of the idea. */ + PDMNETWORKGSOTYPE_IPV4_IPV6_UDP, + /** The end of valid GSO types. */ + PDMNETWORKGSOTYPE_END +} PDMNETWORKGSOTYPE; + + +/** + * Generic segment offloading context. + * + * We generally follow the E1000 specs wrt to which header fields we change. + * However the GSO type implies where the checksum fields are and that they are + * always updated from scratch (no half done pseudo checksums). + * + * @remarks This is part of the internal network GSO packets. Take great care + * when making changes. The size is expected to be exactly 8 bytes. + * + * @ingroup grp_pdm + */ +typedef struct PDMNETWORKGSO +{ + /** The type of segmentation offloading we're performing (PDMNETWORKGSOTYPE). */ + uint8_t u8Type; + /** The total header size. */ + uint8_t cbHdrsTotal; + /** The max segment size (MSS) to apply. */ + uint16_t cbMaxSeg; + + /** Offset of the first header (IPv4 / IPv6). 0 if not not needed. */ + uint8_t offHdr1; + /** Offset of the second header (TCP / UDP). 0 if not not needed. */ + uint8_t offHdr2; + /** The header size used for segmentation (equal to offHdr2 in UFO). */ + uint8_t cbHdrsSeg; + /** Unused. */ + uint8_t u8Unused; +} PDMNETWORKGSO; +/** Pointer to a GSO context. + * @ingroup grp_pdm */ +typedef PDMNETWORKGSO *PPDMNETWORKGSO; +/** Pointer to a const GSO context. + * @ingroup grp_pdm */ +typedef PDMNETWORKGSO const *PCPDMNETWORKGSO; + +/** Pointer to a PDM filter handle. + * @ingroup grp_pdm_net_shaper */ +typedef struct PDMNSFILTER *PPDMNSFILTER; +/** Pointer to a network shaper. + * @ingroup grp_pdm_net_shaper */ +typedef struct PDMNETSHAPER *PPDMNETSHAPER; + + +/** + * The current ROM page protection. + * + * @remarks This is part of the saved state. + * @ingroup grp_pgm + */ +typedef enum PGMROMPROT +{ + /** The customary invalid value. */ + PGMROMPROT_INVALID = 0, + /** Read from the virgin ROM page, ignore writes. + * Map the virgin page, use write access handler to ignore writes. */ + PGMROMPROT_READ_ROM_WRITE_IGNORE, + /** Read from the virgin ROM page, write to the shadow RAM. + * Map the virgin page, use write access handler to change the shadow RAM. */ + PGMROMPROT_READ_ROM_WRITE_RAM, + /** Read from the shadow ROM page, ignore writes. + * Map the shadow page read-only, use write access handler to ignore writes. */ + PGMROMPROT_READ_RAM_WRITE_IGNORE, + /** Read from the shadow ROM page, ignore writes. + * Map the shadow page read-write, disabled write access handler. */ + PGMROMPROT_READ_RAM_WRITE_RAM, + /** The end of valid values. */ + PGMROMPROT_END, + /** The usual 32-bit type size hack. */ + PGMROMPROT_32BIT_HACK = 0x7fffffff +} PGMROMPROT; + + +/** + * Page mapping lock. + * @ingroup grp_pgm + */ +typedef struct PGMPAGEMAPLOCK +{ +#if defined(IN_RC) + /** The locked page. */ + void *pvPage; + /** Pointer to the CPU that made the mapping. + * In ring-0 and raw-mode context we don't intend to ever allow long term + * locking and this is a way of making sure we're still on the same CPU. */ + PVMCPU pVCpu; +#else + /** Pointer to the PGMPAGE and lock type. + * bit-0 abuse: set=write, clear=read. */ + uintptr_t uPageAndType; +/** Read lock type value. */ +# define PGMPAGEMAPLOCK_TYPE_READ ((uintptr_t)0) +/** Write lock type value. */ +# define PGMPAGEMAPLOCK_TYPE_WRITE ((uintptr_t)1) +/** Lock type mask. */ +# define PGMPAGEMAPLOCK_TYPE_MASK ((uintptr_t)1) + /** Pointer to the PGMCHUNKR3MAP. */ + void *pvMap; +#endif +} PGMPAGEMAPLOCK; +/** Pointer to a page mapping lock. + * @ingroup grp_pgm */ +typedef PGMPAGEMAPLOCK *PPGMPAGEMAPLOCK; + + +/** Pointer to a info helper callback structure. */ +typedef struct DBGFINFOHLP *PDBGFINFOHLP; +/** Pointer to a const info helper callback structure. */ +typedef const struct DBGFINFOHLP *PCDBGFINFOHLP; + +/** Pointer to a const register descriptor. */ +typedef struct DBGFREGDESC const *PCDBGFREGDESC; + + +/** Configuration manager tree node - A key. */ +typedef struct CFGMNODE *PCFGMNODE; + +/** Configuration manager tree leaf - A value. */ +typedef struct CFGMLEAF *PCFGMLEAF; + + +/** + * CPU modes. + */ +typedef enum CPUMMODE +{ + /** The usual invalid zero entry. */ + CPUMMODE_INVALID = 0, + /** Real mode. */ + CPUMMODE_REAL, + /** Protected mode (32-bit). */ + CPUMMODE_PROTECTED, + /** Long mode (64-bit). */ + CPUMMODE_LONG +} CPUMMODE; + + +/** + * CPU mode flags (DISSTATE::mode). + */ +typedef enum DISCPUMODE +{ + DISCPUMODE_INVALID = 0, + DISCPUMODE_16BIT, + DISCPUMODE_32BIT, + DISCPUMODE_64BIT, + /** hack forcing the size of the enum to 32-bits. */ + DISCPUMODE_MAKE_32BIT_HACK = 0x7fffffff +} DISCPUMODE; + +/** Pointer to the disassembler state. */ +typedef struct DISSTATE *PDISSTATE; +/** Pointer to a const disassembler state. */ +typedef struct DISSTATE const *PCDISSTATE; + +/** @deprecated PDISSTATE and change pCpu and pDisState to pDis. */ +typedef PDISSTATE PDISCPUSTATE; +/** @deprecated PCDISSTATE and change pCpu and pDisState to pDis. */ +typedef PCDISSTATE PCDISCPUSTATE; + + +/** + * Shared region description (needed by GMM and others, thus global). + * @ingroup grp_vmmdev + */ +typedef struct VMMDEVSHAREDREGIONDESC +{ + RTGCPTR64 GCRegionAddr; + uint32_t cbRegion; + uint32_t u32Alignment; +} VMMDEVSHAREDREGIONDESC; + + +/** + * A PCI bus:device:function (BDF) identifier. + * + * All 16 bits of a BDF are valid according to the PCI spec. We need one extra bit + * to determine whether the BDF is valid in interfaces where the BDF may be + * optional. + */ +typedef uint32_t PCIBDF; +/** PCIBDF flag: Invalid. */ +#define PCI_BDF_F_INVALID RT_BIT(31) +/** Nil PCIBDF value. */ +#define NIL_PCIBDF PCI_BDF_F_INVALID + +/** Pointer to an MSI message struct. */ +typedef struct MSIMSG *PMSIMSG; +/** Pointer to a const MSI message struct. */ +typedef const struct MSIMSG *PCMSIMSG; + + +/** @} */ + +#endif /* !VBOX_INCLUDED_types_h */ diff --git a/include/VBox/usb.h b/include/VBox/usb.h new file mode 100644 index 00000000..e83b7661 --- /dev/null +++ b/include/VBox/usb.h @@ -0,0 +1,280 @@ +/** @file + * USB - Universal Serial Bus. (DEV,Main?) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_usb_h +#define VBOX_INCLUDED_usb_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_usblib_usb USB Device Structures & Types + * @ingroup grp_usblib + * @{ + */ + +/** + * The USB host device state. + */ +typedef enum USBDEVICESTATE +{ + /** The device is unsupported. */ + USBDEVICESTATE_UNSUPPORTED = 1, + /** The device is in use by the host. */ + USBDEVICESTATE_USED_BY_HOST, + /** The device is in use by the host but could perhaps be captured even so. */ + USBDEVICESTATE_USED_BY_HOST_CAPTURABLE, + /** The device is not used by the host or any guest. */ + USBDEVICESTATE_UNUSED, + /** The device is held by the proxy for later guest usage. */ + USBDEVICESTATE_HELD_BY_PROXY, + /** The device in use by a guest. */ + USBDEVICESTATE_USED_BY_GUEST, + /** The usual 32-bit hack. */ + USBDEVICESTATE_32BIT_HACK = 0x7fffffff +} USBDEVICESTATE; + + +/** + * The USB device speed. + */ +typedef enum USBDEVICESPEED +{ + /** Unknown. */ + USBDEVICESPEED_UNKNOWN = 0, + /** Low speed (1.5 Mbit/s). */ + USBDEVICESPEED_LOW, + /** Full speed (12 Mbit/s). */ + USBDEVICESPEED_FULL, + /** High speed (480 Mbit/s). */ + USBDEVICESPEED_HIGH, + /** Variable speed - USB 2.5 / wireless. */ + USBDEVICESPEED_VARIABLE, + /** Super speed - USB 3.0 (5Gbit/s). */ + USBDEVICESPEED_SUPER, + /** The usual 32-bit hack. */ + USBDEVICESPEED_32BIT_HACK = 0x7fffffff +} USBDEVICESPEED; + + +/** + * USB host device description. + * Used for enumeration of USB devices. + */ +typedef struct USBDEVICE +{ + /** If linked, this is the pointer to the next device in the list. */ + struct USBDEVICE *pNext; + /** If linked doubly, this is the pointer to the prev device in the list. */ + struct USBDEVICE *pPrev; + /** Manufacturer string. */ + const char *pszManufacturer; + /** Product string. */ + const char *pszProduct; + /** Serial number string. */ + const char *pszSerialNumber; + /** The address of the device. */ + const char *pszAddress; + /** The backend to use for this device. */ + const char *pszBackend; + + /** Vendor ID. */ + uint16_t idVendor; + /** Product ID. */ + uint16_t idProduct; + /** Revision, integer part. */ + uint16_t bcdDevice; + /** USB version number. */ + uint16_t bcdUSB; + /** Device class. */ + uint8_t bDeviceClass; + /** Device subclass. */ + uint8_t bDeviceSubClass; + /** Device protocol */ + uint8_t bDeviceProtocol; + /** Number of configurations. */ + uint8_t bNumConfigurations; + /** The device state. */ + USBDEVICESTATE enmState; + /** The device speed. */ + USBDEVICESPEED enmSpeed; + /** Serial hash. */ + uint64_t u64SerialHash; + /** The USB Bus number. */ + uint8_t bBus; + /** The port number. */ + uint8_t bPort; + /** The hub+port path. */ + char *pszPortPath; +#if defined(RT_OS_LINUX) || defined(RT_OS_FREEBSD) + /** Device number. */ + uint8_t bDevNum; +#endif +#ifdef RT_OS_WINDOWS + /** Alternate address. Can be NULL. */ + char *pszAltAddress; + /** The hub name. */ + char *pszHubName; +#endif +#ifdef RT_OS_SOLARIS + /** The /devices path of the device. */ + char *pszDevicePath; + /** Do we have a partial or full device descriptor here. */ + bool fPartialDescriptor; +#endif +} USBDEVICE; +/** Pointer to a USB device. */ +typedef USBDEVICE *PUSBDEVICE; +/** Pointer to a const USB device. */ +typedef USBDEVICE *PCUSBDEVICE; + + +#ifdef VBOX_USB_H_INCL_DESCRIPTORS /* for the time being, since this may easily conflict with system headers */ + +/** + * USB device descriptor. + */ +#pragma pack(1) +typedef struct USBDESCHDR +{ + /** The descriptor length. */ + uint8_t bLength; + /** The descriptor type. */ + uint8_t bDescriptorType; +} USBDESCHDR; +#pragma pack() +/** Pointer to an USB descriptor header. */ +typedef USBDESCHDR *PUSBDESCHDR; + +/** @name Descriptor Type values (bDescriptorType) + * {@ */ +#if !defined(USB_DT_DEVICE) && !defined(USB_DT_ENDPOINT) +# define USB_DT_DEVICE 0x01 +# define USB_DT_CONFIG 0x02 +# define USB_DT_STRING 0x03 +# define USB_DT_INTERFACE 0x04 +# define USB_DT_ENDPOINT 0x05 + +# define USB_DT_HID 0x21 +# define USB_DT_REPORT 0x22 +# define USB_DT_PHYSICAL 0x23 +# define USB_DT_HUB 0x29 +#endif +/** @} */ + + +/** + * USB device descriptor. + */ +#pragma pack(1) +typedef struct USBDEVICEDESC +{ + /** The descriptor length. (Usually sizeof(USBDEVICEDESC).) */ + uint8_t bLength; + /** The descriptor type. (USB_DT_DEVICE) */ + uint8_t bDescriptorType; + /** USB version number. */ + uint16_t bcdUSB; + /** Device class. */ + uint8_t bDeviceClass; + /** Device subclass. */ + uint8_t bDeviceSubClass; + /** Device protocol */ + uint8_t bDeviceProtocol; + /** The max packet size of the default control pipe. */ + uint8_t bMaxPacketSize0; + /** Vendor ID. */ + uint16_t idVendor; + /** Product ID. */ + uint16_t idProduct; + /** Revision, integer part. */ + uint16_t bcdDevice; + /** Manufacturer string index. */ + uint8_t iManufacturer; + /** Product string index. */ + uint8_t iProduct; + /** Serial number string index. */ + uint8_t iSerialNumber; + /** Number of configurations. */ + uint8_t bNumConfigurations; +} USBDEVICEDESC; +#pragma pack() +/** Pointer to an USB device descriptor. */ +typedef USBDEVICEDESC *PUSBDEVICEDESC; + +/** @name Class codes (bDeviceClass) + * @{ */ +#ifndef USB_HUB_CLASSCODE +# define USB_HUB_CLASSCODE 0x09 +#endif +/** @} */ + +/** + * USB configuration descriptor. + */ +#pragma pack(1) +typedef struct USBCONFIGDESC +{ + /** The descriptor length. (Usually sizeof(USBCONFIGDESC).) */ + uint8_t bLength; + /** The descriptor type. (USB_DT_CONFIG) */ + uint8_t bDescriptorType; + /** The length of the configuration descriptor plus all associated descriptors. */ + uint16_t wTotalLength; + /** Number of interfaces. */ + uint8_t bNumInterfaces; + /** Configuration number. (For SetConfiguration().) */ + uint8_t bConfigurationValue; + /** Configuration description string. */ + uint8_t iConfiguration; + /** Configuration characteristics. */ + uint8_t bmAttributes; + /** Maximum power consumption of the USB device in this config. */ + uint8_t MaxPower; +} USBCONFIGDESC; +#pragma pack() +/** Pointer to an USB configuration descriptor. */ +typedef USBCONFIGDESC *PUSBCONFIGDESC; + +#endif /* VBOX_USB_H_INCL_DESCRIPTORS */ + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_usb_h */ + diff --git a/include/VBox/usbfilter.h b/include/VBox/usbfilter.h new file mode 100644 index 00000000..3f7f15ca --- /dev/null +++ b/include/VBox/usbfilter.h @@ -0,0 +1,271 @@ +/** @file + * USBFilter - USB Filter constructs shared by kernel and user mode. + * (DEV,HDrv,Main) + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_usbfilter_h +#define VBOX_INCLUDED_usbfilter_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +/** @defgroup grp_usbfilter USBFilter - USB Filter constructs shared by kernel and user mode + * @ingroup grp_usblib + * @{ + */ + +/** + * How to match a field. + * + * @remarks This is a binary interface (drivers). + */ +typedef enum USBFILTERMATCH +{ + /** The usual invalid first zero value. */ + USBFILTERMATCH_INVALID = 0, + /** Ignore this field (always matching). + * Device Data: No value present. */ + USBFILTERMATCH_IGNORE, + /** Only require this field to be present on the device. */ + USBFILTERMATCH_PRESENT, + + /** Numeric Field: The first numeric field matching method. */ + USBFILTERMATCH_NUM_FIRST, + /** Numeric Field: Exact match, required to be present. */ + USBFILTERMATCH_NUM_EXACT = USBFILTERMATCH_NUM_FIRST, + /** Numeric Field: Exact match or not present. */ + USBFILTERMATCH_NUM_EXACT_NP, + /** Numeric Field: Expression match, required to be present. + * The expression is represented as a string. */ + USBFILTERMATCH_NUM_EXPRESSION, + /** Numeric Field: Expression match or not present. + * The expression is represented as a string. */ + USBFILTERMATCH_NUM_EXPRESSION_NP, + /** Numeric Field: The last numeric field matching method (inclusive). */ + USBFILTERMATCH_NUM_LAST = USBFILTERMATCH_NUM_EXPRESSION_NP, + + /** String Field: The first string field matching method. */ + USBFILTERMATCH_STR_FIRST, + /** String Field: Exact match, required to be present. */ + USBFILTERMATCH_STR_EXACT = USBFILTERMATCH_STR_FIRST, + /** String Field: Exact match or not present. */ + USBFILTERMATCH_STR_EXACT_NP, + /** String Field: Pattern match, required to be present.*/ + USBFILTERMATCH_STR_PATTERN, + /** String Field: Pattern match or not present.*/ + USBFILTERMATCH_STR_PATTERN_NP, + /** String Field: The last string field matching method (inclusive). */ + USBFILTERMATCH_STR_LAST = USBFILTERMATCH_STR_PATTERN_NP, + + /** The end of valid matching methods (exclusive). */ + USBFILTERMATCH_END +} USBFILTERMATCH; +AssertCompile(USBFILTERMATCH_END == 11); + + +/** + * A USB filter field. + * + * @remarks This is a binary interface (drivers). + */ +typedef struct USBFILTERFIELD +{ + /** The matching method. (USBFILTERMATCH) */ + uint16_t enmMatch; + /** The field value or offset into the string table. + * The enmMatch field decides which it is. */ + uint16_t u16Value; +} USBFILTERFIELD; +AssertCompileSize(USBFILTERFIELD, 4); +/** Pointer to a USB filter field. */ +typedef USBFILTERFIELD *PUSBFILTERFIELD; +/** Pointer to a const USBFILTERFIELD. */ +typedef const USBFILTERFIELD *PCUSBFILTERFIELD; + + +/** + * USB filter field index. + * + * This is used as an index into the USBFILTER::aFields array. + * + * @remarks This is a binary interface (drivers). + */ +typedef enum USBFILTERIDX +{ + /** idVendor (= 0) */ + USBFILTERIDX_VENDOR_ID = 0, + /** idProduct (= 1) */ + USBFILTERIDX_PRODUCT_ID, + /** bcdDevice (= 2)*/ + USBFILTERIDX_DEVICE_REV, + USBFILTERIDX_DEVICE = USBFILTERIDX_DEVICE_REV, + /** bDeviceClass (= 3) */ + USBFILTERIDX_DEVICE_CLASS, + /** bDeviceSubClass (= 4) */ + USBFILTERIDX_DEVICE_SUB_CLASS, + /** bDeviceProtocol (= 5) */ + USBFILTERIDX_DEVICE_PROTOCOL, + /** bBus (= 6 )*/ + USBFILTERIDX_BUS, + /** bPort (=7) */ + USBFILTERIDX_PORT, + /** Manufacturer string. (=8) */ + USBFILTERIDX_MANUFACTURER_STR, + /** Product string. (=9) */ + USBFILTERIDX_PRODUCT_STR, + /** SerialNumber string. (=10) */ + USBFILTERIDX_SERIAL_NUMBER_STR, + /** The end of the USB filter fields (exclusive). */ + USBFILTERIDX_END +} USBFILTERIDX; +AssertCompile(USBFILTERIDX_END == 11); + + +/** + * USB Filter types. + * + * The filters types are list in priority order, i.e. highest priority first. + * + * @remarks This is a binary interface (drivers). + */ +typedef enum USBFILTERTYPE +{ + /** The usual invalid first zero value. */ + USBFILTERTYPE_INVALID = 0, + /** The first valid entry. */ + USBFILTERTYPE_FIRST, + /** A one-shot ignore filter that's installed when releasing a device. + * This filter will be automatically removedwhen the device re-appears, + * or when ring-3 decides that time is up, or if ring-3 dies upon us. */ + USBFILTERTYPE_ONESHOT_IGNORE = USBFILTERTYPE_FIRST, + /** A one-shot capture filter that's installed when hijacking a device that's already plugged. + * This filter will be automatically removed when the device re-appears, + * or when ring-3 decides that time is up, or if ring-3 dies upon us. */ + USBFILTERTYPE_ONESHOT_CAPTURE, + /** Ignore filter. + * This picks out devices that shouldn't be captured. */ + USBFILTERTYPE_IGNORE, + /** A normal capture filter. + * When a device matching the filter is attach, we'll take it. */ + USBFILTERTYPE_CAPTURE, + /** The end of the valid filter types (exclusive). */ + USBFILTERTYPE_END, + /** The usual 32-bit hack. */ + USBFILTERTYPE_32BIT_HACK = 0x7fffffff +} USBFILTERTYPE; +AssertCompileSize(USBFILTERTYPE, 4); +AssertCompile(USBFILTERTYPE_END == 5); + + +/** + * USB Filter. + * + * Consider the an abstract data type, use the methods below to access it. + * + * @remarks This is a binary interface (drivers). + */ +typedef struct USBFILTER +{ + /** Magic number (USBFILTER_MAGIC). */ + uint32_t u32Magic; + /** The filter type. */ + USBFILTERTYPE enmType; + /** The filter fields. + * This array is indexed by USBFILTERIDX */ + USBFILTERFIELD aFields[USBFILTERIDX_END]; + /** Offset to the end of the string table (last terminator). (used to speed up things) */ + uint32_t offCurEnd; + /** String table. + * This is used for string and numeric patterns. */ + char achStrTab[256]; +} USBFILTER; +AssertCompileSize(USBFILTER, 312); + +/** Pointer to a USBLib filter. */ +typedef USBFILTER *PUSBFILTER; +/** Pointer to a const USBLib filter. */ +typedef const USBFILTER *PCUSBFILTER; + +/** USBFILTER::u32Magic (Yasuhiro Nightow). */ +#define USBFILTER_MAGIC UINT32_C(0x19670408) + + +RT_C_DECLS_BEGIN + +USBLIB_DECL(void) USBFilterInit(PUSBFILTER pFilter, USBFILTERTYPE enmType); +USBLIB_DECL(void) USBFilterClone(PUSBFILTER pFilter, PCUSBFILTER pToClone); +USBLIB_DECL(void) USBFilterDelete(PUSBFILTER pFilter); +USBLIB_DECL(int) USBFilterValidate(PCUSBFILTER pFilter); +USBLIB_DECL(bool) USBFilterMatch(PCUSBFILTER pFilter, PCUSBFILTER pDevice); +USBLIB_DECL(int) USBFilterMatchRated(PCUSBFILTER pFilter, PCUSBFILTER pDevice); +USBLIB_DECL(bool) USBFilterMatchDevice(PCUSBFILTER pFilter, PCUSBDEVICE pDevice); +USBLIB_DECL(bool) USBFilterIsIdentical(PCUSBFILTER pFilter, PCUSBFILTER pFilter2); + +USBLIB_DECL(int) USBFilterSetFilterType(PUSBFILTER pFilter, USBFILTERTYPE enmType); +USBLIB_DECL(int) USBFilterSetIgnore(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx); +USBLIB_DECL(int) USBFilterSetPresentOnly(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx); +USBLIB_DECL(int) USBFilterSetNumExact(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, uint16_t u16Value, bool fMustBePresent); +USBLIB_DECL(int) USBFilterSetNumExpression(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszExpression, bool fMustBePresent); +USBLIB_DECL(int) USBFilterSetStringExact(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszValue, + bool fMustBePresent, bool fPurge); +USBLIB_DECL(int) USBFilterSetStringPattern(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, const char *pszPattern, bool fMustBePresent); +USBLIB_DECL(int) USBFilterSetMustBePresent(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, bool fMustBePresent); + +USBLIB_DECL(USBFILTERTYPE) USBFilterGetFilterType(PCUSBFILTER pFilter); +USBLIB_DECL(USBFILTERMATCH) USBFilterGetMatchingMethod(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx); +USBLIB_DECL(int) USBFilterQueryNum(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, uint16_t *pu16Value); +USBLIB_DECL(int) USBFilterGetNum(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx); +USBLIB_DECL(int) USBFilterQueryString(PUSBFILTER pFilter, USBFILTERIDX enmFieldIdx, char *pszBuf, size_t cchBuf); +USBLIB_DECL(const char *) USBFilterGetString(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx); +USBLIB_DECL(ssize_t) USBFilterGetStringLen(PCUSBFILTER pFilter, USBFILTERIDX enmFieldIdx); + +USBLIB_DECL(bool) USBFilterHasAnySubstatialCriteria(PCUSBFILTER pFilter); +USBLIB_DECL(bool) USBFilterIsNumericField(USBFILTERIDX enmFieldIdx); +USBLIB_DECL(bool) USBFilterIsStringField(USBFILTERIDX enmFieldIdx); +USBLIB_DECL(bool) USBFilterIsMethodUsingNumericValue(USBFILTERMATCH enmMatchingMethod); +USBLIB_DECL(bool) USBFilterIsMethodUsingStringValue(USBFILTERMATCH enmMatchingMethod); +USBLIB_DECL(bool) USBFilterIsMethodNumeric(USBFILTERMATCH enmMatchingMethod); +USBLIB_DECL(bool) USBFilterIsMethodString(USBFILTERMATCH enmMatchingMethod); + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_usbfilter_h */ diff --git a/include/VBox/usblib-darwin.h b/include/VBox/usblib-darwin.h new file mode 100644 index 00000000..f74d5f92 --- /dev/null +++ b/include/VBox/usblib-darwin.h @@ -0,0 +1,72 @@ +/** @file + * USBLib - Library for wrapping up the VBoxUSB functionality, Darwin flavor. + * (DEV,HDrv,Main) + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_usblib_darwin_h +#define VBOX_INCLUDED_usblib_darwin_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_usblib_darwin Darwin USB Specifics + * @ingroup grp_usblib + * @{ + */ + +/** @name VBoxUSB specific device properties. + * VBoxUSB makes use of the OWNER property for communicating between the probe and + * start stage. + * USBProxyServiceDarwin makes use of all of them to correctly determine the state + * of the device. + * @{ */ +/** Contains the pid of the current client. If 0, the kernel is the current client. */ +#define VBOXUSB_CLIENT_KEY "VBoxUSB-Client" +/** Contains the pid of the filter owner (i.e. the VBoxSVC pid). */ +#define VBOXUSB_OWNER_KEY "VBoxUSB-Owner" +/** Contains the ID of the matching filter. */ +#define VBOXUSB_FILTER_KEY "VBoxUSB-Filter" +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_usblib_darwin_h */ + diff --git a/include/VBox/usblib-solaris.h b/include/VBox/usblib-solaris.h new file mode 100644 index 00000000..3cc900bb --- /dev/null +++ b/include/VBox/usblib-solaris.h @@ -0,0 +1,288 @@ +/** @file + * USBLib - Library for wrapping up the VBoxUSB functionality, Solaris flavor. + * (DEV,HDrv,Main) + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_usblib_solaris_h +#define VBOX_INCLUDED_usblib_solaris_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_usblib_solaris Solaris USB Specifics + * @ingroup grp_usblib + * @{ + */ + +/** @name VBoxUSB specific IOCtls. + * VBoxUSB uses them for resetting USB devices requests from userland. + * USBProxyService/Device makes use of them to communicate with VBoxUSB. + * @{ */ + +/** Ring-3 request wrapper for big requests. + * + * This is necessary because the ioctl number scheme on many Unixy OSes (esp. Solaris) + * only allows a relatively small size to be encoded into the request. So, for big + * request this generic form is used instead. */ +typedef struct VBOXUSBREQ +{ + /** Magic value (VBOXUSB(MON)_MAGIC). */ + uint32_t u32Magic; + /** The size of the data buffer (In & Out). */ + uint32_t cbData; + /** Result code of the request filled by driver. */ + int32_t rc; + /** The user address of the data buffer. */ + RTR3PTR pvDataR3; +} VBOXUSBREQ; +/** Pointer to a request wrapper for solaris. */ +typedef VBOXUSBREQ *PVBOXUSBREQ; +/** Pointer to a const request wrapper for solaris. */ +typedef const VBOXUSBREQ *PCVBOXUSBREQ; + +#pragma pack(1) +typedef struct +{ + /* Pointer to the Filter. */ + USBFILTER Filter; + /* Where to store the added Filter (Id). */ + uintptr_t uId; +} VBOXUSBREQ_ADD_FILTER; + +typedef struct +{ + /* Pointer to Filter (Id) to be removed. */ + uintptr_t uId; +} VBOXUSBREQ_REMOVE_FILTER; + +typedef struct +{ + /** Whether to re-attach the driver. */ + bool fReattach; + /* Physical path of the USB device. */ + char szDevicePath[1]; +} VBOXUSBREQ_RESET_DEVICE; + +typedef struct +{ + /* Where to store the instance. */ + int *pInstance; + /* Physical path of the USB device. */ + char szDevicePath[1]; +} VBOXUSBREQ_DEVICE_INSTANCE; + +typedef struct +{ + /** Where to store the instance. */ + int Instance; + /* Where to store the client path. */ + char szClientPath[MAXPATHLEN]; + /** Device identifier (VendorId:ProductId:Release:StaticPath) */ + char szDeviceIdent[MAXPATHLEN+48]; + /** Callback from monitor specifying client consumer (VM) credentials */ + DECLR0CALLBACKMEMBER(int, pfnSetConsumerCredentials,(RTPROCESS Process, int Instance, void *pvReserved)); +} VBOXUSBREQ_CLIENT_INFO, *PVBOXUSBREQ_CLIENT_INFO; +typedef VBOXUSBREQ_CLIENT_INFO VBOXUSB_CLIENT_INFO; +typedef PVBOXUSBREQ_CLIENT_INFO PVBOXUSB_CLIENT_INFO; + +/** Isoc packet descriptor (Must mirror exactly Solaris USBA's usb_isoc_pkt_descr_t) */ +typedef struct +{ + ushort_t cbPkt; /* Size of the packet */ + ushort_t cbActPkt; /* Size of the packet actually transferred */ + VUSBSTATUS enmStatus; /* Per frame transfer status */ +} VUSBISOC_PKT_DESC; + +/** VBoxUSB IOCtls */ +typedef struct +{ + void *pvUrbR3; /* Pointer to userland URB (untouched by kernel driver) */ + uint8_t bEndpoint; /* Endpoint address */ + VUSBXFERTYPE enmType; /* Xfer type */ + VUSBDIRECTION enmDir; /* Xfer direction */ + VUSBSTATUS enmStatus; /* URB status */ + bool fShortOk; /* Whether receiving less data than requested is acceptable. */ + size_t cbData; /* Size of the data */ + void *pvData; /* Pointer to the data */ + uint32_t cIsocPkts; /* Number of Isoc packets */ + VUSBISOC_PKT_DESC aIsocPkts[8]; /* Array of Isoc packet descriptors */ +} VBOXUSBREQ_URB, *PVBOXUSBREQ_URB; + +typedef struct +{ + uint8_t bEndpoint; /* Endpoint address */ +} VBOXUSBREQ_CLEAR_EP, *PVBOXUSBREQ_CLEAR_EP; + + +typedef struct +{ + uint8_t bConfigValue; /* Configuration value */ +} VBOXUSBREQ_SET_CONFIG, *PVBOXUSBREQ_SET_CONFIG; +typedef VBOXUSBREQ_SET_CONFIG VBOXUSBREQ_GET_CONFIG; +typedef PVBOXUSBREQ_SET_CONFIG PVBOXUSBREQ_GET_CONFIG; + +typedef struct +{ + uint8_t bInterface; /* Interface number */ + uint8_t bAlternate; /* Alternate setting */ +} VBOXUSBREQ_SET_INTERFACE, *PVBOXUSBREQ_SET_INTERFACE; + +typedef enum +{ + /** Close device not a reset. */ + VBOXUSB_RESET_LEVEL_CLOSE = 0, + /** Hard reset resulting in device replug behaviour. */ + VBOXUSB_RESET_LEVEL_REATTACH = 2, + /** Device-level reset. */ + VBOXUSB_RESET_LEVEL_SOFT = 4 +} VBOXUSB_RESET_LEVEL; + +typedef struct +{ + VBOXUSB_RESET_LEVEL ResetLevel; /* Reset level after closing */ +} VBOXUSBREQ_CLOSE_DEVICE, *PVBOXUSBREQ_CLOSE_DEVICE; + +typedef struct +{ + uint8_t bEndpoint; /* Endpoint address */ +} VBOXUSBREQ_ABORT_PIPE, *PVBOXUSBREQ_ABORT_PIPE; + +typedef struct +{ + uint32_t u32Major; /* Driver major number */ + uint32_t u32Minor; /* Driver minor number */ +} VBOXUSBREQ_GET_VERSION, *PVBOXUSBREQ_GET_VERSION; + +#pragma pack() + +/** The VBOXUSBREQ::u32Magic value for VBoxUSBMon. */ +#define VBOXUSBMON_MAGIC 0xba5eba11 +/** The VBOXUSBREQ::u32Magic value for VBoxUSB.*/ +#define VBOXUSB_MAGIC 0x601fba11 +/** The USBLib entry point for userland. */ +#define VBOXUSB_DEVICE_NAME "/dev/vboxusbmon" + +/** The USBMonitor Major version. */ +#define VBOXUSBMON_VERSION_MAJOR 2 +/** The USBMonitor Minor version. */ +#define VBOXUSBMON_VERSION_MINOR 1 + +/** The USB Major version. */ +#define VBOXUSB_VERSION_MAJOR 1 +/** The USB Minor version. */ +#define VBOXUSB_VERSION_MINOR 1 + +#ifdef RT_ARCH_AMD64 +# define VBOXUSB_IOCTL_FLAG 128 +#elif defined(RT_ARCH_X86) +# define VBOXUSB_IOCTL_FLAG 0 +#else +# error "dunno which arch this is!" +#endif + +/** USB driver name*/ +#define VBOXUSB_DRIVER_NAME "vboxusb" + +/* No automatic buffering, size limited to 255 bytes => use VBOXUSBREQ for everything. */ +#define VBOXUSB_IOCTL_CODE(Function, Size) _IOWRN('V', (Function) | VBOXUSB_IOCTL_FLAG, sizeof(VBOXUSBREQ)) +#define VBOXUSB_IOCTL_CODE_FAST(Function) _IO( 'V', (Function) | VBOXUSB_IOCTL_FLAG) +#define VBOXUSB_IOCTL_STRIP_SIZE(Code) (Code) + +#define VBOXUSBMON_IOCTL_ADD_FILTER VBOXUSB_IOCTL_CODE(1, (sizeof(VBoxUSBAddFilterReq))) +#define VBOXUSBMON_IOCTL_REMOVE_FILTER VBOXUSB_IOCTL_CODE(2, (sizeof(VBoxUSBRemoveFilterReq))) +#define VBOXUSBMON_IOCTL_RESET_DEVICE VBOXUSB_IOCTL_CODE(3, (sizeof(VBOXUSBREQ_RESET_DEVICE))) +#define VBOXUSBMON_IOCTL_DEVICE_INSTANCE VBOXUSB_IOCTL_CODE(4, (sizeof(VBOXUSBREQ_DEVICE_INSTANCE))) +#define VBOXUSBMON_IOCTL_CLIENT_INFO VBOXUSB_IOCTL_CODE(5, (sizeof(VBOXUSBREQ_CLIENT_PATH))) +#define VBOXUSBMON_IOCTL_GET_VERSION VBOXUSB_IOCTL_CODE(6, (sizeof(VBOXUSBREQ_GET_VERSION))) + +/* VBoxUSB ioctls */ +#define VBOXUSB_IOCTL_SEND_URB VBOXUSB_IOCTL_CODE(20, (sizeof(VBOXUSBREQ_URB))) /* 1072146796 */ +#define VBOXUSB_IOCTL_REAP_URB VBOXUSB_IOCTL_CODE(21, (sizeof(VBOXUSBREQ_URB))) /* 1072146795 */ +#define VBOXUSB_IOCTL_CLEAR_EP VBOXUSB_IOCTL_CODE(22, (sizeof(VBOXUSBREQ_CLEAR_EP))) /* 1072146794 */ +#define VBOXUSB_IOCTL_SET_CONFIG VBOXUSB_IOCTL_CODE(23, (sizeof(VBOXUSBREQ_SET_CONFIG))) /* 1072146793 */ +#define VBOXUSB_IOCTL_SET_INTERFACE VBOXUSB_IOCTL_CODE(24, (sizeof(VBOXUSBREQ_SET_INTERFACE))) /* 1072146792 */ +#define VBOXUSB_IOCTL_CLOSE_DEVICE VBOXUSB_IOCTL_CODE(25, (sizeof(VBOXUSBREQ_CLOSE_DEVICE))) /* 1072146791 0xc0185699 */ +#define VBOXUSB_IOCTL_ABORT_PIPE VBOXUSB_IOCTL_CODE(26, (sizeof(VBOXUSBREQ_ABORT_PIPE))) /* 1072146790 */ +#define VBOXUSB_IOCTL_GET_CONFIG VBOXUSB_IOCTL_CODE(27, (sizeof(VBOXUSBREQ_GET_CONFIG))) /* 1072146789 */ +#define VBOXUSB_IOCTL_GET_VERSION VBOXUSB_IOCTL_CODE(28, (sizeof(VBOXUSBREQ_GET_VERSION))) /* 1072146788 */ + +/** @} */ + +/* USBLibHelper data for resetting the device. */ +typedef struct VBOXUSBHELPERDATA_RESET +{ + /** Path of the USB device. */ + const char *pszDevicePath; + /** Re-enumerate or not. */ + bool fHardReset; +} VBOXUSBHELPERDATA_RESET; +typedef VBOXUSBHELPERDATA_RESET *PVBOXUSBHELPERDATA_RESET; +typedef const VBOXUSBHELPERDATA_RESET *PCVBOXUSBHELPERDATA_RESET; + +/* USBLibHelper data for device hijacking. */ +typedef struct VBOXUSBHELPERDATA_ALIAS +{ + /** Vendor ID. */ + uint16_t idVendor; + /** Product ID. */ + uint16_t idProduct; + /** Revision, integer part. */ + uint16_t bcdDevice; + /** Path of the USB device. */ + const char *pszDevicePath; +} VBOXUSBHELPERDATA_ALIAS; +typedef VBOXUSBHELPERDATA_ALIAS *PVBOXUSBHELPERDATA_ALIAS; +typedef const VBOXUSBHELPERDATA_ALIAS *PCVBOXUSBHELPERDATA_ALIAS; + +USBLIB_DECL(int) USBLibResetDevice(char *pszDevicePath, bool fReattach); +USBLIB_DECL(int) USBLibDeviceInstance(char *pszDevicePath, int *pInstance); +USBLIB_DECL(int) USBLibGetClientInfo(char *pszDeviceIdent, char **ppszClientPath, int *pInstance); +USBLIB_DECL(int) USBLibAddDeviceAlias(PUSBDEVICE pDevice); +USBLIB_DECL(int) USBLibRemoveDeviceAlias(PUSBDEVICE pDevice); +/*USBLIB_DECL(int) USBLibConfigureDevice(PUSBDEVICE pDevice);*/ + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_usblib_solaris_h */ + diff --git a/include/VBox/usblib-win.h b/include/VBox/usblib-win.h new file mode 100644 index 00000000..24b26c6d --- /dev/null +++ b/include/VBox/usblib-win.h @@ -0,0 +1,309 @@ +/** @file + * USBLib - Library for wrapping up the VBoxUSB functionality, Windows flavor. + * (DEV,HDrv,Main) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_usblib_win_h +#define VBOX_INCLUDED_usblib_win_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +#include + + +/** @defgroup grp_usblib_win Windows USB Specifics + * @ingroup grp_usblib + * @{ + */ + +// {6068EB61-98E7-4c98-9E20-1F068295909A} +DEFINE_GUID(GUID_CLASS_VBOXUSB, 0x873fdf, 0xCAFE, 0x80EE, 0xaa, 0x5e, 0x0, 0xc0, 0x4f, 0xb1, 0x72, 0xb); + +#define USBFLT_SERVICE_NAME "\\\\.\\VBoxUSBFlt" +#define USBFLT_NTDEVICE_NAME_STRING L"\\Device\\VBoxUSBFlt" +#define USBFLT_SYMBOLIC_NAME_STRING L"\\DosDevices\\VBoxUSBFlt" + +#define USBMON_SERVICE_NAME_W L"VBoxUSBMon" +#define USBMON_DEVICE_NAME "\\\\.\\VBoxUSBMon" +#define USBMON_DEVICE_NAME_NT L"\\Device\\VBoxUSBMon" +#define USBMON_DEVICE_NAME_DOS L"\\DosDevices\\VBoxUSBMon" + +/* + * IOCtl numbers. + * We're using the Win32 type of numbers here, thus the macros below. + */ + +#ifndef CTL_CODE +# if defined(RT_OS_WINDOWS) +# define CTL_CODE(DeviceType, Function, Method, Access) \ + ( ((DeviceType) << 16) | ((Access) << 14) | ((Function) << 2) | (Method)) +#else /* unix: */ +# define CTL_CODE(DeviceType, Function, Method_ignored, Access_ignored) \ + ( (3 << 30) | ((DeviceType) << 8) | (Function) | (sizeof(SUPDRVIOCTLDATA) << 16) ) +# endif +#endif +#ifndef METHOD_BUFFERED +# define METHOD_BUFFERED 0 +#endif +#ifndef FILE_WRITE_ACCESS +# define FILE_WRITE_ACCESS 0x0002 +#endif +#ifndef FILE_DEVICE_UNKNOWN +# define FILE_DEVICE_UNKNOWN 0x00000022 +#endif + +#define USBMON_MAJOR_VERSION 5 +#define USBMON_MINOR_VERSION 0 + +#define USBDRV_MAJOR_VERSION 5 +#define USBDRV_MINOR_VERSION 0 + +#define SUPUSB_IOCTL_TEST CTL_CODE(FILE_DEVICE_UNKNOWN, 0x601, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_GET_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x603, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_SEND_URB CTL_CODE(FILE_DEVICE_UNKNOWN, 0x607, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_RESET CTL_CODE(FILE_DEVICE_UNKNOWN, 0x608, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_SELECT_INTERFACE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x609, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_SET_CONFIG CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60A, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_CLAIM_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60B, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_RELEASE_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60C, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_IS_OPERATIONAL CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60D, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_CLEAR_ENDPOINT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60E, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60F, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSB_IOCTL_USB_ABORT_ENDPOINT CTL_CODE(FILE_DEVICE_UNKNOWN, 0x610, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +#define SUPUSBFLT_IOCTL_GET_NUM_DEVICES CTL_CODE(FILE_DEVICE_UNKNOWN, 0x602, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_USB_CHANGE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x604, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_DISABLE_CAPTURE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x605, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_ENABLE_CAPTURE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x606, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_IGNORE_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x60F, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_GET_VERSION CTL_CODE(FILE_DEVICE_UNKNOWN, 0x610, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_ADD_FILTER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x611, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_REMOVE_FILTER CTL_CODE(FILE_DEVICE_UNKNOWN, 0x612, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_CAPTURE_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x613, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_RELEASE_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x614, METHOD_BUFFERED, FILE_WRITE_ACCESS) +#define SUPUSBFLT_IOCTL_RUN_FILTERS CTL_CODE(FILE_DEVICE_UNKNOWN, 0x615, METHOD_BUFFERED, FILE_WRITE_ACCESS) +/* Used to be SUPUSBFLT_IOCTL_SET_NOTIFY_EVENT, 0x616 */ +#define SUPUSBFLT_IOCTL_GET_DEVICE CTL_CODE(FILE_DEVICE_UNKNOWN, 0x617, METHOD_BUFFERED, FILE_WRITE_ACCESS) + +#pragma pack(4) + +#define MAX_FILTER_NAME 128 +#define MAX_USB_SERIAL_STRING 64 + +/* a user-mode handle that could be used for retriving device information + * from the monitor driver */ +typedef void* HVBOXUSBDEVUSR; + +typedef struct +{ + HVBOXUSBDEVUSR hDevice; +} USBSUP_GETDEV, *PUSBSUP_GETDEV; + +typedef struct +{ + USBDEVICESTATE enmState; +} USBSUP_GETDEV_MON, *PUSBSUP_GETDEV_MON; + +typedef struct +{ + uint32_t u32Major; + uint32_t u32Minor; +} USBSUP_VERSION, *PUSBSUP_VERSION; + + +typedef struct USBSUP_FLTADDOUT +{ + uintptr_t uId; /* The ID. */ + int rc; /* The return code. */ +} USBSUP_FLTADDOUT, *PUSBSUP_FLTADDOUT; + +typedef struct +{ + uint16_t usVendorId; + uint16_t usProductId; + uint16_t usRevision; +} USBSUP_CAPTURE, *PUSBSUP_CAPTURE; + +typedef USBSUP_CAPTURE USBSUP_RELEASE; +typedef PUSBSUP_CAPTURE PUSBSUP_RELEASE; + +typedef struct +{ + uint8_t bInterfaceNumber; + uint8_t fClaimed; +} USBSUP_CLAIMDEV, *PUSBSUP_CLAIMDEV; + +typedef USBSUP_CLAIMDEV USBSUP_RELEASEDEV; +typedef PUSBSUP_CLAIMDEV PUSBSUP_RELEASEDEV; + +typedef struct +{ + uint32_t cUSBDevices; +} USBSUP_GETNUMDEV, *PUSBSUP_GETNUMDEV; + +typedef struct +{ + uint8_t fUSBChange; + uint32_t cUSBStateChange; +} USBSUP_USB_CHANGE, *PUSBSUP_USB_CHANGE; + +typedef struct +{ + uint8_t bConfigurationValue; +} USBSUP_SET_CONFIG, *PUSBSUP_SET_CONFIG; + +typedef struct +{ + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; +} USBSUP_SELECT_INTERFACE, *PUSBSUP_SELECT_INTERFACE; + +typedef struct +{ + uint8_t bEndpoint; +} USBSUP_CLEAR_ENDPOINT, *PUSBSUP_CLEAR_ENDPOINT; + +typedef enum +{ + USBSUP_TRANSFER_TYPE_CTRL = 0, + USBSUP_TRANSFER_TYPE_ISOC = 1, + USBSUP_TRANSFER_TYPE_BULK = 2, + USBSUP_TRANSFER_TYPE_INTR = 3, + USBSUP_TRANSFER_TYPE_MSG = 4 +} USBSUP_TRANSFER_TYPE; + +typedef enum +{ + USBSUP_DIRECTION_SETUP = 0, + USBSUP_DIRECTION_IN = 1, + USBSUP_DIRECTION_OUT = 2 +} USBSUP_DIRECTION; + +typedef enum +{ + USBSUP_FLAG_NONE = 0, + USBSUP_FLAG_SHORT_OK = 1 +} USBSUP_XFER_FLAG; + +typedef enum +{ + USBSUP_XFER_OK = 0, + USBSUP_XFER_STALL = 1, + USBSUP_XFER_DNR = 2, + USBSUP_XFER_CRC = 3, + USBSUP_XFER_NAC = 4, + USBSUP_XFER_UNDERRUN = 5, + USBSUP_XFER_OVERRUN = 6 +} USBSUP_ERROR; + +typedef struct USBSUP_ISOCPKT +{ + uint16_t cb; /* [in/out] packet size/size transferred */ + uint16_t off; /* [in] offset of packet in buffer */ + USBSUP_ERROR stat; /* [out] packet status */ +} USBSUP_ISOCPKT; + +typedef struct +{ + USBSUP_TRANSFER_TYPE type; /* [in] USBSUP_TRANSFER_TYPE_XXX */ + uint32_t ep; /* [in] index to dev->pipe */ + USBSUP_DIRECTION dir; /* [in] USBSUP_DIRECTION_XXX */ + USBSUP_XFER_FLAG flags; /* [in] USBSUP_FLAG_XXX */ + USBSUP_ERROR error; /* [out] USBSUP_XFER_XXX */ + size_t len; /* [in/out] may change */ + void *buf; /* [in/out] depends on dir */ + uint32_t numIsoPkts; /* [in] number of isochronous packets (8 max) */ + USBSUP_ISOCPKT aIsoPkts[8]; /* [in/out] isochronous packet descriptors */ +} USBSUP_URB, *PUSBSUP_URB; + +typedef struct +{ + union + { + /* in: event handle */ + void* hEvent; + /* out: result */ + int rc; + } u; +} USBSUP_SET_NOTIFY_EVENT, *PUSBSUP_SET_NOTIFY_EVENT; + +typedef struct +{ + uint16_t usVendorId; + uint16_t usProductId; + uint16_t usRevision; + uint16_t usAlignment; + char DrvKeyName[512]; +} USBSUP_DEVID, *PUSBSUP_DEVID; + +#pragma pack() /* paranoia */ + + +RT_C_DECLS_BEGIN + +#ifdef IN_RING3 + +/** @defgroup grp_usblib_r3 USBLIB Host Context Ring 3 API + * @{ + */ + +/** + * Return all attached USB devices. + * + * @returns VBox status code + * @param ppDevices Receives pointer to list of devices + * @param pcbNumDevices Number of USB devices in the list + */ +USBLIB_DECL(int) USBLibGetDevices(PUSBDEVICE *ppDevices, uint32_t *pcbNumDevices); + +USBLIB_DECL(int) USBLibWaitChange(RTMSINTERVAL cMillies); + +USBLIB_DECL(int) USBLibInterruptWaitChange(void); + +USBLIB_DECL(int) USBLibRunFilters(void); + +/** @} */ +#endif + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_usblib_win_h */ + diff --git a/include/VBox/usblib.h b/include/VBox/usblib.h new file mode 100644 index 00000000..13fc690e --- /dev/null +++ b/include/VBox/usblib.h @@ -0,0 +1,196 @@ +/** @file + * USBLib - Library for wrapping up the VBoxUSB functionality. (DEV,HDrv,Main) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_usblib_h +#define VBOX_INCLUDED_usblib_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +#ifdef RT_OS_WINDOWS +# include +#endif +#ifdef RT_OS_SOLARIS +# include +#endif +#ifdef RT_OS_DARWIN +# include +#endif +/** @todo merge the usblib-win.h interface into the darwin and linux ports where suitable. */ + +RT_C_DECLS_BEGIN +/** @defgroup grp_usblib USBLib - USB Support Library + * This module implements the basic low-level OS interfaces and common USB code. + * @{ + */ + +#ifdef IN_RING3 +/** + * Initializes the USBLib component. + * + * The USBLib keeps a per process connection to the kernel driver + * and all USBLib users within a process will share the same + * connection. USBLib does reference counting to make sure that + * the connection remains open until all users has called USBLibTerm(). + * + * @returns VBox status code. + * + * @remark The users within the process are responsible for not calling + * this function at the same time (because I'm lazy). + */ +USBLIB_DECL(int) USBLibInit(void); + +/** + * Terminates the USBLib component. + * + * Must match successful USBLibInit calls. + * + * @returns VBox status code. + */ +USBLIB_DECL(int) USBLibTerm(void); + +/** + * Adds a filter. + * + * This function will validate and transfer the specified filter + * to the kernel driver and make it start using it. The kernel + * driver will return a filter id that this function passes on + * to its caller. + * + * The kernel driver will associate the added filter with the + * calling process and automatically remove all filters when + * the process terminates the connection to it or dies. + * + * @returns Filter id for passing to USBLibRemoveFilter on success. + * @returns NULL on failure. + * + * @param pFilter The filter to add. + */ +USBLIB_DECL(void *) USBLibAddFilter(PCUSBFILTER pFilter); + +/** + * Removes a filter. + * + * @param pvId The ID returned by USBLibAddFilter. + */ +USBLIB_DECL(void) USBLibRemoveFilter(void *pvId); + +/** + * Calculate the hash of the serial string. + * + * 64bit FNV1a, chosen because it is designed to hash in to a power of two + * space, and is much quicker and simpler than, say, a half MD4. + * + * @returns the hash. + * @param pszSerial The serial string. + */ +USBLIB_DECL(uint64_t) USBLibHashSerial(const char *pszSerial); + +#endif /* IN_RING3 */ + +/** + * Purge string of non-UTF-8 encodings and control characters. + * + * Control characters creates problems when presented to the user and currently + * also when used in XML settings. So, we must purge them in the USB vendor, + * product, and serial number strings. + * + * @returns String length (excluding terminator). + * @param psz The string to purge. + * + * @remarks The return string may be shorter than the input, left over space + * after the end of the string will be filled with zeros. + */ +DECLINLINE(size_t) USBLibPurgeEncoding(char *psz) +{ + if (psz) + { + size_t offSrc; + + /* Beat it into valid UTF-8 encoding. */ + RTStrPurgeEncoding(psz); + + /* Look for control characters. */ + for (offSrc = 0; ; offSrc++) + { + char ch = psz[offSrc]; + if (RT_UNLIKELY(RT_C_IS_CNTRL(ch) && ch != '\0')) + { + /* Found a control character! Replace tab by space and remove all others. */ + size_t offDst = offSrc; + for (;; offSrc++) + { + ch = psz[offSrc]; + if (RT_C_IS_CNTRL(ch) && ch != '\0') + { + if (ch == '\t') + ch = ' '; + else + continue; + } + psz[offDst++] = ch; + if (ch == '\0') + break; + } + + /* Wind back to the zero terminator and zero fill any gap to make + USBFilterValidate happy. (offSrc is at zero terminator too.) */ + offDst--; + while (offSrc > offDst) + psz[offSrc--] = '\0'; + + return offDst; + } + if (ch == '\0') + break; + } + return offSrc; + } + return 0; +} + + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_usblib_h */ + diff --git a/include/VBox/various.sed b/include/VBox/various.sed new file mode 100644 index 00000000..8797b029 --- /dev/null +++ b/include/VBox/various.sed @@ -0,0 +1,148 @@ +# $Id: various.sed $ +## @file +# Converts some C header elements into nasm/yasm syntax. +# +# This is used by 'incs' in /Maintenance.kmk (/Makefile.kmk). +# + +# +# Copyright (C) 2006-2022 Oracle and/or its affiliates. +# +# This file is part of VirtualBox base platform packages, as +# available from https://www.virtualbox.org. +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation, in version 3 of the +# License. +# +# This program is distributed in the hope that it will be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, see . +# +# The contents of this file may alternatively be used under the terms +# of the Common Development and Distribution License Version 1.0 +# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +# in the VirtualBox distribution, in which case the provisions of the +# CDDL are applicable instead of those of the GPL. +# +# You may elect to license modified versions of this file under the +# terms and conditions of either the GPL or the CDDL or both. +# +# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +# + +# Pass thru the file header and copyright. +1,/^\#ifndef/{ +/^\#ifndef/b next +s/^[/ ]// +s/^\*\//;/ +s/\*/;/g +4s/^.*$/; Automatically generated by various.sed. DO NOT EDIT!/ +b end +} +:next + +# Check for markers (typically in comments). +/ASM-INC/basm-inc +/ASM-NOINC/basm-noinc + +# Newline escapes. +:check-newline-escape +/\\$/!bno-more-newline-escapes +N +b check-newline-escape +:no-more-newline-escapes + +# Strip comments and trailing space. +s/[[:space:]][[:space:]]*\/\*.*$//g +s/[[:space:]][[:space:]]*\/\/.*$//g +s/[[:space:]][[:space:]]*$//g + +# Try identify the statement. +/#[[:space:]]*define[[:space:]]/bdefine +/#[[:space:]]*ifdef[[:space:]]/bifdef +/#[[:space:]]*ifndef[[:space:]]/bifndef +/#[[:space:]]*if[[:space:]]/bif +/#[[:space:]]*elif[[:space:]]/belif +/#[[:space:]]*else$/belse +/#[[:space:]]*endif$/bendif + +# Not recognized, drop it. +:asm-noinc +d +b end + +# +# Defines needs some extra massaging to work in yasm. +# Things like trailing type indicators ('U', 'ULL' ++) does not go down well. +# +:define +/\$/d +s/#\([[:space:]]*\)define/\1%define/ + +s/\([[:space:]]0[xX][0-9a-fA-F][0-9a-fA-F]*\)U$/\1/ +s/\([[:space:]]0[xX][0-9a-fA-F][0-9a-fA-F]*\)U\([[:space:]]*\))$/\1\2)/ +s/\([[:space:]][0-9][0-9]*\)U[[:space:]]*$/\1/ +s/\([[:space:]][0-9][0-9]*\)U\([[:space:]]*\))$/\1\2)/ + +s/\([[:space:]]0[xX][0-9a-fA-F][0-9a-fA-F]*\)UL$/\1/ +s/\([[:space:]]0[xX][0-9a-fA-F][0-9a-fA-F]*\)UL\([[:space:]]*\))$/\1\2)/ +s/\([[:space:]][0-9][0-9]*\)UL[[:space:]]*$/\1/ +s/\([[:space:]][0-9][0-9]*\)UL\([[:space:]]*\))$/\1\2)/ + +s/\([[:space:]]0[xX][0-9a-fA-F][0-9a-fA-F]*\)ULL$/\1/ +s/\([[:space:]]0[xX][0-9a-fA-F][0-9a-fA-F]*\)ULL\([[:space:]]*\))$/\1\2)/ +s/\([[:space:]][0-9][0-9]*\)ULL[[:space:]]*$/\1/ +s/\([[:space:]][0-9][0-9]*\)ULL\([[:space:]]*\))$/\1\2)/ + +s/UINT64_C([[:space:]]*\(0[xX][0-9a-fA-F][0-9a-fA-F]*\)[[:space:]]*)/\1/ +s/UINT64_C([[:space:]]*\([0-9][0-9]*\)[[:space:]]*)/\1/ +s/UINT32_C([[:space:]]*\(0[xX][0-9a-fA-F][0-9a-fA-F]*\)[[:space:]]*)/\1/ +s/UINT32_C([[:space:]]*\([0-9][0-9]*\)[[:space:]]*)/\1/ +s/UINT16_C([[:space:]]*\(0[xX][0-9a-fA-F][0-9a-fA-F]*\)[[:space:]]*)/\1/ +s/UINT16_C([[:space:]]*\([0-9][0-9]*\)[[:space:]]*)/\1/ +s/UINT8_C([[:space:]]*\(0[xX][0-9a-fA-F][0-9a-fA-F]*\)[[:space:]]*)/\1/ +s/UINT8_C([[:space:]]*\([0-9][0-9]*\)[[:space:]]*)/\1/ + +b end + +# +# Conditional statements, 1:1. +# +:ifdef +s/#\([[:space:]]*\)ifdef/\1%ifdef/ +b end + +:ifndef +s/#\([[:space:]]*\)ifndef/\1%ifndef/ +b end + +:if +s/#\([[:space:]]*\)if/\1%if/ +b end + +:elif +s/#\([[:space:]]*\)elif/\1%elif/ +b end + +:else +s/#\([[:space:]]*\)else.*$/\1%else/ +b end + +:endif +s/#\([[:space:]]*\)endif.*$/\1%endif/ +b end + +# +# Assembly statement... may need adjusting when used. +# +:asm-inc +b end + +:end + diff --git a/include/VBox/vd-cache-backend.h b/include/VBox/vd-cache-backend.h new file mode 100644 index 00000000..c2d7163f --- /dev/null +++ b/include/VBox/vd-cache-backend.h @@ -0,0 +1,332 @@ +/** @file + * Internal hard disk format support API for VBoxHDD cache images. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_cache_backend_h +#define VBOX_INCLUDED_vd_cache_backend_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +/** + * Cache format backend interface used by VBox HDD Container implementation. + */ +typedef struct VDCACHEBACKEND +{ + /** Structure version. VD_CACHEBACKEND_VERSION defines the current version. */ + uint32_t u32Version; + /** The name of the backend (constant string). */ + const char *pszBackendName; + /** The capabilities of the backend. */ + uint64_t uBackendCaps; + + /** + * Pointer to a NULL-terminated array of strings, containing the supported + * file extensions. Note that some backends do not work on files, so this + * pointer may just contain NULL. + */ + const char * const *papszFileExtensions; + + /** + * Pointer to an array of structs describing each supported config key. + * Terminated by a NULL config key. Note that some backends do not support + * the configuration interface, so this pointer may just contain NULL. + * Mandatory if the backend sets VD_CAP_CONFIG. + */ + PCVDCONFIGINFO paConfigInfo; + + /** + * Probes the given image. + * + * @returns VBox status code. + * @param pszFilename Name of the image file. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + */ + DECLR3CALLBACKMEMBER(int, pfnProbe, (const char *pszFilename, PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage)); + + /** + * Open a cache image. + * + * @returns VBox status code. + * @param pszFilename Name of the image file to open. Guaranteed to be available and + * unchanged during the lifetime of this image. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param ppBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(int, pfnOpen, (const char *pszFilename, unsigned uOpenFlags, + PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage, + void **ppBackendData)); + + /** + * Create a cache image. + * + * @returns VBox status code. + * @param pszFilename Name of the image file to create. Guaranteed to be available and + * unchanged during the lifetime of this image. + * @param cbSize Image size in bytes. + * @param uImageFlags Flags specifying special image features. + * @param pszComment Pointer to image comment. NULL is ok. + * @param pUuid New UUID of the image. Not NULL. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param uPercentStart Starting value for progress percentage. + * @param uPercentSpan Span for varying progress percentage. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + * @param ppBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(int, pfnCreate, (const char *pszFilename, uint64_t cbSize, + unsigned uImageFlags, const char *pszComment, + PCRTUUID pUuid, unsigned uOpenFlags, + unsigned uPercentStart, unsigned uPercentSpan, + PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation, + void **ppBackendData)); + + /** + * Close a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param fDelete If true, delete the image from the host disk. + */ + DECLR3CALLBACKMEMBER(int, pfnClose, (void *pBackendData, bool fDelete)); + + /** + * Start a read request. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param uOffset The offset of the virtual disk to read from. + * @param cbToRead How many bytes to read. + * @param pIoCtx I/O context associated with this request. + * @param pcbActuallyRead Pointer to returned number of bytes read. + */ + DECLR3CALLBACKMEMBER(int, pfnRead, (void *pBackendData, uint64_t uOffset, size_t cbToRead, + PVDIOCTX pIoCtx, size_t *pcbActuallyRead)); + + /** + * Start a write request. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param uOffset The offset of the virtual disk to write to. + * @param cbToWrite How many bytes to write. + * @param pIoCtx I/O context associated with this request. + * @param pcbWriteProcess Pointer to returned number of bytes that could + * be processed. In case the function returned + * VERR_VD_BLOCK_FREE this is the number of bytes + * that could be written in a full block write, + * when prefixed/postfixed by the appropriate + * amount of (previously read) padding data. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite, (void *pBackendData, uint64_t uOffset, size_t cbToWrite, + PVDIOCTX pIoCtx, size_t *pcbWriteProcess)); + + /** + * Flush data to disk. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pIoCtx I/O context associated with this request. + */ + DECLR3CALLBACKMEMBER(int, pfnFlush, (void *pBackendData, PVDIOCTX pIoCtx)); + + /** + * Discards the given amount of bytes from the cache. + * + * @returns VBox status code. + * @retval VERR_VD_DISCARD_ALIGNMENT_NOT_MET if the range doesn't meet the required alignment + * for the discard. + * @param pBackendData Opaque state data for this image. + * @param pIoCtx I/O context associated with this request. + * @param uOffset The offset of the first byte to discard. + * @param cbDiscard How many bytes to discard. + */ + DECLR3CALLBACKMEMBER(int, pfnDiscard, (void *pBackendData, PVDIOCTX pIoCtx, + uint64_t uOffset, size_t cbDiscard, + size_t *pcbPreAllocated, + size_t *pcbPostAllocated, + size_t *pcbActuallyDiscarded, + void **ppbmAllocationBitmap, + unsigned fDiscard)); + + /** + * Get the version of a cache image. + * + * @returns version of cache image. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetVersion, (void *pBackendData)); + + /** + * Get the capacity of a cache image. + * + * @returns size of cache image in bytes. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetSize, (void *pBackendData)); + + /** + * Get the file size of a cache image. + * + * @returns size of cache image in bytes. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetFileSize, (void *pBackendData)); + + /** + * Get the image flags of a cache image. + * + * @returns image flags of cache image. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetImageFlags, (void *pBackendData)); + + /** + * Get the open flags of a cache image. + * + * @returns open flags of cache image. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetOpenFlags, (void *pBackendData)); + + /** + * Set the open flags of a cache image. May cause the image to be locked + * in a different mode or be reopened (which can fail). + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param uOpenFlags New open flags for this image. + */ + DECLR3CALLBACKMEMBER(int, pfnSetOpenFlags, (void *pBackendData, unsigned uOpenFlags)); + + /** + * Get comment of a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pszComment Where to store the comment. + * @param cbComment Size of the comment buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnGetComment, (void *pBackendData, char *pszComment, size_t cbComment)); + + /** + * Set comment of a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pszComment Where to get the comment from. NULL resets comment. + * The comment is silently truncated if the image format + * limit is exceeded. + */ + DECLR3CALLBACKMEMBER(int, pfnSetComment, (void *pBackendData, const char *pszComment)); + + /** + * Get UUID of a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to store the image UUID. + */ + DECLR3CALLBACKMEMBER(int, pfnGetUuid, (void *pBackendData, PRTUUID pUuid)); + + /** + * Set UUID of a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to get the image UUID from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetUuid, (void *pBackendData, PCRTUUID pUuid)); + + /** + * Get last modification UUID of a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to store the image modification UUID. + */ + DECLR3CALLBACKMEMBER(int, pfnGetModificationUuid, (void *pBackendData, PRTUUID pUuid)); + + /** + * Set last modification UUID of a cache image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to get the image modification UUID from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetModificationUuid, (void *pBackendData, PCRTUUID pUuid)); + + /** + * Dump information about a cache image. + * + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(void, pfnDump, (void *pBackendData)); + + /** Returns a human readable hard disk location string given a + * set of hard disk configuration keys. The returned string is an + * equivalent of the full file path for image-based hard disks. + * Mandatory for backends with no VD_CAP_FILE and NULL otherwise. */ + DECLR3CALLBACKMEMBER(int, pfnComposeLocation, (PVDINTERFACE pConfig, char **pszLocation)); + + /** Returns a human readable hard disk name string given a + * set of hard disk configuration keys. The returned string is an + * equivalent of the file name part in the full file path for + * image-based hard disks. Mandatory for backends with no + * VD_CAP_FILE and NULL otherwise. */ + DECLR3CALLBACKMEMBER(int, pfnComposeName, (PVDINTERFACE pConfig, char **pszName)); + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; + +} VDCACHEBACKEND; +/** Pointer to VD cache backend. */ +typedef VDCACHEBACKEND *PVDCACHEBACKEND; +/** Constant pointer to VD backend. */ +typedef const VDCACHEBACKEND *PCVDCACHEBACKEND; + +/** The current version of the VDCACHEBACKEND structure. */ +#define VD_CACHEBACKEND_VERSION VD_VERSION_MAKE(0xff03, 1, 0) + +#endif /* !VBOX_INCLUDED_vd_cache_backend_h */ diff --git a/include/VBox/vd-common.h b/include/VBox/vd-common.h new file mode 100644 index 00000000..6c65e13a --- /dev/null +++ b/include/VBox/vd-common.h @@ -0,0 +1,76 @@ +/** @file + * VD: common definitions for the registration, backend and interface structures. + */ + +/* + * Copyright (C) 2016-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_common_h +#define VBOX_INCLUDED_vd_common_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** Makes a VD structure version out of an unique magic value and major & + * minor version numbers. + * + * @returns 32-bit structure version number. + * + * @param uMagic 16-bit magic value. This must be unique. + * @param uMajor 12-bit major version number. Structures with different + * major numbers are not compatible. + * @param uMinor 4-bit minor version number. When only the minor version + * differs, the structures will be 100% backwards + * compatible. + */ +#define VD_VERSION_MAKE(uMagic, uMajor, uMinor) \ + ( ((uint32_t)(uMagic) << 16) | ((uint32_t)((uMajor) & 0xff) << 4) | ((uint32_t)((uMinor) & 0xf) << 0) ) + +/** Checks if @a uVerMagic1 is compatible with @a uVerMagic2. + * + * @returns true / false. + * @param uVerMagic1 Typically the runtime version of the struct. This must + * have the same magic and major version as @a uVerMagic2 + * and the minor version must be greater or equal to that + * of @a uVerMagic2. + * @param uVerMagic2 Typically the version the code was compiled against. + * + * @remarks The parameters will be referenced more than once. + */ +#define VD_VERSION_ARE_COMPATIBLE(uVerMagic1, uVerMagic2) \ + ( (uVerMagic1) == (uVerMagic2) \ + || ( (uVerMagic1) >= (uVerMagic2) \ + && ((uVerMagic1) & UINT32_C(0xfffffff0)) == ((uVerMagic2) & UINT32_C(0xfffffff0)) ) \ + ) + +#endif /* !VBOX_INCLUDED_vd_common_h */ diff --git a/include/VBox/vd-filter-backend.h b/include/VBox/vd-filter-backend.h new file mode 100644 index 00000000..ab45253f --- /dev/null +++ b/include/VBox/vd-filter-backend.h @@ -0,0 +1,122 @@ +/** @file + * Internal VD filter backend interface. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_filter_backend_h +#define VBOX_INCLUDED_vd_filter_backend_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +/** + * VD filter backend interface. + */ +typedef struct VDFILTERBACKEND +{ + /** Structure version. VD_FLTBACKEND_VERSION defines the current version. */ + uint32_t u32Version; + /** The name of the backend (constant string). */ + const char *pszBackendName; + + /** + * Pointer to an array of structs describing each supported config key. + * Terminated by a NULL config key. Note that some backends do not support + * the configuration interface, so this pointer may just contain NULL. + * Mandatory if the backend sets VD_CAP_CONFIG. + */ + PCVDCONFIGINFO paConfigInfo; + + /** + * Creates a new filter instance. + * + * @returns VBox status code. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param fFlags Subset of VD_FILTER_FLAGS_*. + * @param pVDIfsFilter Pointer to the per-filter VD interface list. + * @param ppvBackendData Opaque state data for this filter instance. + */ + DECLR3CALLBACKMEMBER(int, pfnCreate, (PVDINTERFACE pVDIfsDisk, uint32_t fFlags, + PVDINTERFACE pVDIfsFilter, + void **ppvBackendData)); + + /** + * Destroys a filter instance. + * + * @returns VBox status code. + * @param pvBackendData Opaque state data for the filter instance to destroy. + */ + DECLR3CALLBACKMEMBER(int, pfnDestroy, (void *pvBackendData)); + + /** + * Filters the data of a read from the image chain. The filter is applied + * after everything was read. + * + * @returns VBox status code. + * @param pvBackendData Opaque state data for the filter instance. + * @param uOffset Start offset of the read. + * @param cbRead Number of bytes read. + * @param pIoCtx The I/O context holding the read data. + */ + DECLR3CALLBACKMEMBER(int, pfnFilterRead, (void *pvBackendData, uint64_t uOffset, size_t cbRead, + PVDIOCTX pIoCtx)); + + /** + * Filters the data of a write to the image chain. The filter is applied + * before everything is written. + * + * @returns VBox status code. + * @param pvBackendData Opaque state data for the filter instance. + * @param uOffset Start offset of the write. + * @param cbWrite Number of bytes to be written. + * @param pIoCtx The I/O context holding the data to write. + */ + DECLR3CALLBACKMEMBER(int, pfnFilterWrite, (void *pvBackendData, uint64_t uOffset, size_t cbWrite, + PVDIOCTX pIoCtx)); + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} VDFILTERBACKEND; +/** Pointer to VD filter backend. */ +typedef VDFILTERBACKEND *PVDFILTERBACKEND; +/** Constant pointer to a VD filter backend. */ +typedef const VDFILTERBACKEND *PCVDFILTERBACKEND; + +/** The current version of the VDFILTERBACKEND structure. */ +#define VD_FLTBACKEND_VERSION VD_VERSION_MAKE(0xff02, 1, 0) + +#endif /* !VBOX_INCLUDED_vd_filter_backend_h */ diff --git a/include/VBox/vd-ifs-internal.h b/include/VBox/vd-ifs-internal.h new file mode 100644 index 00000000..7bff7642 --- /dev/null +++ b/include/VBox/vd-ifs-internal.h @@ -0,0 +1,710 @@ +/** @file + * VD Container API - internal interfaces. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_ifs_internal_h +#define VBOX_INCLUDED_vd_ifs_internal_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @addtogroup grp_vd + * @internal + * @{ */ + +/** + * Read data callback. + * + * @return VBox status code. + * @return VERR_VD_NOT_OPENED if no image is opened in HDD container. + * @param pvUser The opaque data passed for the operation. + * @param uOffset Offset of first reading byte from start of disk. + * Must be aligned to a sector boundary. + * @param pvBuffer Pointer to buffer for reading data. + * @param cbBuffer Number of bytes to read. + * Must be aligned to a sector boundary. + */ +typedef DECLCALLBACKTYPE(int, FNVDPARENTREAD,(void *pvUser, uint64_t uOffset, void *pvBuffer, size_t cbBuffer)); +/** Pointer to a FNVDPARENTREAD. */ +typedef FNVDPARENTREAD *PFNVDPARENTREAD; + +/** + * Interface to get the parent state. + * + * Per-operation interface. Optional, present only if there is a parent, and + * used only internally for compacting. + */ +typedef struct VDINTERFACEPARENTSTATE +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Read data callback, see FNVDPARENTREAD for details. + */ + PFNVDPARENTREAD pfnParentRead; + +} VDINTERFACEPARENTSTATE, *PVDINTERFACEPARENTSTATE; + + +/** + * Get parent state interface from interface list. + * + * @return Pointer to the first parent state interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACEPARENTSTATE) VDIfParentStateGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_PARENTSTATE); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_PARENTSTATE) + && (pIf->cbSize == sizeof(VDINTERFACEPARENTSTATE))), + ("Not a parent state interface"), NULL); + + return (PVDINTERFACEPARENTSTATE)pIf; +} + +/** Forward declaration. Only visible in the VBoxHDD module. */ +/** I/O context */ +typedef struct VDIOCTX *PVDIOCTX; +/** Storage backend handle. */ +typedef struct VDIOSTORAGE *PVDIOSTORAGE; +/** Pointer to a storage backend handle. */ +typedef PVDIOSTORAGE *PPVDIOSTORAGE; + +/** + * Completion callback for meta/userdata reads or writes. + * + * @return VBox status code. + * VINF_SUCCESS if everything was successful and the transfer can continue. + * VERR_VD_ASYNC_IO_IN_PROGRESS if there is another data transfer pending. + * @param pBackendData The opaque backend data. + * @param pIoCtx I/O context associated with this request. + * @param pvUser Opaque user data passed during a read/write request. + * @param rcReq Status code for the completed request. + */ +typedef DECLCALLBACKTYPE(int, FNVDXFERCOMPLETED,(void *pBackendData, PVDIOCTX pIoCtx, void *pvUser, int rcReq)); +/** Pointer to FNVDXFERCOMPLETED() */ +typedef FNVDXFERCOMPLETED *PFNVDXFERCOMPLETED; + +/** Metadata transfer handle. */ +typedef struct VDMETAXFER *PVDMETAXFER; +/** Pointer to a metadata transfer handle. */ +typedef PVDMETAXFER *PPVDMETAXFER; + + +/** + * Internal I/O interface between the generic VD layer and the backends. + * + * Per-image. Always passed to backends. + */ +typedef struct VDINTERFACEIOINT +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Open callback + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pszLocation Name of the location to open. + * @param fOpen Flags for opening the backend. + * See RTFILE_O_* \#defines, inventing another set + * of open flags is not worth the mapping effort. + * @param ppStorage Where to store the storage handle. + */ + DECLR3CALLBACKMEMBER(int, pfnOpen, (void *pvUser, const char *pszLocation, + uint32_t fOpen, PPVDIOSTORAGE ppStorage)); + + /** + * Close callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pStorage The storage handle to close. + */ + DECLR3CALLBACKMEMBER(int, pfnClose, (void *pvUser, PVDIOSTORAGE pStorage)); + + /** + * Delete callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszFilename Name of the file to delete. + */ + DECLR3CALLBACKMEMBER(int, pfnDelete, (void *pvUser, const char *pcszFilename)); + + /** + * Move callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszSrc The path to the source file. + * @param pcszDst The path to the destination file. + * This file will be created. + * @param fMove A combination of the RTFILEMOVE_* flags. + */ + DECLR3CALLBACKMEMBER(int, pfnMove, (void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)); + + /** + * Returns the free space on a disk. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszFilename Name of a file to identify the disk. + * @param pcbFreeSpace Where to store the free space of the disk. + */ + DECLR3CALLBACKMEMBER(int, pfnGetFreeSpace, (void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)); + + /** + * Returns the last modification timestamp of a file. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszFilename Name of a file to identify the disk. + * @param pModificationTime Where to store the timestamp of the file. + */ + DECLR3CALLBACKMEMBER(int, pfnGetModificationTime, (void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)); + + /** + * Returns the size of the opened storage backend. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pStorage The storage handle to get the size from. + * @param pcbSize Where to store the size of the storage backend. + */ + DECLR3CALLBACKMEMBER(int, pfnGetSize, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t *pcbSize)); + + /** + * Sets the size of the opened storage backend if possible. + * + * @return VBox status code. + * @retval VERR_NOT_SUPPORTED if the backend does not support this operation. + * @param pvUser The opaque data passed on container creation. + * @param pStorage The storage handle. + * @param cbSize The new size of the image. + * + * @note Depending on the host the underlying storage (backing file, etc.) + * might not have all required storage allocated (sparse file) which + * can delay writes or fail with a not enough free space error if there + * is not enough space on the storage medium when writing to the range for + * the first time. + * Use VDINTERFACEIOINT::pfnSetAllocationSize to make sure the storage is + * really alloacted. + */ + DECLR3CALLBACKMEMBER(int, pfnSetSize, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t cbSize)); + + /** + * Sets the size of the opened storage backend making sure the given size + * is really allocated. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pStorage The storage handle. + * @param cbSize The new size of the image. + * @param fFlags Flags for controlling the allocation strategy. + * Reserved for future use, MBZ. + * @param pIfProgress Progress interface (optional). + * @param uPercentStart Progress starting point. + * @param uPercentSpan Length of operation in percent. + */ + DECLR3CALLBACKMEMBER(int, pfnSetAllocationSize, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t cbSize, uint32_t fFlags, + PVDINTERFACEPROGRESS pIfProgress, + unsigned uPercentStart, unsigned uPercentSpan)); + + /** + * Initiate a read request for user data. + * + * @return VBox status code. + * @param pvUser The opaque user data passed on container creation. + * @param pStorage The storage handle. + * @param uOffset The offset to start reading from. + * @param pIoCtx I/O context passed in the read/write callback. + * @param cbRead How many bytes to read. + */ + DECLR3CALLBACKMEMBER(int, pfnReadUser, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t uOffset, PVDIOCTX pIoCtx, + size_t cbRead)); + + /** + * Initiate a write request for user data. + * + * @return VBox status code. + * @param pvUser The opaque user data passed on container creation. + * @param pStorage The storage handle. + * @param uOffset The offset to start writing to. + * @param pIoCtx I/O context passed in the read/write callback. + * @param cbWrite How many bytes to write. + * @param pfnCompleted Completion callback. + * @param pvCompleteUser Opaque user data passed in the completion callback. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteUser, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t uOffset, PVDIOCTX pIoCtx, + size_t cbWrite, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser)); + + /** + * Reads metadata from storage. + * The current I/O context will be halted. + * + * @returns VBox status code. + * @param pvUser The opaque user data passed on container creation. + * @param pStorage The storage handle. + * @param uOffset Offset to start reading from. + * @param pvBuffer Where to store the data. + * @param cbBuffer How many bytes to read. + * @param pIoCtx The I/O context which triggered the read. + * @param ppMetaXfer Where to store the metadata transfer handle on success. + * @param pfnCompleted Completion callback. + * @param pvCompleteUser Opaque user data passed in the completion callback. + * + * @note If pIoCtx is NULL the metadata read is handled synchronously + * i.e. the call returns only if the data is available in the given + * buffer. ppMetaXfer, pfnCompleted and pvCompleteUser are ignored in that case. + * Use the synchronous version only when opening/closing the image + * or when doing certain operations like resizing, compacting or repairing + * the disk. + */ + DECLR3CALLBACKMEMBER(int, pfnReadMeta, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t uOffset, void *pvBuffer, + size_t cbBuffer, PVDIOCTX pIoCtx, + PPVDMETAXFER ppMetaXfer, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser)); + + /** + * Writes metadata to storage. + * + * @returns VBox status code. + * @param pvUser The opaque user data passed on container creation. + * @param pStorage The storage handle. + * @param uOffset Offset to start writing to. + * @param pvBuffer Written data. + * @param cbBuffer How many bytes to write. + * @param pIoCtx The I/O context which triggered the write. + * @param pfnCompleted Completion callback. + * @param pvCompleteUser Opaque user data passed in the completion callback. + * + * @sa VDINTERFACEIOINT::pfnReadMeta + */ + DECLR3CALLBACKMEMBER(int, pfnWriteMeta, (void *pvUser, PVDIOSTORAGE pStorage, + uint64_t uOffset, const void *pvBuffer, + size_t cbBuffer, PVDIOCTX pIoCtx, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser)); + + /** + * Releases a metadata transfer handle. + * The free space can be used for another transfer. + * + * @returns nothing. + * @param pvUser The opaque user data passed on container creation. + * @param pMetaXfer The metadata transfer handle to release. + */ + DECLR3CALLBACKMEMBER(void, pfnMetaXferRelease, (void *pvUser, PVDMETAXFER pMetaXfer)); + + /** + * Initiates a flush request. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pStorage The storage handle to flush. + * @param pIoCtx I/O context which triggered the flush. + * @param pfnCompleted Completion callback. + * @param pvCompleteUser Opaque user data passed in the completion callback. + * + * @sa VDINTERFACEIOINT::pfnReadMeta + */ + DECLR3CALLBACKMEMBER(int, pfnFlush, (void *pvUser, PVDIOSTORAGE pStorage, + PVDIOCTX pIoCtx, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser)); + + /** + * Copies a buffer into the I/O context. + * + * @return Number of bytes copied. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx I/O context to copy the data to. + * @param pvBuffer Buffer to copy. + * @param cbBuffer Number of bytes to copy. + */ + DECLR3CALLBACKMEMBER(size_t, pfnIoCtxCopyTo, (void *pvUser, PVDIOCTX pIoCtx, + const void *pvBuffer, size_t cbBuffer)); + + /** + * Copies data from the I/O context into a buffer. + * + * @return Number of bytes copied. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx I/O context to copy the data from. + * @param pvBuffer Destination buffer. + * @param cbBuffer Number of bytes to copy. + */ + DECLR3CALLBACKMEMBER(size_t, pfnIoCtxCopyFrom, (void *pvUser, PVDIOCTX pIoCtx, + void *pvBuffer, size_t cbBuffer)); + + /** + * Sets the buffer of the given context to a specific byte. + * + * @return Number of bytes set. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx I/O context to copy the data from. + * @param ch The byte to set. + * @param cbSet Number of bytes to set. + */ + DECLR3CALLBACKMEMBER(size_t, pfnIoCtxSet, (void *pvUser, PVDIOCTX pIoCtx, + int ch, size_t cbSet)); + + /** + * Creates a segment array from the I/O context data buffer. + * + * @returns Number of bytes the array describes. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx I/O context to copy the data from. + * @param paSeg The uninitialized segment array. + * If NULL pcSeg will contain the number of segments needed + * to describe the requested amount of data. + * @param pcSeg The number of segments the given array has. + * This will hold the actual number of entries needed upon return. + * @param cbData Number of bytes the new array should describe. + */ + DECLR3CALLBACKMEMBER(size_t, pfnIoCtxSegArrayCreate, (void *pvUser, PVDIOCTX pIoCtx, + PRTSGSEG paSeg, unsigned *pcSeg, + size_t cbData)); + /** + * Marks the given number of bytes as completed and continues the I/O context. + * + * @returns nothing. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx The I/O context. + * @param rcReq Status code the request completed with. + * @param cbCompleted Number of bytes completed. + */ + DECLR3CALLBACKMEMBER(void, pfnIoCtxCompleted, (void *pvUser, PVDIOCTX pIoCtx, + int rcReq, size_t cbCompleted)); + + /** + * Returns whether the given I/O context must be treated synchronously. + * + * @returns true if the I/O context must be processed synchronously + * false otherwise. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx The I/O context. + */ + DECLR3CALLBACKMEMBER(bool, pfnIoCtxIsSynchronous, (void *pvUser, PVDIOCTX pIoCtx)); + + /** + * Returns whether the user buffer of the I/O context is complete zero + * from to current position upto the given number of bytes. + * + * @returns true if the I/O context user buffer consists solely of zeros + * false otherwise. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx The I/O context. + * @param cbCheck Number of bytes to check for zeros. + * @param fAdvance Flag whether to advance the buffer pointer if true + * is returned. + */ + DECLR3CALLBACKMEMBER(bool, pfnIoCtxIsZero, (void *pvUser, PVDIOCTX pIoCtx, + size_t cbCheck, bool fAdvance)); + + /** + * Returns the data unit size, i.e. the smallest size for a transfer. + * (similar to the sector size of disks). + * + * @returns The data unit size. + * @param pvUser The opaque user data passed on container creation. + * @param pIoCtx The I/O context. + */ + DECLR3CALLBACKMEMBER(size_t, pfnIoCtxGetDataUnitSize, (void *pvUser, PVDIOCTX pIoCtx)); + +} VDINTERFACEIOINT, *PVDINTERFACEIOINT; + +/** + * Get internal I/O interface from interface list. + * + * @return Pointer to the first internal I/O interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACEIOINT) VDIfIoIntGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_IOINT); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_IOINT) + && (pIf->cbSize == sizeof(VDINTERFACEIOINT))), + ("Not an internal I/O interface"), NULL); + + return (PVDINTERFACEIOINT)pIf; +} + +DECLINLINE(int) vdIfIoIntFileOpen(PVDINTERFACEIOINT pIfIoInt, const char *pszFilename, + uint32_t fOpen, PPVDIOSTORAGE ppStorage) +{ + return pIfIoInt->pfnOpen(pIfIoInt->Core.pvUser, pszFilename, fOpen, ppStorage); +} + +DECLINLINE(int) vdIfIoIntFileClose(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage) +{ + return pIfIoInt->pfnClose(pIfIoInt->Core.pvUser, pStorage); +} + +DECLINLINE(int) vdIfIoIntFileDelete(PVDINTERFACEIOINT pIfIoInt, const char *pszFilename) +{ + return pIfIoInt->pfnDelete(pIfIoInt->Core.pvUser, pszFilename); +} + +DECLINLINE(int) vdIfIoIntFileMove(PVDINTERFACEIOINT pIfIoInt, const char *pszSrc, + const char *pszDst, unsigned fMove) +{ + return pIfIoInt->pfnMove(pIfIoInt->Core.pvUser, pszSrc, pszDst, fMove); +} + +DECLINLINE(int) vdIfIoIntFileGetFreeSpace(PVDINTERFACEIOINT pIfIoInt, const char *pszFilename, + int64_t *pcbFree) +{ + return pIfIoInt->pfnGetFreeSpace(pIfIoInt->Core.pvUser, pszFilename, pcbFree); +} + +DECLINLINE(int) vdIfIoIntFileGetModificationTime(PVDINTERFACEIOINT pIfIoInt, const char *pcszFilename, + PRTTIMESPEC pModificationTime) +{ + return pIfIoInt->pfnGetModificationTime(pIfIoInt->Core.pvUser, pcszFilename, + pModificationTime); +} + +DECLINLINE(int) vdIfIoIntFileGetSize(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t *pcbSize) +{ + return pIfIoInt->pfnGetSize(pIfIoInt->Core.pvUser, pStorage, pcbSize); +} + +DECLINLINE(int) vdIfIoIntFileSetSize(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t cbSize) +{ + return pIfIoInt->pfnSetSize(pIfIoInt->Core.pvUser, pStorage, cbSize); +} + +DECLINLINE(int) vdIfIoIntFileSetAllocationSize(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t cbSize, uint32_t fFlags, + PVDINTERFACEPROGRESS pIfProgress, + unsigned uPercentStart, unsigned uPercentSpan) +{ + return pIfIoInt->pfnSetAllocationSize(pIfIoInt->Core.pvUser, pStorage, cbSize, fFlags, + pIfProgress, uPercentStart, uPercentSpan); +} + +DECLINLINE(int) vdIfIoIntFileWriteSync(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t uOffset, const void *pvBuffer, size_t cbBuffer) +{ + return pIfIoInt->pfnWriteMeta(pIfIoInt->Core.pvUser, pStorage, + uOffset, pvBuffer, cbBuffer, NULL, + NULL, NULL); +} + +DECLINLINE(int) vdIfIoIntFileReadSync(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t uOffset, void *pvBuffer, size_t cbBuffer) +{ + return pIfIoInt->pfnReadMeta(pIfIoInt->Core.pvUser, pStorage, + uOffset, pvBuffer, cbBuffer, NULL, + NULL, NULL, NULL); +} + +DECLINLINE(int) vdIfIoIntFileFlushSync(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage) +{ + return pIfIoInt->pfnFlush(pIfIoInt->Core.pvUser, pStorage, NULL, NULL, NULL); +} + +DECLINLINE(int) vdIfIoIntFileReadUser(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t uOffset, PVDIOCTX pIoCtx, size_t cbRead) +{ + return pIfIoInt->pfnReadUser(pIfIoInt->Core.pvUser, pStorage, + uOffset, pIoCtx, cbRead); +} + +DECLINLINE(int) vdIfIoIntFileWriteUser(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t uOffset, PVDIOCTX pIoCtx, size_t cbWrite, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser) +{ + return pIfIoInt->pfnWriteUser(pIfIoInt->Core.pvUser, pStorage, + uOffset, pIoCtx, cbWrite, pfnComplete, + pvCompleteUser); +} + +DECLINLINE(int) vdIfIoIntFileReadMeta(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t uOffset, void *pvBuffer, + size_t cbBuffer, PVDIOCTX pIoCtx, + PPVDMETAXFER ppMetaXfer, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser) +{ + return pIfIoInt->pfnReadMeta(pIfIoInt->Core.pvUser, pStorage, + uOffset, pvBuffer, cbBuffer, pIoCtx, + ppMetaXfer, pfnComplete, pvCompleteUser); +} + +DECLINLINE(int) vdIfIoIntFileWriteMeta(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + uint64_t uOffset, void *pvBuffer, + size_t cbBuffer, PVDIOCTX pIoCtx, + PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser) +{ + return pIfIoInt->pfnWriteMeta(pIfIoInt->Core.pvUser, pStorage, + uOffset, pvBuffer, cbBuffer, pIoCtx, + pfnComplete, pvCompleteUser); +} + +DECLINLINE(void) vdIfIoIntMetaXferRelease(PVDINTERFACEIOINT pIfIoInt, PVDMETAXFER pMetaXfer) +{ + pIfIoInt->pfnMetaXferRelease(pIfIoInt->Core.pvUser, pMetaXfer); +} + +DECLINLINE(int) vdIfIoIntFileFlush(PVDINTERFACEIOINT pIfIoInt, PVDIOSTORAGE pStorage, + PVDIOCTX pIoCtx, PFNVDXFERCOMPLETED pfnComplete, + void *pvCompleteUser) +{ + return pIfIoInt->pfnFlush(pIfIoInt->Core.pvUser, pStorage, pIoCtx, pfnComplete, + pvCompleteUser); +} + +DECLINLINE(size_t) vdIfIoIntIoCtxCopyTo(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx, + const void *pvBuffer, size_t cbBuffer) +{ + return pIfIoInt->pfnIoCtxCopyTo(pIfIoInt->Core.pvUser, pIoCtx, pvBuffer, cbBuffer); +} + +DECLINLINE(size_t) vdIfIoIntIoCtxCopyFrom(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx, + void *pvBuffer, size_t cbBuffer) +{ + return pIfIoInt->pfnIoCtxCopyFrom(pIfIoInt->Core.pvUser, pIoCtx, pvBuffer, cbBuffer); +} + +DECLINLINE(size_t) vdIfIoIntIoCtxSet(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx, + int ch, size_t cbSet) +{ + return pIfIoInt->pfnIoCtxSet(pIfIoInt->Core.pvUser, pIoCtx, ch, cbSet); +} + +DECLINLINE(size_t) vdIfIoIntIoCtxSegArrayCreate(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx, + PRTSGSEG paSeg, unsigned *pcSeg, + size_t cbData) +{ + return pIfIoInt->pfnIoCtxSegArrayCreate(pIfIoInt->Core.pvUser, pIoCtx, paSeg, pcSeg, cbData); +} + +DECLINLINE(bool) vdIfIoIntIoCtxIsSynchronous(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx) +{ + return pIfIoInt->pfnIoCtxIsSynchronous(pIfIoInt->Core.pvUser, pIoCtx); +} + +DECLINLINE(bool) vdIfIoIntIoCtxIsZero(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx, + size_t cbCheck, bool fAdvance) +{ + return pIfIoInt->pfnIoCtxIsZero(pIfIoInt->Core.pvUser, pIoCtx, cbCheck, fAdvance); +} + +DECLINLINE(size_t) vdIfIoIntIoCtxGetDataUnitSize(PVDINTERFACEIOINT pIfIoInt, PVDIOCTX pIoCtx) +{ + return pIfIoInt->pfnIoCtxGetDataUnitSize(pIfIoInt->Core.pvUser, pIoCtx); +} + +/** + * Interface for the metadata traverse callback. + * + * Per-operation interface. Present only for the metadata traverse callback. + */ +typedef struct VDINTERFACETRAVERSEMETADATA +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Traverse callback. + * + * @returns VBox status code. + * @param pvUser The opaque data passed for the operation. + * @param pvMetadataChunk Pointer to a chunk of the image metadata. + * @param cbMetadataChunk Size of the metadata chunk + */ + DECLR3CALLBACKMEMBER(int, pfnMetadataCallback, (void *pvUser, const void *pvMetadataChunk, + size_t cbMetadataChunk)); + +} VDINTERFACETRAVERSEMETADATA, *PVDINTERFACETRAVERSEMETADATA; + + +/** + * Get parent state interface from interface list. + * + * @return Pointer to the first parent state interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACETRAVERSEMETADATA) VDIfTraverseMetadataGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_TRAVERSEMETADATA); + + /* Check that the interface descriptor the correct interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_TRAVERSEMETADATA) + && (pIf->cbSize == sizeof(VDINTERFACETRAVERSEMETADATA))), + ("Not a traverse metadata interface"), NULL); + + return (PVDINTERFACETRAVERSEMETADATA)pIf; +} + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vd_ifs_internal_h */ diff --git a/include/VBox/vd-ifs.h b/include/VBox/vd-ifs.h new file mode 100644 index 00000000..87dec3f3 --- /dev/null +++ b/include/VBox/vd-ifs.h @@ -0,0 +1,1765 @@ +/** @file + * VD Container API - interfaces. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_ifs_h +#define VBOX_INCLUDED_vd_ifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @addtogroup grp_vd + * @{ */ + +/** Interface header magic. */ +#define VDINTERFACE_MAGIC UINT32_C(0x19701015) + +/** + * Supported interface types. + */ +typedef enum VDINTERFACETYPE +{ + /** First valid interface. */ + VDINTERFACETYPE_FIRST = 0, + /** Interface to pass error message to upper layers. Per-disk. */ + VDINTERFACETYPE_ERROR = VDINTERFACETYPE_FIRST, + /** Interface for I/O operations. Per-image. */ + VDINTERFACETYPE_IO, + /** Interface for progress notification. Per-operation. */ + VDINTERFACETYPE_PROGRESS, + /** Interface for configuration information. Per-image. */ + VDINTERFACETYPE_CONFIG, + /** Interface for TCP network stack. Per-image. */ + VDINTERFACETYPE_TCPNET, + /** Interface for getting parent image state. Per-operation. */ + VDINTERFACETYPE_PARENTSTATE, + /** Interface for synchronizing accesses from several threads. Per-disk. */ + VDINTERFACETYPE_THREADSYNC, + /** Interface for I/O between the generic VBoxHDD code and the backend. Per-image (internal). + * This interface is completely internal and must not be used elsewhere. */ + VDINTERFACETYPE_IOINT, + /** Interface to query the use of block ranges on the disk. Per-operation. */ + VDINTERFACETYPE_QUERYRANGEUSE, + /** Interface for the metadata traverse callback. Per-operation. */ + VDINTERFACETYPE_TRAVERSEMETADATA, + /** Interface for crypto operations. Per-filter. */ + VDINTERFACETYPE_CRYPTO, + /** invalid interface. */ + VDINTERFACETYPE_INVALID +} VDINTERFACETYPE; + +/** + * Common structure for all interfaces and at the beginning of all types. + */ +typedef struct VDINTERFACE +{ + uint32_t u32Magic; + /** Human readable interface name. */ + const char *pszInterfaceName; + /** Pointer to the next common interface structure. */ + struct VDINTERFACE *pNext; + /** Interface type. */ + VDINTERFACETYPE enmInterface; + /** Size of the interface. */ + size_t cbSize; + /** Opaque user data which is passed on every call. */ + void *pvUser; +} VDINTERFACE; +/** Pointer to a VDINTERFACE. */ +typedef VDINTERFACE *PVDINTERFACE; +/** Pointer to a const VDINTERFACE. */ +typedef const VDINTERFACE *PCVDINTERFACE; + +/** + * Helper functions to handle interface lists. + * + * @note These interface lists are used consistently to pass per-disk, + * per-image and/or per-operation callbacks. Those three purposes are strictly + * separate. See the individual interface declarations for what context they + * apply to. The caller is responsible for ensuring that the lifetime of the + * interface descriptors is appropriate for the category of interface. + */ + +/** + * Get a specific interface from a list of interfaces specified by the type. + * + * @return Pointer to the matching interface or NULL if none was found. + * @param pVDIfs Pointer to the VD interface list. + * @param enmInterface Interface to search for. + */ +DECLINLINE(PVDINTERFACE) VDInterfaceGet(PVDINTERFACE pVDIfs, VDINTERFACETYPE enmInterface) +{ + AssertMsgReturn( enmInterface >= VDINTERFACETYPE_FIRST + && enmInterface < VDINTERFACETYPE_INVALID, + ("enmInterface=%u", enmInterface), NULL); + + while (pVDIfs) + { + AssertMsgBreak(pVDIfs->u32Magic == VDINTERFACE_MAGIC, + ("u32Magic=%#x\n", pVDIfs->u32Magic)); + + if (pVDIfs->enmInterface == enmInterface) + return pVDIfs; + pVDIfs = pVDIfs->pNext; + } + + /* No matching interface was found. */ + return NULL; +} + +/** + * Add an interface to a list of interfaces. + * + * @return VBox status code. + * @param pInterface Pointer to an unitialized common interface structure. + * @param pszName Name of the interface. + * @param enmInterface Type of the interface. + * @param pvUser Opaque user data passed on every function call. + * @param cbInterface The interface size. + * @param ppVDIfs Pointer to the VD interface list. + */ +DECLINLINE(int) VDInterfaceAdd(PVDINTERFACE pInterface, const char *pszName, VDINTERFACETYPE enmInterface, void *pvUser, + size_t cbInterface, PVDINTERFACE *ppVDIfs) +{ + /* Argument checks. */ + AssertMsgReturn( enmInterface >= VDINTERFACETYPE_FIRST + && enmInterface < VDINTERFACETYPE_INVALID, + ("enmInterface=%u", enmInterface), VERR_INVALID_PARAMETER); + + AssertPtrReturn(ppVDIfs, VERR_INVALID_PARAMETER); + + /* Fill out interface descriptor. */ + pInterface->u32Magic = VDINTERFACE_MAGIC; + pInterface->cbSize = cbInterface; + pInterface->pszInterfaceName = pszName; + pInterface->enmInterface = enmInterface; + pInterface->pvUser = pvUser; + pInterface->pNext = *ppVDIfs; + + /* Remember the new start of the list. */ + *ppVDIfs = pInterface; + + return VINF_SUCCESS; +} + +/** + * Removes an interface from a list of interfaces. + * + * @return VBox status code + * @param pInterface Pointer to an initialized common interface structure to remove. + * @param ppVDIfs Pointer to the VD interface list to remove from. + */ +DECLINLINE(int) VDInterfaceRemove(PVDINTERFACE pInterface, PVDINTERFACE *ppVDIfs) +{ + int rc = VERR_NOT_FOUND; + + /* Argument checks. */ + AssertPtrReturn(pInterface, VERR_INVALID_PARAMETER); + AssertPtrReturn(ppVDIfs, VERR_INVALID_PARAMETER); + + if (*ppVDIfs) + { + PVDINTERFACE pPrev = NULL; + PVDINTERFACE pCurr = *ppVDIfs; + + while ( pCurr + && (pCurr != pInterface)) + { + pPrev = pCurr; + pCurr = pCurr->pNext; + } + + /* First interface */ + if (!pPrev) + { + *ppVDIfs = pCurr->pNext; + rc = VINF_SUCCESS; + } + else if (pCurr) + { + Assert(pPrev->pNext == pCurr); + pPrev->pNext = pCurr->pNext; + rc = VINF_SUCCESS; + } + } + + return rc; +} + +/** + * Interface to deliver error messages (and also informational messages) + * to upper layers. + * + * Per-disk interface. Optional, but think twice if you want to miss the + * opportunity of reporting better human-readable error messages. + */ +typedef struct VDINTERFACEERROR +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Error message callback. Must be able to accept special IPRT format + * strings. + * + * @param pvUser The opaque data passed on container creation. + * @param rc The VBox error code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(void, pfnError, (void *pvUser, int rc, RT_SRC_POS_DECL, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * Informational message callback. May be NULL. Used e.g. in + * VDDumpImages(). Must be able to accept special IPRT format strings. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pszFormat Message format string. + * @param va Message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnMessage, (void *pvUser, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(2, 0)); + +} VDINTERFACEERROR, *PVDINTERFACEERROR; + +/** + * Get error interface from interface list. + * + * @return Pointer to the first error interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACEERROR) VDIfErrorGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_ERROR); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_ERROR) + && (pIf->cbSize == sizeof(VDINTERFACEERROR))), + ("Not an error interface\n"), NULL); + + return (PVDINTERFACEERROR)pIf; +} + +/** + * Signal an error to the frontend. + * + * @returns VBox status code. + * @param pIfError The error interface. + * @param rc The status code. + * @param SRC_POS The position in the source code. + * @param pszFormat The format string to pass. + * @param ... Arguments to the format string. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) vdIfError(PVDINTERFACEERROR pIfError, int rc, RT_SRC_POS_DECL, + const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + if (pIfError) + pIfError->pfnError(pIfError->Core.pvUser, rc, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + +#if defined(LOG_ENABLED) && defined(Log) + va_start(va, pszFormat); + Log(("vdIfError: %N\n", pszFormat, &va)); + va_end(va); +#endif + return rc; +} + +/** + * Signal an informational message to the frontend. + * + * @returns VBox status code. + * @param pIfError The error interface. + * @param pszFormat The format string to pass. + * @param ... Arguments to the format string. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(2, 3) vdIfErrorMessage(PVDINTERFACEERROR pIfError, const char *pszFormat, ...) +{ + int rc = VINF_SUCCESS; + va_list va; + va_start(va, pszFormat); + if (pIfError && pIfError->pfnMessage) + rc = pIfError->pfnMessage(pIfError->Core.pvUser, pszFormat, va); + va_end(va); + +#if defined(LOG_ENABLED) && defined(Log) + va_start(va, pszFormat); + Log(("vdIfErrorMessage: %N\n", pszFormat, &va)); + va_end(va); +#endif + return rc; +} + +/** + * Completion callback which is called by the interface owner + * to inform the backend that a task finished. + * + * @return VBox status code. + * @param pvUser Opaque user data which is passed on request submission. + * @param rcReq Status code of the completed request. + */ +typedef DECLCALLBACKTYPE(int, FNVDCOMPLETED,(void *pvUser, int rcReq)); +/** Pointer to FNVDCOMPLETED() */ +typedef FNVDCOMPLETED *PFNVDCOMPLETED; + +/** + * Support interface for I/O + * + * Per-image. Optional as input. + */ +typedef struct VDINTERFACEIO +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Open callback + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pszLocation Name of the location to open. + * @param fOpen Flags for opening the backend. + * See RTFILE_O_* \#defines, inventing another set + * of open flags is not worth the mapping effort. + * @param pfnCompleted The callback which is called whenever a task + * completed. The backend has to pass the user data + * of the request initiator (ie the one who calls + * VDAsyncRead or VDAsyncWrite) in pvCompletion + * if this is NULL. + * @param ppvStorage Where to store the opaque storage handle. + */ + DECLR3CALLBACKMEMBER(int, pfnOpen, (void *pvUser, const char *pszLocation, + uint32_t fOpen, + PFNVDCOMPLETED pfnCompleted, + void **ppvStorage)); + + /** + * Close callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The opaque storage handle to close. + */ + DECLR3CALLBACKMEMBER(int, pfnClose, (void *pvUser, void *pvStorage)); + + /** + * Delete callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszFilename Name of the file to delete. + */ + DECLR3CALLBACKMEMBER(int, pfnDelete, (void *pvUser, const char *pcszFilename)); + + /** + * Move callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszSrc The path to the source file. + * @param pcszDst The path to the destination file. + * This file will be created. + * @param fMove A combination of the RTFILEMOVE_* flags. + */ + DECLR3CALLBACKMEMBER(int, pfnMove, (void *pvUser, const char *pcszSrc, const char *pcszDst, unsigned fMove)); + + /** + * Returns the free space on a disk. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszFilename Name of a file to identify the disk. + * @param pcbFreeSpace Where to store the free space of the disk. + */ + DECLR3CALLBACKMEMBER(int, pfnGetFreeSpace, (void *pvUser, const char *pcszFilename, int64_t *pcbFreeSpace)); + + /** + * Returns the last modification timestamp of a file. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pcszFilename Name of a file to identify the disk. + * @param pModificationTime Where to store the timestamp of the file. + */ + DECLR3CALLBACKMEMBER(int, pfnGetModificationTime, (void *pvUser, const char *pcszFilename, PRTTIMESPEC pModificationTime)); + + /** + * Returns the size of the opened storage backend. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The opaque storage handle to get the size from. + * @param pcb Where to store the size of the storage backend. + */ + DECLR3CALLBACKMEMBER(int, pfnGetSize, (void *pvUser, void *pvStorage, uint64_t *pcb)); + + /** + * Sets the size of the opened storage backend if possible. + * + * @return VBox status code. + * @retval VERR_NOT_SUPPORTED if the backend does not support this operation. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The opaque storage handle to set the size for. + * @param cb The new size of the image. + * + * @note Depending on the host the underlying storage (backing file, etc.) + * might not have all required storage allocated (sparse file) which + * can delay writes or fail with a not enough free space error if there + * is not enough space on the storage medium when writing to the range for + * the first time. + * Use VDINTERFACEIO::pfnSetAllocationSize to make sure the storage is + * really alloacted. + */ + DECLR3CALLBACKMEMBER(int, pfnSetSize, (void *pvUser, void *pvStorage, uint64_t cb)); + + /** + * Sets the size of the opened storage backend making sure the given size + * is really allocated. + * + * @return VBox status code. + * @retval VERR_NOT_SUPPORTED if the implementer of the interface doesn't support + * this method. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The storage handle. + * @param cbSize The new size of the image. + * @param fFlags Flags for controlling the allocation strategy. + * Reserved for future use, MBZ. + */ + DECLR3CALLBACKMEMBER(int, pfnSetAllocationSize, (void *pvUser, void *pvStorage, + uint64_t cbSize, uint32_t fFlags)); + + /** + * Synchronous write callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The storage handle to use. + * @param off The offset to start from. + * @param pvBuf Pointer to the bits need to be written. + * @param cbToWrite How many bytes to write. + * @param pcbWritten Where to store how many bytes were actually written. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteSync, (void *pvUser, void *pvStorage, uint64_t off, + const void *pvBuf, size_t cbToWrite, size_t *pcbWritten)); + + /** + * Synchronous read callback. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The storage handle to use. + * @param off The offset to start from. + * @param pvBuf Where to store the read bits. + * @param cbToRead How many bytes to read. + * @param pcbRead Where to store how many bytes were actually read. + */ + DECLR3CALLBACKMEMBER(int, pfnReadSync, (void *pvUser, void *pvStorage, uint64_t off, + void *pvBuf, size_t cbToRead, size_t *pcbRead)); + + /** + * Flush data to the storage backend. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The storage handle to flush. + */ + DECLR3CALLBACKMEMBER(int, pfnFlushSync, (void *pvUser, void *pvStorage)); + + /** + * Initiate an asynchronous read request. + * + * @return VBox status code. + * @param pvUser The opaque user data passed on container creation. + * @param pvStorage The storage handle. + * @param uOffset The offset to start reading from. + * @param paSegments Scatter gather list to store the data in. + * @param cSegments Number of segments in the list. + * @param cbRead How many bytes to read. + * @param pvCompletion The opaque user data which is returned upon completion. + * @param ppTask Where to store the opaque task handle. + */ + DECLR3CALLBACKMEMBER(int, pfnReadAsync, (void *pvUser, void *pvStorage, uint64_t uOffset, + PCRTSGSEG paSegments, size_t cSegments, + size_t cbRead, void *pvCompletion, + void **ppTask)); + + /** + * Initiate an asynchronous write request. + * + * @return VBox status code. + * @param pvUser The opaque user data passed on conatiner creation. + * @param pvStorage The storage handle. + * @param uOffset The offset to start writing to. + * @param paSegments Scatter gather list of the data to write + * @param cSegments Number of segments in the list. + * @param cbWrite How many bytes to write. + * @param pvCompletion The opaque user data which is returned upon completion. + * @param ppTask Where to store the opaque task handle. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteAsync, (void *pvUser, void *pvStorage, uint64_t uOffset, + PCRTSGSEG paSegments, size_t cSegments, + size_t cbWrite, void *pvCompletion, + void **ppTask)); + + /** + * Initiates an async flush request. + * + * @return VBox status code. + * @param pvUser The opaque data passed on container creation. + * @param pvStorage The storage handle to flush. + * @param pvCompletion The opaque user data which is returned upon completion. + * @param ppTask Where to store the opaque task handle. + */ + DECLR3CALLBACKMEMBER(int, pfnFlushAsync, (void *pvUser, void *pvStorage, + void *pvCompletion, void **ppTask)); + +} VDINTERFACEIO, *PVDINTERFACEIO; + +/** + * Get I/O interface from interface list. + * + * @return Pointer to the first I/O interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACEIO) VDIfIoGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_IO); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_IO) + && (pIf->cbSize == sizeof(VDINTERFACEIO))), + ("Not a I/O interface"), NULL); + + return (PVDINTERFACEIO)pIf; +} + +DECLINLINE(int) vdIfIoFileOpen(PVDINTERFACEIO pIfIo, const char *pszFilename, + uint32_t fOpen, PFNVDCOMPLETED pfnCompleted, + void **ppStorage) +{ + return pIfIo->pfnOpen(pIfIo->Core.pvUser, pszFilename, fOpen, pfnCompleted, ppStorage); +} + +DECLINLINE(int) vdIfIoFileClose(PVDINTERFACEIO pIfIo, void *pStorage) +{ + return pIfIo->pfnClose(pIfIo->Core.pvUser, pStorage); +} + +DECLINLINE(int) vdIfIoFileDelete(PVDINTERFACEIO pIfIo, const char *pszFilename) +{ + return pIfIo->pfnDelete(pIfIo->Core.pvUser, pszFilename); +} + +DECLINLINE(int) vdIfIoFileMove(PVDINTERFACEIO pIfIo, const char *pszSrc, + const char *pszDst, unsigned fMove) +{ + return pIfIo->pfnMove(pIfIo->Core.pvUser, pszSrc, pszDst, fMove); +} + +DECLINLINE(int) vdIfIoFileGetFreeSpace(PVDINTERFACEIO pIfIo, const char *pszFilename, + int64_t *pcbFree) +{ + return pIfIo->pfnGetFreeSpace(pIfIo->Core.pvUser, pszFilename, pcbFree); +} + +DECLINLINE(int) vdIfIoFileGetModificationTime(PVDINTERFACEIO pIfIo, const char *pcszFilename, + PRTTIMESPEC pModificationTime) +{ + return pIfIo->pfnGetModificationTime(pIfIo->Core.pvUser, pcszFilename, + pModificationTime); +} + +DECLINLINE(int) vdIfIoFileGetSize(PVDINTERFACEIO pIfIo, void *pStorage, + uint64_t *pcbSize) +{ + return pIfIo->pfnGetSize(pIfIo->Core.pvUser, pStorage, pcbSize); +} + +DECLINLINE(int) vdIfIoFileSetSize(PVDINTERFACEIO pIfIo, void *pStorage, + uint64_t cbSize) +{ + return pIfIo->pfnSetSize(pIfIo->Core.pvUser, pStorage, cbSize); +} + +DECLINLINE(int) vdIfIoFileWriteSync(PVDINTERFACEIO pIfIo, void *pStorage, + uint64_t uOffset, const void *pvBuffer, size_t cbBuffer, + size_t *pcbWritten) +{ + return pIfIo->pfnWriteSync(pIfIo->Core.pvUser, pStorage, uOffset, + pvBuffer, cbBuffer, pcbWritten); +} + +DECLINLINE(int) vdIfIoFileReadSync(PVDINTERFACEIO pIfIo, void *pStorage, + uint64_t uOffset, void *pvBuffer, size_t cbBuffer, + size_t *pcbRead) +{ + return pIfIo->pfnReadSync(pIfIo->Core.pvUser, pStorage, uOffset, + pvBuffer, cbBuffer, pcbRead); +} + +DECLINLINE(int) vdIfIoFileFlushSync(PVDINTERFACEIO pIfIo, void *pStorage) +{ + return pIfIo->pfnFlushSync(pIfIo->Core.pvUser, pStorage); +} + +/** + * Create a VFS stream handle around a VD I/O interface. + * + * The I/O interface will not be closed or free by the stream, the caller will + * do so after it is done with the stream and has released the instances of the + * I/O stream object returned by this API. + * + * @return VBox status code. + * @param pVDIfsIo Pointer to the VD I/O interface. + * @param pvStorage The storage argument to pass to the interface + * methods. + * @param fFlags RTFILE_O_XXX, access mask requied. + * @param phVfsIos Where to return the VFS I/O stream handle on + * success. + */ +VBOXDDU_DECL(int) VDIfCreateVfsStream(PVDINTERFACEIO pVDIfsIo, void *pvStorage, uint32_t fFlags, PRTVFSIOSTREAM phVfsIos); + +struct VDINTERFACEIOINT; + +/** + * Create a VFS file handle around a VD I/O interface. + * + * The I/O interface will not be closed or free by the VFS file, the caller will + * do so after it is done with the VFS file and has released the instances of + * the VFS object returned by this API. + * + * @return VBox status code. + * @param pVDIfs Pointer to the VD I/O interface. If NULL, then @a + * pVDIfsInt must be specified. + * @param pVDIfsInt Pointer to the internal VD I/O interface. If NULL, + * then @ pVDIfs must be specified. + * @param pvStorage The storage argument to pass to the interface + * methods. + * @param fFlags RTFILE_O_XXX, access mask requied. + * @param phVfsFile Where to return the VFS file handle on success. + */ +VBOXDDU_DECL(int) VDIfCreateVfsFile(PVDINTERFACEIO pVDIfs, struct VDINTERFACEIOINT *pVDIfsInt, void *pvStorage, + uint32_t fFlags, PRTVFSFILE phVfsFile); + +/** + * Creates an VD I/O interface wrapper around an IPRT VFS I/O stream. + * + * @return VBox status code. + * @param hVfsIos The IPRT VFS I/O stream handle. The handle will be + * retained by the returned I/O interface (released on + * close or destruction). + * @param fAccessMode The access mode (RTFILE_O_ACCESS_MASK) to accept. + * @param ppIoIf Where to return the pointer to the VD I/O interface. + * This must be passed to VDIfDestroyFromVfsStream(). + */ +VBOXDDU_DECL(int) VDIfCreateFromVfsStream(RTVFSIOSTREAM hVfsIos, uint32_t fAccessMode, PVDINTERFACEIO *ppIoIf); + +/** + * Destroys the VD I/O interface returned by VDIfCreateFromVfsStream. + * + * @returns VBox status code. + * @param pIoIf The I/O interface pointer returned by + * VDIfCreateFromVfsStream. NULL will be quietly + * ignored. + */ +VBOXDDU_DECL(int) VDIfDestroyFromVfsStream(PVDINTERFACEIO pIoIf); + + +/** + * Callback which provides progress information about a currently running + * lengthy operation. + * + * @return VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param uPercentage Completion percentage. + */ +typedef DECLCALLBACKTYPE(int, FNVDPROGRESS,(void *pvUser, unsigned uPercentage)); +/** Pointer to FNVDPROGRESS() */ +typedef FNVDPROGRESS *PFNVDPROGRESS; + +/** + * Progress notification interface + * + * Per-operation. Optional. + */ +typedef struct VDINTERFACEPROGRESS +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Progress notification callbacks. + */ + PFNVDPROGRESS pfnProgress; + +} VDINTERFACEPROGRESS, *PVDINTERFACEPROGRESS; + +/** Initializer for VDINTERFACEPROGRESS. */ +#define VDINTERFACEPROGRESS_INITALIZER(a_pfnProgress) { { 0, NULL, NULL, VDINTERFACETYPE_INVALID, 0, NULL }, a_pfnProgress } + +/** + * Get progress interface from interface list. + * + * @return Pointer to the first progress interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACEPROGRESS) VDIfProgressGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_PROGRESS); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_PROGRESS) + && (pIf->cbSize == sizeof(VDINTERFACEPROGRESS))), + ("Not a progress interface"), NULL); + + return (PVDINTERFACEPROGRESS)pIf; +} + +/** + * Signal new progress information to the frontend. + * + * @returns VBox status code. + * @param pIfProgress The progress interface. + * @param uPercentage Completion percentage. + */ +DECLINLINE(int) vdIfProgress(PVDINTERFACEPROGRESS pIfProgress, unsigned uPercentage) +{ + if (pIfProgress) + return pIfProgress->pfnProgress(pIfProgress->Core.pvUser, uPercentage); + return VINF_SUCCESS; +} + +/** + * Configuration information interface + * + * Per-image. Optional for most backends, but mandatory for images which do + * not operate on files (including standard block or character devices). + */ +typedef struct VDINTERFACECONFIG +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Validates that the keys are within a set of valid names. + * + * @return true if all key names are found in pszzAllowed. + * @return false if not. + * @param pvUser The opaque user data associated with this interface. + * @param pszzValid List of valid key names separated by '\\0' and ending with + * a double '\\0'. + */ + DECLR3CALLBACKMEMBER(bool, pfnAreKeysValid, (void *pvUser, const char *pszzValid)); + + /** + * Retrieves the length of the string value associated with a key (including + * the terminator, for compatibility with CFGMR3QuerySize). + * + * @return VBox status code. + * VERR_CFGM_VALUE_NOT_FOUND means that the key is not known. + * @param pvUser The opaque user data associated with this interface. + * @param pszName Name of the key to query. + * @param pcbValue Where to store the value length. Non-NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnQuerySize, (void *pvUser, const char *pszName, size_t *pcbValue)); + + /** + * Query the string value associated with a key. + * + * @return VBox status code. + * VERR_CFGM_VALUE_NOT_FOUND means that the key is not known. + * VERR_CFGM_NOT_ENOUGH_SPACE means that the buffer is not big enough. + * @param pvUser The opaque user data associated with this interface. + * @param pszName Name of the key to query. + * @param pszValue Pointer to buffer where to store value. + * @param cchValue Length of value buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnQuery, (void *pvUser, const char *pszName, char *pszValue, size_t cchValue)); + + /** + * Query the bytes value associated with a key. + * + * @return VBox status code. + * VERR_CFGM_VALUE_NOT_FOUND means that the key is not known. + * VERR_CFGM_NOT_ENOUGH_SPACE means that the buffer is not big enough. + * @param pvUser The opaque user data associated with this interface. + * @param pszName Name of the key to query. + * @param ppvData Pointer to buffer where to store the data. + * @param cbData Length of data buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryBytes, (void *pvUser, const char *pszName, void *ppvData, size_t cbData)); + + /** + * Set a named property to a specified string value, optionally creating if it doesn't exist. + * + * @return VBox status code. + * VERR_CFGM_VALUE_NOT_FOUND means that the key is not known and fCreate flag was not set. + * @param pvUser The opaque user data associated with this interface. + * @param fCreate Create property if it doesn't exist (if property exists, it is not an error) + * @param pszName Name of the key to query. + * @param pszValue String value to set the name property to. + */ + DECLR3CALLBACKMEMBER(int, pfnUpdate, (void *pvUser, bool fCreate, + const char *pszName, const char *pszValue)); + +} VDINTERFACECONFIG, *PVDINTERFACECONFIG; + +/** + * Get configuration information interface from interface list. + * + * @return Pointer to the first configuration information interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACECONFIG) VDIfConfigGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_CONFIG); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_CONFIG) + && (pIf->cbSize == sizeof(VDINTERFACECONFIG))), + ("Not a config interface"), NULL); + + return (PVDINTERFACECONFIG)pIf; +} + +/** + * Query configuration, validates that the keys are within a set of valid names. + * + * @return true if all key names are found in pszzAllowed. + * @return false if not. + * @param pCfgIf Pointer to configuration callback table. + * @param pszzValid List of valid names separated by '\\0' and ending with + * a double '\\0'. + */ +DECLINLINE(bool) VDCFGAreKeysValid(PVDINTERFACECONFIG pCfgIf, const char *pszzValid) +{ + return pCfgIf->pfnAreKeysValid(pCfgIf->Core.pvUser, pszzValid); +} + +/** + * Checks whether a given key is existing. + * + * @return true if the key exists. + * @return false if the key does not exist. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of the key. + */ +DECLINLINE(bool) VDCFGIsKeyExisting(PVDINTERFACECONFIG pCfgIf, const char *pszName) +{ + size_t cb = 0; + int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb); + return rc == VERR_CFGM_VALUE_NOT_FOUND ? false : true; +} + +/** + * Query configuration, unsigned 64-bit integer value with default. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an integer value + * @param pu64 Where to store the value. Set to default on failure. + * @param u64Def The default value. + */ +DECLINLINE(int) VDCFGQueryU64Def(PVDINTERFACECONFIG pCfgIf, + const char *pszName, uint64_t *pu64, + uint64_t u64Def) +{ + char aszBuf[32]; + int rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, aszBuf, sizeof(aszBuf)); + if (RT_SUCCESS(rc)) + { + rc = RTStrToUInt64Full(aszBuf, 0, pu64); + } + else if (rc == VERR_CFGM_VALUE_NOT_FOUND) + { + rc = VINF_SUCCESS; + *pu64 = u64Def; + } + return rc; +} + +/** + * Query configuration, unsigned 64-bit integer value. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an integer value + * @param pu64 Where to store the value. + */ +DECLINLINE(int) VDCFGQueryU64(PVDINTERFACECONFIG pCfgIf, const char *pszName, + uint64_t *pu64) +{ + char aszBuf[32]; + int rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, aszBuf, sizeof(aszBuf)); + if (RT_SUCCESS(rc)) + { + rc = RTStrToUInt64Full(aszBuf, 0, pu64); + } + + return rc; +} + +/** + * Query configuration, unsigned 32-bit integer value with default. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an integer value + * @param pu32 Where to store the value. Set to default on failure. + * @param u32Def The default value. + */ +DECLINLINE(int) VDCFGQueryU32Def(PVDINTERFACECONFIG pCfgIf, + const char *pszName, uint32_t *pu32, + uint32_t u32Def) +{ + uint64_t u64; + int rc = VDCFGQueryU64Def(pCfgIf, pszName, &u64, u32Def); + if (RT_SUCCESS(rc)) + { + if (!(u64 & UINT64_C(0xffffffff00000000))) + *pu32 = (uint32_t)u64; + else + rc = VERR_CFGM_INTEGER_TOO_BIG; + } + return rc; +} + +/** + * Query configuration, bool value with default. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an integer value + * @param pf Where to store the value. Set to default on failure. + * @param fDef The default value. + */ +DECLINLINE(int) VDCFGQueryBoolDef(PVDINTERFACECONFIG pCfgIf, + const char *pszName, bool *pf, + bool fDef) +{ + uint64_t u64; + int rc = VDCFGQueryU64Def(pCfgIf, pszName, &u64, fDef); + if (RT_SUCCESS(rc)) + *pf = u64 ? true : false; + return rc; +} + +/** + * Query configuration, bool value. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an integer value + * @param pf Where to store the value. + */ +DECLINLINE(int) VDCFGQueryBool(PVDINTERFACECONFIG pCfgIf, const char *pszName, + bool *pf) +{ + uint64_t u64; + int rc = VDCFGQueryU64(pCfgIf, pszName, &u64); + if (RT_SUCCESS(rc)) + *pf = u64 ? true : false; + return rc; +} + +/** + * Query configuration, dynamically allocated (RTMemAlloc) zero terminated + * character value. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an zero terminated character value + * @param ppszString Where to store the string pointer. Not set on failure. + * Free this using RTMemFree(). + */ +DECLINLINE(int) VDCFGQueryStringAlloc(PVDINTERFACECONFIG pCfgIf, + const char *pszName, char **ppszString) +{ + size_t cb; + int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb); + if (RT_SUCCESS(rc)) + { + char *pszString = (char *)RTMemAlloc(cb); + if (pszString) + { + rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, pszString, cb); + if (RT_SUCCESS(rc)) + *ppszString = pszString; + else + RTMemFree(pszString); + } + else + rc = VERR_NO_MEMORY; + } + return rc; +} + +/** + * Query configuration, dynamically allocated (RTMemAlloc) zero terminated + * character value with default. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an zero terminated character value + * @param ppszString Where to store the string pointer. Not set on failure. + * Free this using RTMemFree(). + * @param pszDef The default value. + */ +DECLINLINE(int) VDCFGQueryStringAllocDef(PVDINTERFACECONFIG pCfgIf, + const char *pszName, + char **ppszString, + const char *pszDef) +{ + size_t cb; + int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb); + if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT) + { + cb = strlen(pszDef) + 1; + rc = VINF_SUCCESS; + } + if (RT_SUCCESS(rc)) + { + char *pszString = (char *)RTMemAlloc(cb); + if (pszString) + { + rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, pszString, cb); + if (rc == VERR_CFGM_VALUE_NOT_FOUND || rc == VERR_CFGM_NO_PARENT) + { + memcpy(pszString, pszDef, cb); + rc = VINF_SUCCESS; + } + if (RT_SUCCESS(rc)) + *ppszString = pszString; + else + RTMemFree(pszString); + } + else + rc = VERR_NO_MEMORY; + } + return rc; +} + +/** + * Query configuration, dynamically allocated (RTMemAlloc) byte string value. + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param pszName Name of an zero terminated character value + * @param ppvData Where to store the byte string pointer. Not set on failure. + * Free this using RTMemFree(). + * @param pcbData Where to store the byte string length. + */ +DECLINLINE(int) VDCFGQueryBytesAlloc(PVDINTERFACECONFIG pCfgIf, + const char *pszName, void **ppvData, size_t *pcbData) +{ + size_t cb; + int rc = pCfgIf->pfnQuerySize(pCfgIf->Core.pvUser, pszName, &cb); + if (RT_SUCCESS(rc)) + { + char *pbData; + Assert(cb); + + pbData = (char *)RTMemAlloc(cb); + if (pbData) + { + if(pCfgIf->pfnQueryBytes) + rc = pCfgIf->pfnQueryBytes(pCfgIf->Core.pvUser, pszName, pbData, cb); + else + rc = pCfgIf->pfnQuery(pCfgIf->Core.pvUser, pszName, pbData, cb); + + if (RT_SUCCESS(rc)) + { + *ppvData = pbData; + /* Exclude terminator if the byte data was obtained using the string query callback. */ + *pcbData = cb; + if (!pCfgIf->pfnQueryBytes) + (*pcbData)--; + } + else + RTMemFree(pbData); + } + else + rc = VERR_NO_MEMORY; + } + return rc; +} + +/** + * Set property value to string (optionally create if non-existent). + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param fCreate Create the property if it doesn't exist + * @param pszName Name of property + * @param pszValue String value to assign to property + */ +DECLINLINE(int) VDCFGUpdate(PVDINTERFACECONFIG pCfgIf, bool fCreate, const char *pszName, const char *pszValue) +{ + int rc = pCfgIf->pfnUpdate(pCfgIf->Core.pvUser, fCreate, pszName, pszValue); + return rc; +} + +/** + * Set property value to Unsigned Int 64-bit (optionally create if non-existent). + * + * @return VBox status code. + * @param pCfgIf Pointer to configuration callback table. + * @param fCreate Create the property if it doesn't exist + * @param pszName Name of property + * @param u64Value 64-bit unsigned value to save with property. + */ + +DECLINLINE(int) VDCFGUpdateU64(PVDINTERFACECONFIG pCfgIf, bool fCreate, const char *pszName, uint64_t u64Value) +{ + int rc = 0; + char pszValue[21]; + (void) RTStrPrintf(pszValue, sizeof(pszValue), "%RU64", u64Value); + rc = VDCFGUpdate(pCfgIf, fCreate, pszName, pszValue); + return rc; +} + + + +/** Forward declaration of a VD socket. */ +typedef struct VDSOCKETINT *VDSOCKET; +/** Pointer to a VD socket. */ +typedef VDSOCKET *PVDSOCKET; +/** Nil socket handle. */ +#define NIL_VDSOCKET ((VDSOCKET)0) + +/** Connect flag to indicate that the backend wants to use the extended + * socket I/O multiplexing call. This might not be supported on all configurations + * (internal networking and iSCSI) + * and the backend needs to take appropriate action. + */ +#define VD_INTERFACETCPNET_CONNECT_EXTENDED_SELECT RT_BIT_32(0) + +/** @name Select events + * @{ */ +/** Readable without blocking. */ +#define VD_INTERFACETCPNET_EVT_READ RT_BIT_32(0) +/** Writable without blocking. */ +#define VD_INTERFACETCPNET_EVT_WRITE RT_BIT_32(1) +/** Error condition, hangup, exception or similar. */ +#define VD_INTERFACETCPNET_EVT_ERROR RT_BIT_32(2) +/** Hint for the select that getting interrupted while waiting is more likely. + * The interface implementation can optimize the waiting strategy based on this. + * It is assumed that it is more likely to get one of the above socket events + * instead of being interrupted if the flag is not set. */ +#define VD_INTERFACETCPNET_HINT_INTERRUPT RT_BIT_32(3) +/** Mask of the valid bits. */ +#define VD_INTERFACETCPNET_EVT_VALID_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * TCP network stack interface + * + * Per-image. Mandatory for backends which have the VD_CAP_TCPNET bit set. + */ +typedef struct VDINTERFACETCPNET +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Creates a socket. The socket is not connected if this succeeds. + * + * @return iprt status code. + * @retval VERR_NOT_SUPPORTED if the combination of flags is not supported. + * @param fFlags Combination of the VD_INTERFACETCPNET_CONNECT_* \#defines. + * @param phVdSock Where to store the handle. + */ + DECLR3CALLBACKMEMBER(int, pfnSocketCreate, (uint32_t fFlags, PVDSOCKET phVdSock)); + + /** + * Destroys the socket. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + */ + DECLR3CALLBACKMEMBER(int, pfnSocketDestroy, (VDSOCKET hVdSock)); + + /** + * Connect as a client to a TCP port. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer).. + * @param pszAddress The address to connect to. + * @param uPort The port to connect to. + * @param cMillies Number of milliseconds to wait for the connect attempt to complete. + * Use RT_INDEFINITE_WAIT to wait for ever. + * Use RT_SOCKETCONNECT_DEFAULT_WAIT to wait for the default time + * configured on the running system. + */ + DECLR3CALLBACKMEMBER(int, pfnClientConnect, (VDSOCKET hVdSock, const char *pszAddress, uint32_t uPort, + RTMSINTERVAL cMillies)); + + /** + * Close a TCP connection. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + */ + DECLR3CALLBACKMEMBER(int, pfnClientClose, (VDSOCKET hVdSock)); + + /** + * Returns whether the socket is currently connected to the client. + * + * @returns true if the socket is connected. + * false otherwise. + * @param hVdSock Socket handle (/ pointer). + */ + DECLR3CALLBACKMEMBER(bool, pfnIsClientConnected, (VDSOCKET hVdSock)); + + /** + * Socket I/O multiplexing. + * Checks if the socket is ready for reading. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param cMillies Number of milliseconds to wait for the socket. + * Use RT_INDEFINITE_WAIT to wait for ever. + */ + DECLR3CALLBACKMEMBER(int, pfnSelectOne, (VDSOCKET hVdSock, RTMSINTERVAL cMillies)); + + /** + * Receive data from a socket. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. + * If NULL the entire buffer will be filled upon successful return. + * If not NULL a partial read can be done successfully. + */ + DECLR3CALLBACKMEMBER(int, pfnRead, (VDSOCKET hVdSock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)); + + /** + * Send data to a socket. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite, (VDSOCKET hVdSock, const void *pvBuffer, size_t cbBuffer)); + + /** + * Send data from scatter/gather buffer to a socket. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pSgBuf Scatter/gather buffer to write data to socket. + */ + DECLR3CALLBACKMEMBER(int, pfnSgWrite, (VDSOCKET hVdSock, PCRTSGBUF pSgBuf)); + + /** + * Receive data from a socket - not blocking. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pvBuffer Where to put the data we read. + * @param cbBuffer Read buffer size. + * @param pcbRead Number of bytes read. + */ + DECLR3CALLBACKMEMBER(int, pfnReadNB, (VDSOCKET hVdSock, void *pvBuffer, size_t cbBuffer, size_t *pcbRead)); + + /** + * Send data to a socket - not blocking. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pvBuffer Buffer to write data to socket. + * @param cbBuffer How much to write. + * @param pcbWritten Number of bytes written. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteNB, (VDSOCKET hVdSock, const void *pvBuffer, size_t cbBuffer, size_t *pcbWritten)); + + /** + * Send data from scatter/gather buffer to a socket - not blocking. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pSgBuf Scatter/gather buffer to write data to socket. + * @param pcbWritten Number of bytes written. + */ + DECLR3CALLBACKMEMBER(int, pfnSgWriteNB, (VDSOCKET hVdSock, PRTSGBUF pSgBuf, size_t *pcbWritten)); + + /** + * Flush socket write buffers. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + */ + DECLR3CALLBACKMEMBER(int, pfnFlush, (VDSOCKET hVdSock)); + + /** + * Enables or disables delaying sends to coalesce packets. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param fEnable When set to true enables coalescing. + */ + DECLR3CALLBACKMEMBER(int, pfnSetSendCoalescing, (VDSOCKET hVdSock, bool fEnable)); + + /** + * Gets the address of the local side. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pAddr Where to store the local address on success. + */ + DECLR3CALLBACKMEMBER(int, pfnGetLocalAddress, (VDSOCKET hVdSock, PRTNETADDR pAddr)); + + /** + * Gets the address of the other party. + * + * @return iprt status code. + * @param hVdSock Socket handle (/ pointer). + * @param pAddr Where to store the peer address on success. + */ + DECLR3CALLBACKMEMBER(int, pfnGetPeerAddress, (VDSOCKET hVdSock, PRTNETADDR pAddr)); + + /** + * Socket I/O multiplexing - extended version which can be woken up. + * Checks if the socket is ready for reading or writing. + * + * @return iprt status code. + * @retval VERR_INTERRUPTED if the thread was woken up by a pfnPoke call. + * @param hVdSock VD Socket handle(/pointer). + * @param fEvents Mask of events to wait for. + * @param pfEvents Where to store the received events. + * @param cMillies Number of milliseconds to wait for the socket. + * Use RT_INDEFINITE_WAIT to wait for ever. + */ + DECLR3CALLBACKMEMBER(int, pfnSelectOneEx, (VDSOCKET hVdSock, uint32_t fEvents, + uint32_t *pfEvents, RTMSINTERVAL cMillies)); + + /** + * Wakes up the thread waiting in pfnSelectOneEx. + * + * @return iprt status code. + * @param hVdSock VD Socket handle(/pointer). + */ + DECLR3CALLBACKMEMBER(int, pfnPoke, (VDSOCKET hVdSock)); + +} VDINTERFACETCPNET, *PVDINTERFACETCPNET; + +/** + * Get TCP network stack interface from interface list. + * + * @return Pointer to the first TCP network stack interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACETCPNET) VDIfTcpNetGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_TCPNET); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_TCPNET) + && (pIf->cbSize == sizeof(VDINTERFACETCPNET))), + ("Not a TCP net interface"), NULL); + + return (PVDINTERFACETCPNET)pIf; +} + + +/** + * Interface to synchronize concurrent accesses by several threads. + * + * @note The scope of this interface is to manage concurrent accesses after + * the HDD container has been created, and they must stop before destroying the + * container. Opening or closing images is covered by the synchronization, but + * that does not mean it is safe to close images while a thread executes + * #VDMerge or #VDCopy operating on these images. Making them safe would require + * the lock to be held during the entire operation, which prevents other + * concurrent acitivities. + * + * @note Right now this is kept as simple as possible, and does not even + * attempt to provide enough information to allow e.g. concurrent write + * accesses to different areas of the disk. The reason is that it is very + * difficult to predict which area of a disk is affected by a write, + * especially when different image formats are mixed. Maybe later a more + * sophisticated interface will be provided which has the necessary information + * about worst case affected areas. + * + * Per-disk interface. Optional, needed if the disk is accessed concurrently + * by several threads, e.g. when merging diff images while a VM is running. + */ +typedef struct VDINTERFACETHREADSYNC +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Start a read operation. + */ + DECLR3CALLBACKMEMBER(int, pfnStartRead, (void *pvUser)); + + /** + * Finish a read operation. + */ + DECLR3CALLBACKMEMBER(int, pfnFinishRead, (void *pvUser)); + + /** + * Start a write operation. + */ + DECLR3CALLBACKMEMBER(int, pfnStartWrite, (void *pvUser)); + + /** + * Finish a write operation. + */ + DECLR3CALLBACKMEMBER(int, pfnFinishWrite, (void *pvUser)); + +} VDINTERFACETHREADSYNC, *PVDINTERFACETHREADSYNC; + +/** + * Get thread synchronization interface from interface list. + * + * @return Pointer to the first thread synchronization interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACETHREADSYNC) VDIfThreadSyncGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_THREADSYNC); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_THREADSYNC) + && (pIf->cbSize == sizeof(VDINTERFACETHREADSYNC))), + ("Not a thread synchronization interface"), NULL); + + return (PVDINTERFACETHREADSYNC)pIf; +} + +/** + * Interface to query usage of disk ranges. + * + * Per-operation interface. Optional. + */ +typedef struct VDINTERFACEQUERYRANGEUSE +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Query use of a disk range. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryRangeUse, (void *pvUser, uint64_t off, uint64_t cb, + bool *pfUsed)); + +} VDINTERFACEQUERYRANGEUSE, *PVDINTERFACEQUERYRANGEUSE; + +/** + * Get query range use interface from interface list. + * + * @return Pointer to the first thread synchronization interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACEQUERYRANGEUSE) VDIfQueryRangeUseGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_QUERYRANGEUSE); + + /* Check that the interface descriptor is a progress interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_QUERYRANGEUSE) + && (pIf->cbSize == sizeof(VDINTERFACEQUERYRANGEUSE))), + ("Not a query range use interface"), NULL); + + return (PVDINTERFACEQUERYRANGEUSE)pIf; +} + +DECLINLINE(int) vdIfQueryRangeUse(PVDINTERFACEQUERYRANGEUSE pIfQueryRangeUse, uint64_t off, uint64_t cb, + bool *pfUsed) +{ + return pIfQueryRangeUse->pfnQueryRangeUse(pIfQueryRangeUse->Core.pvUser, off, cb, pfUsed); +} + + +/** + * Interface used to retrieve keys for cryptographic operations. + * + * Per-module interface. Optional but cryptographic modules might fail and + * return an error if this is not present. + */ +typedef struct VDINTERFACECRYPTO +{ + /** + * Common interface header. + */ + VDINTERFACE Core; + + /** + * Retains a key identified by the ID. The caller will only hold a reference + * to the key and must not modify the key buffer in any way. + * + * @returns VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param pszId The alias/id for the key to retrieve. + * @param ppbKey Where to store the pointer to the key buffer on success. + * @param pcbKey Where to store the size of the key in bytes on success. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyRetain, (void *pvUser, const char *pszId, const uint8_t **ppbKey, size_t *pcbKey)); + + /** + * Releases one reference of the key identified by the given identifier. + * The caller must not access the key buffer after calling this operation. + * + * @returns VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param pszId The alias/id for the key to release. + * + * @note It is advised to release the key whenever it is not used anymore so + * the entity storing the key can do anything to make retrieving the key + * from memory more difficult like scrambling the memory buffer for + * instance. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyRelease, (void *pvUser, const char *pszId)); + + /** + * Gets a reference to the password identified by the given ID to open a key store supplied through the config interface. + * + * @returns VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param pszId The alias/id for the password to retain. + * @param ppszPassword Where to store the password to unlock the key store on success. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyStorePasswordRetain, (void *pvUser, const char *pszId, const char **ppszPassword)); + + /** + * Releases a reference of the password previously acquired with VDINTERFACECRYPTO::pfnKeyStorePasswordRetain() + * identified by the given ID. + * + * @returns VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param pszId The alias/id for the password to release. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyStorePasswordRelease, (void *pvUser, const char *pszId)); + + /** + * Saves a key store. + * + * @returns VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param pvKeyStore The key store to save. + * @param cbKeyStore Size of the key store in bytes. + * + * @note The format is filter specific and should be treated as binary data. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyStoreSave, (void *pvUser, const void *pvKeyStore, size_t cbKeyStore)); + + /** + * Returns the parameters after the key store was loaded successfully. + * + * @returns VBox status code. + * @param pvUser The opaque user data associated with this interface. + * @param pszCipher The cipher identifier the DEK is used for. + * @param pbDek The raw DEK which was contained in the key store loaded by + * VDINTERFACECRYPTO::pfnKeyStoreLoad(). + * @param cbDek The size of the DEK. + * + * @note The provided pointer to the DEK is only valid until this call returns. + * The content might change afterwards with out notice (when scrambling the key + * for further protection for example) or might be even freed. + * + * @note This method is optional and can be NULL if the caller does not require the + * parameters. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyStoreReturnParameters, (void *pvUser, const char *pszCipher, + const uint8_t *pbDek, size_t cbDek)); + +} VDINTERFACECRYPTO, *PVDINTERFACECRYPTO; + + +/** + * Get error interface from interface list. + * + * @return Pointer to the first error interface in the list. + * @param pVDIfs Pointer to the interface list. + */ +DECLINLINE(PVDINTERFACECRYPTO) VDIfCryptoGet(PVDINTERFACE pVDIfs) +{ + PVDINTERFACE pIf = VDInterfaceGet(pVDIfs, VDINTERFACETYPE_CRYPTO); + + /* Check that the interface descriptor is a crypto interface. */ + AssertMsgReturn( !pIf + || ( (pIf->enmInterface == VDINTERFACETYPE_CRYPTO) + && (pIf->cbSize == sizeof(VDINTERFACECRYPTO))), + ("Not an crypto interface\n"), NULL); + + return (PVDINTERFACECRYPTO)pIf; +} + +/** + * Retains a key identified by the ID. The caller will only hold a reference + * to the key and must not modify the key buffer in any way. + * + * @returns VBox status code. + * @param pIfCrypto Pointer to the crypto interface. + * @param pszId The alias/id for the key to retrieve. + * @param ppbKey Where to store the pointer to the key buffer on success. + * @param pcbKey Where to store the size of the key in bytes on success. + */ +DECLINLINE(int) vdIfCryptoKeyRetain(PVDINTERFACECRYPTO pIfCrypto, const char *pszId, const uint8_t **ppbKey, size_t *pcbKey) +{ + return pIfCrypto->pfnKeyRetain(pIfCrypto->Core.pvUser, pszId, ppbKey, pcbKey); +} + +/** + * Releases one reference of the key identified by the given identifier. + * The caller must not access the key buffer after calling this operation. + * + * @returns VBox status code. + * @param pIfCrypto Pointer to the crypto interface. + * @param pszId The alias/id for the key to release. + * + * @note It is advised to release the key whenever it is not used anymore so + * the entity storing the key can do anything to make retrieving the key + * from memory more difficult like scrambling the memory buffer for + * instance. + */ +DECLINLINE(int) vdIfCryptoKeyRelease(PVDINTERFACECRYPTO pIfCrypto, const char *pszId) +{ + return pIfCrypto->pfnKeyRelease(pIfCrypto->Core.pvUser, pszId); +} + +/** + * Gets a reference to the password identified by the given ID to open a key store supplied through the config interface. + * + * @returns VBox status code. + * @param pIfCrypto Pointer to the crypto interface. + * @param pszId The alias/id for the password to retain. + * @param ppszPassword Where to store the password to unlock the key store on success. + */ +DECLINLINE(int) vdIfCryptoKeyStorePasswordRetain(PVDINTERFACECRYPTO pIfCrypto, const char *pszId, const char **ppszPassword) +{ + return pIfCrypto->pfnKeyStorePasswordRetain(pIfCrypto->Core.pvUser, pszId, ppszPassword); +} + +/** + * Releases a reference of the password previously acquired with VDINTERFACECRYPTO::pfnKeyStorePasswordRetain() + * identified by the given ID. + * + * @returns VBox status code. + * @param pIfCrypto Pointer to the crypto interface. + * @param pszId The alias/id for the password to release. + */ +DECLINLINE(int) vdIfCryptoKeyStorePasswordRelease(PVDINTERFACECRYPTO pIfCrypto, const char *pszId) +{ + return pIfCrypto->pfnKeyStorePasswordRelease(pIfCrypto->Core.pvUser, pszId); +} + +/** + * Saves a key store. + * + * @returns VBox status code. + * @param pIfCrypto Pointer to the crypto interface. + * @param pvKeyStore The key store to save. + * @param cbKeyStore Size of the key store in bytes. + * + * @note The format is filter specific and should be treated as binary data. + */ +DECLINLINE(int) vdIfCryptoKeyStoreSave(PVDINTERFACECRYPTO pIfCrypto, const void *pvKeyStore, size_t cbKeyStore) +{ + return pIfCrypto->pfnKeyStoreSave(pIfCrypto->Core.pvUser, pvKeyStore, cbKeyStore); +} + +/** + * Returns the parameters after the key store was loaded successfully. + * + * @returns VBox status code. + * @param pIfCrypto Pointer to the crypto interface. + * @param pszCipher The cipher identifier the DEK is used for. + * @param pbDek The raw DEK which was contained in the key store loaded by + * VDINTERFACECRYPTO::pfnKeyStoreLoad(). + * @param cbDek The size of the DEK. + * + * @note The provided pointer to the DEK is only valid until this call returns. + * The content might change afterwards with out notice (when scrambling the key + * for further protection for example) or might be even freed. + * + * @note This method is optional and can be NULL if the caller does not require the + * parameters. + */ +DECLINLINE(int) vdIfCryptoKeyStoreReturnParameters(PVDINTERFACECRYPTO pIfCrypto, const char *pszCipher, + const uint8_t *pbDek, size_t cbDek) +{ + if (pIfCrypto->pfnKeyStoreReturnParameters) + return pIfCrypto->pfnKeyStoreReturnParameters(pIfCrypto->Core.pvUser, pszCipher, pbDek, cbDek); + + return VINF_SUCCESS; +} + + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vd_ifs_h */ diff --git a/include/VBox/vd-image-backend.h b/include/VBox/vd-image-backend.h new file mode 100644 index 00000000..163720c9 --- /dev/null +++ b/include/VBox/vd-image-backend.h @@ -0,0 +1,617 @@ +/** @file + * VD: Image backend interface. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_image_backend_h +#define VBOX_INCLUDED_vd_image_backend_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/** @name VBox HDD backend write flags + * @{ + */ +/** Do not allocate a new block on this write. This is just an advisory + * flag. The backend may still decide in some circumstances that it wants + * to ignore this flag (which may cause extra dynamic image expansion). */ +#define VD_WRITE_NO_ALLOC RT_BIT(1) +/** @}*/ + +/** @name VBox HDD backend discard flags + * @{ + */ +/** Don't discard block but mark the given range as unused + * (usually by writing 0's to it). + * This doesn't require the range to be aligned on a block boundary but + * the image size might not be decreased. */ +#define VD_DISCARD_MARK_UNUSED RT_BIT(0) +/** @}*/ + +/** @name VBox HDD backend metadata traverse flags + * @{ + */ +/** Include per block metadata while traversing the metadata. + * This might take much longer instead of traversing just global metadata. */ +#define VD_TRAVERSE_METADATA_INCLUDE_PER_BLOCK_METADATA RT_BIT(0) +/** @}*/ + +/** + * Image format backend interface used by VBox HDD Container implementation. + */ +typedef struct VDIMAGEBACKEND +{ + /** Structure version. VD_IMGBACKEND_VERSION defines the current version. */ + uint32_t u32Version; + /** The name of the backend (constant string). */ + const char *pszBackendName; + /** The capabilities of the backend. */ + uint64_t uBackendCaps; + + /** + * Pointer to a NULL-terminated array, containing the supported + * file extensions. Note that some backends do not work on files, so this + * pointer may just contain NULL. + */ + PCVDFILEEXTENSION paFileExtensions; + + /** + * Pointer to an array of structs describing each supported config key. + * Terminated by a NULL config key. Note that some backends do not support + * the configuration interface, so this pointer may just contain NULL. + * Mandatory if the backend sets VD_CAP_CONFIG. + */ + PCVDCONFIGINFO paConfigInfo; + + /** + * Check whether the file is supported by the backend. + * + * @returns VBox status code. + * @param pszFilename Name of the image file. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param enmDesiredType The desired image type, VDTYPE_INVALID if anything goes. + * @param penmType Returns the supported device type on success. + */ + DECLR3CALLBACKMEMBER(int, pfnProbe, (const char *pszFilename, PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, VDTYPE enmDesiredType, VDTYPE *penmType)); + + /** + * Open a disk image. + * + * @returns VBox status code. + * @param pszFilename Name of the image file to open. Guaranteed to be available and + * unchanged during the lifetime of this image. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param enmType Requested type of the image. + * @param ppBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(int, pfnOpen, (const char *pszFilename, unsigned uOpenFlags, + PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage, + VDTYPE enmType, void **ppBackendData)); + + /** + * Create a disk image. + * + * @returns VBox status code. + * @param pszFilename Name of the image file to create. Guaranteed to be available and + * unchanged during the lifetime of this image. + * @param cbSize Image size in bytes. + * @param uImageFlags Flags specifying special image features. + * @param pszComment Pointer to image comment. NULL is ok. + * @param pPCHSGeometry Physical drive geometry CHS <= (16383,16,255). + * @param pLCHSGeometry Logical drive geometry CHS <= (1024,255,63). + * @param pUuid New UUID of the image. Not NULL. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param uPercentStart Starting value for progress percentage. + * @param uPercentSpan Span for varying progress percentage. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + * @param enmType Requested type of the image. + * @param ppBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(int, pfnCreate, (const char *pszFilename, uint64_t cbSize, + unsigned uImageFlags, const char *pszComment, + PCVDGEOMETRY pPCHSGeometry, + PCVDGEOMETRY pLCHSGeometry, + PCRTUUID pUuid, unsigned uOpenFlags, + unsigned uPercentStart, unsigned uPercentSpan, + PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation, + VDTYPE enmType, + void **ppBackendData)); + + /** + * Rename a disk image. Only needs to work as long as the operating + * system's rename file functionality is usable. If an attempt is made to + * rename an image to a location on another disk/filesystem, this function + * may just fail with an appropriate error code (not changing the opened + * image data at all). Also works only on images which actually refer to + * regular files. May be NULL. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pszFilename New name of the image file. Guaranteed to be available and + * unchanged during the lifetime of this image. + */ + DECLR3CALLBACKMEMBER(int, pfnRename, (void *pBackendData, const char *pszFilename)); + + /** + * Close a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param fDelete If true, delete the image from the host disk. + */ + DECLR3CALLBACKMEMBER(int, pfnClose, (void *pBackendData, bool fDelete)); + + /** + * Start a read request. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param uOffset The offset of the virtual disk to read from. + * @param cbToRead How many bytes to read. + * @param pIoCtx I/O context associated with this request. + * @param pcbActuallyRead Pointer to returned number of bytes read. + */ + DECLR3CALLBACKMEMBER(int, pfnRead, (void *pBackendData, uint64_t uOffset, size_t cbToRead, + PVDIOCTX pIoCtx, size_t *pcbActuallyRead)); + + /** + * Start a write request. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param uOffset The offset of the virtual disk to write to. + * @param cbToWrite How many bytes to write. + * @param pIoCtx I/O context associated with this request. + * @param pcbWriteProcess Pointer to returned number of bytes that could + * be processed. In case the function returned + * VERR_VD_BLOCK_FREE this is the number of bytes + * that could be written in a full block write, + * when prefixed/postfixed by the appropriate + * amount of (previously read) padding data. + * @param pcbPreRead Pointer to the returned amount of data that must + * be prefixed to perform a full block write. + * @param pcbPostRead Pointer to the returned amount of data that must + * be postfixed to perform a full block write. + * @param fWrite Flags which affect write behavior. Combination + * of the VD_WRITE_* flags. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite, (void *pBackendData, uint64_t uOffset, size_t cbToWrite, + PVDIOCTX pIoCtx, + size_t *pcbWriteProcess, size_t *pcbPreRead, + size_t *pcbPostRead, unsigned fWrite)); + + /** + * Flush data to disk. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pIoCtx I/O context associated with this request. + */ + DECLR3CALLBACKMEMBER(int, pfnFlush, (void *pBackendData, PVDIOCTX pIoCtx)); + + /** + * Discards the given amount of bytes decreasing the size of the image if possible + * + * @returns VBox status code. + * @retval VERR_VD_DISCARD_ALIGNMENT_NOT_MET if the range doesn't meet the required alignment + * for the discard. + * @param pBackendData Opaque state data for this image. + * @param pIoCtx I/O context associated with this request. + * @param uOffset The offset of the first byte to discard. + * @param cbDiscard How many bytes to discard. + * @param pcbPreAllocated Pointer to the returned amount of bytes that must + * be discarded before the range to perform a full + * block discard. + * @param pcbPostAllocated Pointer to the returned amount of bytes that must + * be discarded after the range to perform a full + * block discard. + * @param pcbActuallyDiscarded Pointer to the returned amount of bytes which + * could be actually discarded. + * @param ppbmAllocationBitmap Where to store the pointer to the allocation bitmap + * if VERR_VD_DISCARD_ALIGNMENT_NOT_MET is returned or NULL + * if the allocation bitmap should be returned. + * @param fDiscard Flags which affect discard behavior. Combination + * of the VD_DISCARD_* flags. + */ + DECLR3CALLBACKMEMBER(int, pfnDiscard, (void *pBackendData, PVDIOCTX pIoCtx, + uint64_t uOffset, size_t cbDiscard, + size_t *pcbPreAllocated, + size_t *pcbPostAllocated, + size_t *pcbActuallyDiscarded, + void **ppbmAllocationBitmap, + unsigned fDiscard)); + + /** + * Get the version of a disk image. + * + * @returns version of disk image. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetVersion, (void *pBackendData)); + + /** + * Get the file size of a disk image. + * + * @returns size of disk image in bytes. + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetFileSize, (void *pBackendData)); + + /** + * Get virtual disk PCHS geometry stored in a disk image. + * + * @returns VBox status code. + * @returns VERR_VD_GEOMETRY_NOT_SET if no geometry present in the image. + * @param pBackendData Opaque state data for this image. + * @param pPCHSGeometry Where to store the geometry. Not NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnGetPCHSGeometry, (void *pBackendData, PVDGEOMETRY pPCHSGeometry)); + + /** + * Set virtual disk PCHS geometry stored in a disk image. + * Only called if geometry is different than before. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pPCHSGeometry Where to load the geometry from. Not NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnSetPCHSGeometry, (void *pBackendData, PCVDGEOMETRY pPCHSGeometry)); + + /** + * Get virtual disk LCHS geometry stored in a disk image. + * + * @returns VBox status code. + * @returns VERR_VD_GEOMETRY_NOT_SET if no geometry present in the image. + * @param pBackendData Opaque state data for this image. + * @param pLCHSGeometry Where to store the geometry. Not NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnGetLCHSGeometry, (void *pBackendData, PVDGEOMETRY pLCHSGeometry)); + + /** + * Set virtual disk LCHS geometry stored in a disk image. + * Only called if geometry is different than before. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pLCHSGeometry Where to load the geometry from. Not NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnSetLCHSGeometry, (void *pBackendData, PCVDGEOMETRY pLCHSGeometry)); + + /** + * Returns a region list for the disk image if supported, optional. + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if region lists are not supported for this kind of image. + * @param pBackendData Opaque state data for this image. + * @param ppRegionList Where to store the pointer to the region list on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryRegions, (void *pBackendData, PCVDREGIONLIST *ppRegionList)); + + /** + * Releases the region list acquired with VDIMAGEBACKEND::pfnQueryRegions() before. + * + * @returns nothing. + * @param pBackendData Opaque state data for this image. + * @param pRegionList The region list to release. + */ + DECLR3CALLBACKMEMBER(void, pfnRegionListRelease, (void *pBackendData, PCVDREGIONLIST pRegionList)); + + /** + * Get the image flags of a disk image. + * + * @returns image flags of disk image (VD_IMAGE_FLAGS_XXX). + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetImageFlags, (void *pBackendData)); + + /** + * Get the open flags of a disk image. + * + * @returns open flags of disk image (VD_OPEN_FLAGS_XXX). + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetOpenFlags, (void *pBackendData)); + + /** + * Set the open flags of a disk image. + * + * May cause the image to be locked in a different mode or be reopened (which + * can fail). + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param uOpenFlags New open flags for this image (VD_OPEN_FLAGS_XXX). + */ + DECLR3CALLBACKMEMBER(int, pfnSetOpenFlags, (void *pBackendData, unsigned uOpenFlags)); + + /** + * Get comment of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pszComment Where to store the comment. + * @param cbComment Size of the comment buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnGetComment, (void *pBackendData, char *pszComment, size_t cbComment)); + + /** + * Set comment of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pszComment Where to get the comment from. NULL resets comment. + * The comment is silently truncated if the image format + * limit is exceeded. + */ + DECLR3CALLBACKMEMBER(int, pfnSetComment, (void *pBackendData, const char *pszComment)); + + /** + * Get UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to store the image UUID. + */ + DECLR3CALLBACKMEMBER(int, pfnGetUuid, (void *pBackendData, PRTUUID pUuid)); + + /** + * Set UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to get the image UUID from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetUuid, (void *pBackendData, PCRTUUID pUuid)); + + /** + * Get last modification UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to store the image modification UUID. + */ + DECLR3CALLBACKMEMBER(int, pfnGetModificationUuid, (void *pBackendData, PRTUUID pUuid)); + + /** + * Set last modification UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to get the image modification UUID from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetModificationUuid, (void *pBackendData, PCRTUUID pUuid)); + + /** + * Get parent UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to store the parent image UUID. + */ + DECLR3CALLBACKMEMBER(int, pfnGetParentUuid, (void *pBackendData, PRTUUID pUuid)); + + /** + * Set parent UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to get the parent image UUID from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetParentUuid, (void *pBackendData, PCRTUUID pUuid)); + + /** + * Get parent modification UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to store the parent image modification UUID. + */ + DECLR3CALLBACKMEMBER(int, pfnGetParentModificationUuid, (void *pBackendData, PRTUUID pUuid)); + + /** + * Set parent modification UUID of a disk image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pUuid Where to get the parent image modification UUID from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetParentModificationUuid, (void *pBackendData, PCRTUUID pUuid)); + + /** + * Dump information about a disk image. + * + * @param pBackendData Opaque state data for this image. + */ + DECLR3CALLBACKMEMBER(void, pfnDump, (void *pBackendData)); + + /** + * Get a time stamp of a disk image. May be NULL. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pTimestamp Where to store the time stamp. + */ + DECLR3CALLBACKMEMBER(int, pfnGetTimestamp, (void *pBackendData, PRTTIMESPEC pTimestamp)); + + /** + * Get the parent time stamp of a disk image. May be NULL. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pTimestamp Where to store the time stamp. + */ + DECLR3CALLBACKMEMBER(int, pfnGetParentTimestamp, (void *pBackendData, PRTTIMESPEC pTimestamp)); + + /** + * Set the parent time stamp of a disk image. May be NULL. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pTimestamp Where to get the time stamp from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetParentTimestamp, (void *pBackendData, PCRTTIMESPEC pTimestamp)); + + /** + * Get the relative path to parent image. May be NULL. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param ppszParentFilename Where to store the path. + */ + DECLR3CALLBACKMEMBER(int, pfnGetParentFilename, (void *pBackendData, char **ppszParentFilename)); + + /** + * Set the relative path to parent image. May be NULL. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param pszParentFilename Where to get the path from. + */ + DECLR3CALLBACKMEMBER(int, pfnSetParentFilename, (void *pBackendData, const char *pszParentFilename)); + + /** Returns a human readable hard disk location string given a + * set of hard disk configuration keys. The returned string is an + * equivalent of the full file path for image-based hard disks. + * Mandatory for backends with no VD_CAP_FILE and NULL otherwise. */ + DECLR3CALLBACKMEMBER(int, pfnComposeLocation, (PVDINTERFACE pConfig, char **pszLocation)); + + /** Returns a human readable hard disk name string given a + * set of hard disk configuration keys. The returned string is an + * equivalent of the file name part in the full file path for + * image-based hard disks. Mandatory for backends with no + * VD_CAP_FILE and NULL otherwise. */ + DECLR3CALLBACKMEMBER(int, pfnComposeName, (PVDINTERFACE pConfig, char **pszName)); + + /** + * Compact the image. The pointer may be NULL, indicating that this + * isn't supported yet (for file-based images) or not necessary. + * + * @returns VBox status code. + * @returns VERR_NOT_SUPPORTED if this image cannot be compacted yet. + * @param pBackendData Opaque state data for this image. + * @param uPercentStart Starting value for progress percentage. + * @param uPercentSpan Span for varying progress percentage. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ + DECLR3CALLBACKMEMBER(int, pfnCompact, (void *pBackendData, + unsigned uPercentStart, unsigned uPercentSpan, + PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation)); + + /** + * Resize the image. The pointer may be NULL, indicating that this + * isn't supported yet (for file-based images) or not necessary. + * + * @returns VBox status code. + * @returns VERR_NOT_SUPPORTED if this image cannot be resized yet. + * @param pBackendData Opaque state data for this image. + * @param cbSize New size of the image. + * @param pPCHSGeometry Pointer to the new physical disk geometry <= (16383,16,63). Not NULL. + * @param pLCHSGeometry Pointer to the new logical disk geometry <= (x,255,63). Not NULL. + * @param uPercentStart Starting value for progress percentage. + * @param uPercentSpan Span for varying progress percentage. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ + DECLR3CALLBACKMEMBER(int, pfnResize, (void *pBackendData, + uint64_t cbSize, + PCVDGEOMETRY pPCHSGeometry, + PCVDGEOMETRY pLCHSGeometry, + unsigned uPercentStart, unsigned uPercentSpan, + PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation)); + + /** + * Try to repair the given image. + * + * @returns VBox status code. + * @param pszFilename Name of the image file. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param fFlags Combination of the VD_REPAIR_* flags. + */ + DECLR3CALLBACKMEMBER(int, pfnRepair, (const char *pszFilename, PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, uint32_t fFlags)); + + /** + * Traverse all metadata of the opened image. + * + * @returns VBox status code. + * @param pBackendData Opaque state data for this image. + * @param fFlags Traverse flags, combination of VD_TRAVERSE_METDATA_* defines. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ + DECLR3CALLBACKMEMBER(int, pfnTraverseMetadata, (void *pBackendData, uint32_t fFlags, + PVDINTERFACE pVDIfsDisk, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation)); + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; + +} VDIMAGEBACKEND; + +/** Pointer to VD backend. */ +typedef VDIMAGEBACKEND *PVDIMAGEBACKEND; +/** Constant pointer to VD backend. */ +typedef const VDIMAGEBACKEND *PCVDIMAGEBACKEND; + +/** The current version of the VDIMAGEBACKEND structure. */ +#define VD_IMGBACKEND_VERSION VD_VERSION_MAKE(0xff01, 3, 0) + +/** @copydoc VDIMAGEBACKEND::pfnComposeLocation */ +DECLCALLBACK(int) genericFileComposeLocation(PVDINTERFACE pConfig, char **pszLocation); +/** @copydoc VDIMAGEBACKEND::pfnComposeName */ +DECLCALLBACK(int) genericFileComposeName(PVDINTERFACE pConfig, char **pszName); + +#endif /* !VBOX_INCLUDED_vd_image_backend_h */ diff --git a/include/VBox/vd-plugin.h b/include/VBox/vd-plugin.h new file mode 100644 index 00000000..f165f1cf --- /dev/null +++ b/include/VBox/vd-plugin.h @@ -0,0 +1,106 @@ +/** @file + * VD: Plugin support API. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_plugin_h +#define VBOX_INCLUDED_vd_plugin_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include + +/** + * Backend register callbacks structure. + */ +typedef struct VDBACKENDREGISTER +{ + /** Interface version. + * This is set to VD_BACKENDREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a new image backend. + * + * @returns VBox status code. + * @param pvUser Opaque user data given in the plugin load callback. + * @param pBackend The image backend to register. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterImage, (void *pvUser, PCVDIMAGEBACKEND pBackend)); + + /** + * Registers a new cache backend. + * + * @returns VBox status code. + * @param pvUser Opaque user data given in the plugin load callback. + * @param pBackend The cache backend to register. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterCache, (void *pvUser, PCVDCACHEBACKEND pBackend)); + + /** + * Registers a new filter plugin. + * @param pvUser Opaque user data given in the plugin load callback. + * @param pBackend The filter backend to register. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterFilter, (void *pvUser, PCVDFILTERBACKEND pBackend)); + +} VDBACKENDREGISTER; +/** Pointer to a backend register callbacks structure. */ +typedef VDBACKENDREGISTER *PVDBACKENDREGISTER; + +/** Current version of the VDBACKENDREGISTER structure. */ +#define VD_BACKENDREG_CB_VERSION VD_VERSION_MAKE(0xff00, 1, 0) + +/** + * Initialization entry point called by the generic VD layer when + * a plugin is loaded. + * + * @returns VBox status code. + * @param pvUser Opaque user data passed in the register callbacks. + * @param pRegisterCallbacks Pointer to the register callbacks structure. + */ +typedef DECLCALLBACKTYPE(int, FNVDPLUGINLOAD,(void *pvUser, PVDBACKENDREGISTER pRegisterCallbacks)); +typedef FNVDPLUGINLOAD *PFNVDPLUGINLOAD; +#define VD_PLUGIN_LOAD_NAME "VDPluginLoad" + +/** The prefix to identify Storage Plugins. */ +#define VD_PLUGIN_PREFIX "VDPlugin" +/** The size of the prefix excluding the '\\0' terminator. */ +#define VD_PLUGIN_PREFIX_LENGTH (sizeof(VD_PLUGIN_PREFIX)-1) + +#endif /* !VBOX_INCLUDED_vd_plugin_h */ diff --git a/include/VBox/vd.h b/include/VBox/vd.h new file mode 100644 index 00000000..7013846e --- /dev/null +++ b/include/VBox/vd.h @@ -0,0 +1,1847 @@ +/** @file + * VBox HDD Container API. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vd_h +#define VBOX_INCLUDED_vd_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + +#ifdef IN_RING0 +# error "There are no VBox HDD Container APIs available in Ring-0 Host Context!" +#endif + +/** @defgroup grp_vd Virtual Disk Container + * @{ + */ + +/** Current VMDK image version. */ +#define VMDK_IMAGE_VERSION (0x0001) + +/** Current VDI image major version. */ +#define VDI_IMAGE_VERSION_MAJOR (0x0001) +/** Current VDI image minor version. */ +#define VDI_IMAGE_VERSION_MINOR (0x0001) +/** Current VDI image version. */ +#define VDI_IMAGE_VERSION ((VDI_IMAGE_VERSION_MAJOR << 16) | VDI_IMAGE_VERSION_MINOR) + +/** Get VDI major version from combined version. */ +#define VDI_GET_VERSION_MAJOR(uVer) ((uVer) >> 16) +/** Get VDI minor version from combined version. */ +#define VDI_GET_VERSION_MINOR(uVer) ((uVer) & 0xffff) + +/** Placeholder for specifying the last opened image. */ +#define VD_LAST_IMAGE 0xffffffffU + +/** Placeholder for VDCopyEx to indicate that the image content is unknown. */ +#define VD_IMAGE_CONTENT_UNKNOWN 0xffffffffU + +/** @name VBox HDD container image flags + * Same values as MediumVariant API enum. + * @{ + */ +/** No flags. */ +#define VD_IMAGE_FLAGS_NONE (0) +/** Fixed image. */ +#define VD_IMAGE_FLAGS_FIXED (0x10000) +/** Diff image. Mutually exclusive with fixed image. */ +#define VD_IMAGE_FLAGS_DIFF (0x20000) +/** VMDK: Split image into 2GB extents. */ +#define VD_VMDK_IMAGE_FLAGS_SPLIT_2G (0x0001) +/** VMDK: Raw disk image (giving access to a number of host partitions). */ +#define VD_VMDK_IMAGE_FLAGS_RAWDISK (0x0002) +/** VMDK: stream optimized image, read only. */ +#define VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED (0x0004) +/** VMDK: ESX variant, use in addition to other flags. */ +#define VD_VMDK_IMAGE_FLAGS_ESX (0x0008) +/** VDI: Fill new blocks with zeroes while expanding image file. Only valid + * for newly created images, never set for opened existing images. */ +#define VD_VDI_IMAGE_FLAGS_ZERO_EXPAND (0x0100) + +/** Mask of valid image flags for VMDK. */ +#define VD_VMDK_IMAGE_FLAGS_MASK ( VD_IMAGE_FLAGS_FIXED | VD_IMAGE_FLAGS_DIFF | VD_IMAGE_FLAGS_NONE \ + | VD_VMDK_IMAGE_FLAGS_SPLIT_2G | VD_VMDK_IMAGE_FLAGS_RAWDISK \ + | VD_VMDK_IMAGE_FLAGS_STREAM_OPTIMIZED | VD_VMDK_IMAGE_FLAGS_ESX) + +/** Mask of valid image flags for VDI. */ +#define VD_VDI_IMAGE_FLAGS_MASK (VD_IMAGE_FLAGS_FIXED | VD_IMAGE_FLAGS_DIFF | VD_IMAGE_FLAGS_NONE | VD_VDI_IMAGE_FLAGS_ZERO_EXPAND) + +/** Mask of all valid image flags for all formats. */ +#define VD_IMAGE_FLAGS_MASK (VD_VMDK_IMAGE_FLAGS_MASK | VD_VDI_IMAGE_FLAGS_MASK) + +/** Default image flags. */ +#define VD_IMAGE_FLAGS_DEFAULT (VD_IMAGE_FLAGS_NONE) +/** @} */ + +/** @name VD image repair flags + * @{ + */ +/** Don't repair the image but check what needs to be done. */ +#define VD_REPAIR_DRY_RUN RT_BIT_32(0) + +/** Mask of all valid repair flags. */ +#define VD_REPAIR_FLAGS_MASK (VD_REPAIR_DRY_RUN) +/** @} */ + +/** @name VD image VFS file flags + * @{ + */ +/** Destroy the VD disk container when the VFS file is released. */ +#define VD_VFSFILE_DESTROY_ON_RELEASE RT_BIT_32(0) + +/** Mask of all valid repair flags. */ +#define VD_VFSFILE_FLAGS_MASK (VD_VFSFILE_DESTROY_ON_RELEASE) +/** @} */ + +/** @name VDISKRAW_XXX - VBox raw disk or partition flags + * @{ + */ +/** No special treatment. */ +#define VDISKRAW_NORMAL 0 +/** Whether this is a raw disk (where the partition information is ignored) or + * not. Valid only in the raw disk descriptor. */ +#define VDISKRAW_DISK RT_BIT(0) +/** Open the corresponding raw disk or partition for reading only, no matter + * how the image is created or opened. */ +#define VDISKRAW_READONLY RT_BIT(1) +/** @} */ + +/** + * Auxiliary type for describing partitions on raw disks. + * + * The entries must be in ascending order (as far as uStart is concerned), and + * must not overlap. Note that this does not correspond 1:1 to partitions, it is + * describing the general meaning of contiguous areas on the disk. + */ +typedef struct VDISKRAWPARTDESC +{ + /** Device to use for this partition/data area. Can be the disk device if + * the offset field is set appropriately. If this is NULL, then this + * partition will not be accessible to the guest. The size of the data area + * must still be set correctly. */ + char *pszRawDevice; + /** Pointer to the partitioning info. NULL means this is a regular data + * area on disk, non-NULL denotes data which should be copied to the + * partition data overlay. */ + void *pvPartitionData; + /** Offset where the data starts in this device. */ + uint64_t offStartInDevice; + /** Offset where the data starts in the disk. */ + uint64_t offStartInVDisk; + /** Size of the data area. */ + uint64_t cbData; + /** Flags for special treatment, see VDISKRAW_XXX. */ + uint32_t uFlags; +} VDISKRAWPARTDESC, *PVDISKRAWPARTDESC; + +/** + * Auxiliary data structure for difference between GPT and MBR disks. + */ +typedef enum VDISKPARTTYPE +{ + VDISKPARTTYPE_MBR = 0, + VDISKPARTTYPE_GPT +} VDISKPARTTYPE; + +/** + * Auxiliary data structure for creating raw disks. + */ +typedef struct VDISKRAW +{ + /** Signature for structure. Must be 'R', 'A', 'W', '\\0'. Actually a trick + * to make logging of the comment string produce sensible results. */ + char szSignature[4]; + /** Flags for special treatment, see VDISKRAW_XXX. */ + uint32_t uFlags; + /** Filename for the raw disk. Ignored for partitioned raw disks. + * For Linux e.g. /dev/sda, and for Windows e.g. //./PhysicalDisk0. */ + char *pszRawDisk; + /** Partitioning type of the disk */ + VDISKPARTTYPE enmPartitioningType; + /** Number of entries in the partition descriptor array. */ + uint32_t cPartDescs; + /** Pointer to the partition descriptor array. */ + PVDISKRAWPARTDESC pPartDescs; +} VDISKRAW, *PVDISKRAW; + + +/** @name VBox HDD container image open mode flags + * @{ + */ +/** Try to open image in read/write exclusive access mode if possible, or in read-only elsewhere. */ +#define VD_OPEN_FLAGS_NORMAL 0 +/** Open image in read-only mode with sharing access with others. */ +#define VD_OPEN_FLAGS_READONLY RT_BIT(0) +/** Honor zero block writes instead of ignoring them whenever possible. + * This is not supported by all formats. It is silently ignored in this case. */ +#define VD_OPEN_FLAGS_HONOR_ZEROES RT_BIT(1) +/** Honor writes of the same data instead of ignoring whenever possible. + * This is handled generically, and is only meaningful for differential image + * formats. It is silently ignored otherwise. */ +#define VD_OPEN_FLAGS_HONOR_SAME RT_BIT(2) +/** Do not perform the base/diff image check on open. This does NOT imply + * opening the image as readonly (would break e.g. adding UUIDs to VMDK files + * created by other products). Images opened with this flag should only be + * used for querying information, and nothing else. */ +#define VD_OPEN_FLAGS_INFO RT_BIT(3) +/** Open image for asynchronous access. Only available if VD_CAP_ASYNC_IO is + * set. VDOpen fails with VERR_NOT_SUPPORTED if this operation is not supported for + * this kind of image. */ +#define VD_OPEN_FLAGS_ASYNC_IO RT_BIT(4) +/** Allow sharing of the image for writable images. May be ignored if the + * format backend doesn't support this type of concurrent access. */ +#define VD_OPEN_FLAGS_SHAREABLE RT_BIT(5) +/** Ask the backend to switch to sequential accesses if possible. Opening + * will not fail if it cannot do this, the flag will be simply ignored. */ +#define VD_OPEN_FLAGS_SEQUENTIAL RT_BIT(6) +/** Allow the discard operation if supported. Only available if VD_CAP_DISCARD + * is set. VDOpen fails with VERR_VD_DISCARD_NOT_SUPPORTED if discarding is not + * supported. */ +#define VD_OPEN_FLAGS_DISCARD RT_BIT(7) +/** Ignore all flush requests to workaround certain filesystems which are slow + * when writing a lot of cached data to the medium. + * Use with extreme care as a host crash can result in completely corrupted and + * unusable images. + */ +#define VD_OPEN_FLAGS_IGNORE_FLUSH RT_BIT(8) +/** + * Return VINF_VD_NEW_ZEROED_BLOCK for reads from unallocated blocks. + * The caller who uses the flag has to make sure that the read doesn't cross + * a block boundary. Because the block size can differ between images reading one + * sector at a time is the safest solution. + */ +#define VD_OPEN_FLAGS_INFORM_ABOUT_ZERO_BLOCKS RT_BIT(9) +/** + * Don't do unnecessary consistency checks when opening the image. + * Only valid when the image is opened in readonly because inconsistencies + * can lead to corrupted images in read-write mode. + */ +#define VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS RT_BIT(10) +/** Mask of valid flags. */ +#define VD_OPEN_FLAGS_MASK (VD_OPEN_FLAGS_NORMAL | VD_OPEN_FLAGS_READONLY | VD_OPEN_FLAGS_HONOR_ZEROES | VD_OPEN_FLAGS_HONOR_SAME | VD_OPEN_FLAGS_INFO | VD_OPEN_FLAGS_ASYNC_IO | VD_OPEN_FLAGS_SHAREABLE | VD_OPEN_FLAGS_SEQUENTIAL | VD_OPEN_FLAGS_DISCARD | VD_OPEN_FLAGS_IGNORE_FLUSH | VD_OPEN_FLAGS_INFORM_ABOUT_ZERO_BLOCKS | VD_OPEN_FLAGS_SKIP_CONSISTENCY_CHECKS) +/** @}*/ + +/** @name VBox HDD container filter flags + * @{ + */ +/** The filter is applied during writes. */ +#define VD_FILTER_FLAGS_WRITE RT_BIT(0) +/** The filter is applied during reads. */ +#define VD_FILTER_FLAGS_READ RT_BIT(1) +/** Open the filter in info mode. */ +#define VD_FILTER_FLAGS_INFO RT_BIT(2) +/** Default set of filter flags. */ +#define VD_FILTER_FLAGS_DEFAULT (VD_FILTER_FLAGS_WRITE | VD_FILTER_FLAGS_READ) +/** Mask of valid flags. */ +#define VD_FILTER_FLAGS_MASK (VD_FILTER_FLAGS_WRITE | VD_FILTER_FLAGS_READ | VD_FILTER_FLAGS_INFO) +/** @} */ + +/** + * Helper functions to handle open flags. + */ + +/** + * Translate VD_OPEN_FLAGS_* to RTFile open flags. + * + * @return RTFile open flags. + * @param fOpenFlags VD_OPEN_FLAGS_* open flags. + * @param fCreate Flag that the file should be created. + */ +DECLINLINE(uint32_t) VDOpenFlagsToFileOpenFlags(unsigned fOpenFlags, bool fCreate) +{ + uint32_t fOpen; + AssertMsg(!(fOpenFlags & VD_OPEN_FLAGS_READONLY) || !fCreate, ("Image can't be opened readonly while being created\n")); + + if (fOpenFlags & VD_OPEN_FLAGS_READONLY) + fOpen = RTFILE_O_READ | RTFILE_O_DENY_NONE; + else + { + fOpen = RTFILE_O_READWRITE; + + if (fOpenFlags & VD_OPEN_FLAGS_SHAREABLE) + fOpen |= RTFILE_O_DENY_NONE; + else + fOpen |= RTFILE_O_DENY_WRITE; + } + + if (!fCreate) + fOpen |= RTFILE_O_OPEN; + else + fOpen |= RTFILE_O_CREATE | RTFILE_O_NOT_CONTENT_INDEXED; + + return fOpen; +} + + +/** @name VBox HDD container backend capability flags + * @{ + */ +/** Supports UUIDs as expected by VirtualBox code. */ +#define VD_CAP_UUID RT_BIT(0) +/** Supports creating fixed size images, allocating all space instantly. */ +#define VD_CAP_CREATE_FIXED RT_BIT(1) +/** Supports creating dynamically growing images, allocating space on demand. */ +#define VD_CAP_CREATE_DYNAMIC RT_BIT(2) +/** Supports creating images split in chunks of a bit less than 2GBytes. */ +#define VD_CAP_CREATE_SPLIT_2G RT_BIT(3) +/** Supports being used as differencing image format backend. */ +#define VD_CAP_DIFF RT_BIT(4) +/** Supports asynchronous I/O operations for at least some configurations. */ +#define VD_CAP_ASYNC RT_BIT(5) +/** The backend operates on files. The caller needs to know to handle the + * location appropriately. */ +#define VD_CAP_FILE RT_BIT(6) +/** The backend uses the config interface. The caller needs to know how to + * provide the mandatory configuration parts this way. */ +#define VD_CAP_CONFIG RT_BIT(7) +/** The backend uses the network stack interface. The caller has to provide + * the appropriate interface. */ +#define VD_CAP_TCPNET RT_BIT(8) +/** The backend supports VFS (virtual filesystem) functionality since it uses + * VDINTERFACEIO exclusively for all file operations. */ +#define VD_CAP_VFS RT_BIT(9) +/** The backend supports the discard operation. */ +#define VD_CAP_DISCARD RT_BIT(10) +/** This is a frequently used backend. */ +#define VD_CAP_PREFERRED RT_BIT(11) +/** @}*/ + +/** @name Configuration interface key handling flags. + * @{ + */ +/** Mandatory config key. Not providing a value for this key will cause + * the backend to fail. */ +#define VD_CFGKEY_MANDATORY RT_BIT(0) +/** Expert config key. Not showing it by default in the GUI is is probably + * a good idea, as the average user won't understand it easily. */ +#define VD_CFGKEY_EXPERT RT_BIT(1) +/** Key only need at media creation, not to be retained in registry. + * Should not be exposed in the GUI */ +#define VD_CFGKEY_CREATEONLY RT_BIT(2) +/** @}*/ + + +/** + * Configuration value type for configuration information interface. + */ +typedef enum VDCFGVALUETYPE +{ + /** Integer value. */ + VDCFGVALUETYPE_INTEGER = 1, + /** String value. */ + VDCFGVALUETYPE_STRING, + /** Bytestring value. */ + VDCFGVALUETYPE_BYTES +} VDCFGVALUETYPE; + + +/** + * Structure describing configuration keys required/supported by a backend + * through the config interface. + */ +typedef struct VDCONFIGINFO +{ + /** Key name of the configuration. */ + const char *pszKey; + /** Pointer to default value (descriptor). NULL if no useful default value + * can be specified. */ + const char *pszDefaultValue; + /** Value type for this key. */ + VDCFGVALUETYPE enmValueType; + /** Key handling flags (a combination of VD_CFGKEY_* flags). */ + uint64_t uKeyFlags; +} VDCONFIGINFO; + +/** Pointer to structure describing configuration keys. */ +typedef VDCONFIGINFO *PVDCONFIGINFO; + +/** Pointer to const structure describing configuration keys. */ +typedef const VDCONFIGINFO *PCVDCONFIGINFO; + +/** + * Structure describing a file extension. + */ +typedef struct VDFILEEXTENSION +{ + /** Pointer to the NULL-terminated string containing the extension. */ + const char *pszExtension; + /** The device type the extension supports. */ + VDTYPE enmType; +} VDFILEEXTENSION; + +/** Pointer to a structure describing a file extension. */ +typedef VDFILEEXTENSION *PVDFILEEXTENSION; + +/** Pointer to a const structure describing a file extension. */ +typedef const VDFILEEXTENSION *PCVDFILEEXTENSION; + +/** + * Data structure for returning a list of backend capabilities. + */ +typedef struct VDBACKENDINFO +{ + /** Name of the backend. Must be unique even with case insensitive comparison. */ + const char *pszBackend; + /** Capabilities of the backend (a combination of the VD_CAP_* flags). */ + uint64_t uBackendCaps; + /** Pointer to a NULL-terminated array of strings, containing the supported + * file extensions. Note that some backends do not work on files, so this + * pointer may just contain NULL. */ + PCVDFILEEXTENSION paFileExtensions; + /** Pointer to an array of structs describing each supported config key. + * Terminated by a NULL config key. Note that some backends do not support + * the configuration interface, so this pointer may just contain NULL. + * Mandatory if the backend sets VD_CAP_CONFIG. */ + PCVDCONFIGINFO paConfigInfo; + /** Returns a human readable hard disk location string given a + * set of hard disk configuration keys. The returned string is an + * equivalent of the full file path for image-based hard disks. + * Mandatory for backends with no VD_CAP_FILE and NULL otherwise. */ + DECLR3CALLBACKMEMBER(int, pfnComposeLocation, (PVDINTERFACE pConfig, char **pszLocation)); + /** Returns a human readable hard disk name string given a + * set of hard disk configuration keys. The returned string is an + * equivalent of the file name part in the full file path for + * image-based hard disks. Mandatory for backends with no + * VD_CAP_FILE and NULL otherwise. */ + DECLR3CALLBACKMEMBER(int, pfnComposeName, (PVDINTERFACE pConfig, char **pszName)); +} VDBACKENDINFO, *PVDBACKENDINFO; + +/** + * Data structure for returning a list of filter capabilities. + */ +typedef struct VDFILTERINFO +{ + /** Name of the filter. Must be unique even with case insensitive comparison. */ + const char *pszFilter; + /** Pointer to an array of structs describing each supported config key. + * Terminated by a NULL config key. Note that some filters do not support + * the configuration interface, so this pointer may just contain NULL. */ + PCVDCONFIGINFO paConfigInfo; +} VDFILTERINFO, *PVDFILTERINFO; + + +/** + * Request completion callback for the async read/write API. + */ +typedef DECLCALLBACKTYPE(void, FNVDASYNCTRANSFERCOMPLETE,(void *pvUser1, void *pvUser2, int rcReq)); +/** Pointer to a transfer compelte callback. */ +typedef FNVDASYNCTRANSFERCOMPLETE *PFNVDASYNCTRANSFERCOMPLETE; + +/** + * VD Container main structure. + */ +/* Forward declaration, VDISK structure is visible only inside VD module. */ +struct VDISK; +typedef struct VDISK VDISK; +typedef VDISK *PVDISK; + +/** + * Initializes HDD backends. + * + * @returns VBox status code. + */ +VBOXDDU_DECL(int) VDInit(void); + +/** + * Destroys loaded HDD backends. + * + * @returns VBox status code. + */ +VBOXDDU_DECL(int) VDShutdown(void); + +/** + * Loads a single plugin given by filename. + * + * @returns VBox status code. + * @param pszFilename The plugin filename to load. + */ +VBOXDDU_DECL(int) VDPluginLoadFromFilename(const char *pszFilename); + +/** + * Load all plugins from a given path. + * + * @returns VBox statuse code. + * @param pszPath The path to load plugins from. + */ +VBOXDDU_DECL(int) VDPluginLoadFromPath(const char *pszPath); + +/** + * Unloads a single plugin given by filename. + * + * @returns VBox status code. + * @param pszFilename The plugin filename to unload. + */ +VBOXDDU_DECL(int) VDPluginUnloadFromFilename(const char *pszFilename); + +/** + * Unload all plugins from a given path. + * + * @returns VBox statuse code. + * @param pszPath The path to unload plugins from. + */ +VBOXDDU_DECL(int) VDPluginUnloadFromPath(const char *pszPath); + +/** + * Lists all HDD backends and their capabilities in a caller-provided buffer. + * + * @return VBox status code. + * VERR_BUFFER_OVERFLOW if not enough space is passed. + * @param cEntriesAlloc Number of list entries available. + * @param pEntries Pointer to array for the entries. + * @param pcEntriesUsed Number of entries returned. + */ +VBOXDDU_DECL(int) VDBackendInfo(unsigned cEntriesAlloc, PVDBACKENDINFO pEntries, + unsigned *pcEntriesUsed); + +/** + * Lists the capabilities of a backend identified by its name. + * + * @return VBox status code. + * @param pszBackend The backend name (case insensitive). + * @param pEntry Pointer to an entry. + */ +VBOXDDU_DECL(int) VDBackendInfoOne(const char *pszBackend, PVDBACKENDINFO pEntry); + +/** + * Lists all filters and their capabilities in a caller-provided buffer. + * + * @return VBox status code. + * VERR_BUFFER_OVERFLOW if not enough space is passed. + * @param cEntriesAlloc Number of list entries available. + * @param pEntries Pointer to array for the entries. + * @param pcEntriesUsed Number of entries returned. + */ +VBOXDDU_DECL(int) VDFilterInfo(unsigned cEntriesAlloc, PVDFILTERINFO pEntries, + unsigned *pcEntriesUsed); + +/** + * Lists the capabilities of a filter identified by its name. + * + * @return VBox status code. + * @param pszFilter The filter name (case insensitive). + * @param pEntry Pointer to an entry. + */ +VBOXDDU_DECL(int) VDFilterInfoOne(const char *pszFilter, PVDFILTERINFO pEntry); + +/** + * Allocates and initializes an empty HDD container. + * No image files are opened. + * + * @return VBox status code. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param enmType Type of the image container. + * @param ppDisk Where to store the reference to HDD container. + */ +VBOXDDU_DECL(int) VDCreate(PVDINTERFACE pVDIfsDisk, VDTYPE enmType, PVDISK *ppDisk); + +/** + * Destroys HDD container. + * If container has opened image files they will be closed. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(int) VDDestroy(PVDISK pDisk); + +/** + * Try to get the backend name which can use this image. + * + * @return VBox status code. + * VINF_SUCCESS if a plugin was found. + * ppszFormat contains the string which can be used as backend name. + * VERR_NOT_SUPPORTED if no backend was found. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pszFilename Name of the image file for which the backend is queried. + * @param enmDesiredType The desired image type, VDTYPE_INVALID if anything goes. + * @param ppszFormat Receives pointer of the UTF-8 string which contains the format name. + * The returned pointer must be freed using RTStrFree(). + * @param penmType Where to store the type of the image. + */ +VBOXDDU_DECL(int) VDGetFormat(PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage, + const char *pszFilename, VDTYPE enmDesiredType, + char **ppszFormat, VDTYPE *penmType); + +/** + * Opens an image file. + * + * The first opened image file in HDD container must have a base image type, + * others (next opened images) must be differencing or undo images. + * Linkage is checked for differencing image to be consistent with the previously opened image. + * When another differencing image is opened and the last image was opened in read/write access + * mode, then the last image is reopened in read-only with deny write sharing mode. This allows + * other processes to use images in read-only mode too. + * + * Note that the image is opened in read-only mode if a read/write open is not possible. + * Use VDIsReadOnly to check open mode. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param pszBackend Name of the image file backend to use (case insensitive). + * @param pszFilename Name of the image file to open. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsImage Pointer to the per-image VD interface list. + */ +VBOXDDU_DECL(int) VDOpen(PVDISK pDisk, const char *pszBackend, + const char *pszFilename, unsigned uOpenFlags, + PVDINTERFACE pVDIfsImage); + +/** + * Opens a cache image. + * + * @return VBox status code. + * @param pDisk Pointer to the HDD container which should use the cache image. + * @param pszBackend Name of the cache file backend to use (case insensitive). + * @param pszFilename Name of the cache image to open. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsCache Pointer to the per-cache VD interface list. + */ +VBOXDDU_DECL(int) VDCacheOpen(PVDISK pDisk, const char *pszBackend, + const char *pszFilename, unsigned uOpenFlags, + PVDINTERFACE pVDIfsCache); + +/** + * Adds a filter to the disk. + * + * @returns VBox status code. + * @param pDisk Pointer to the HDD container which should use the filter. + * @param pszFilter Name of the filter backend to use (case insensitive). + * @param fFlags Flags which apply to the filter, combination of VD_FILTER_FLAGS_* + * defines. + * @param pVDIfsFilter Pointer to the per-filter VD interface list. + */ +VBOXDDU_DECL(int) VDFilterAdd(PVDISK pDisk, const char *pszFilter, uint32_t fFlags, + PVDINTERFACE pVDIfsFilter); + +/** + * Creates and opens a new base image file. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param pszBackend Name of the image file backend to use (case insensitive). + * @param pszFilename Name of the image file to create. + * @param cbSize Image size in bytes. + * @param uImageFlags Flags specifying special image features. + * @param pszComment Pointer to image comment. NULL is ok. + * @param pPCHSGeometry Pointer to physical disk geometry <= (16383,16,63). Not NULL. + * @param pLCHSGeometry Pointer to logical disk geometry <= (x,255,63). Not NULL. + * @param pUuid New UUID of the image. If NULL, a new UUID is created. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDCreateBase(PVDISK pDisk, const char *pszBackend, + const char *pszFilename, uint64_t cbSize, + unsigned uImageFlags, const char *pszComment, + PCVDGEOMETRY pPCHSGeometry, + PCVDGEOMETRY pLCHSGeometry, + PCRTUUID pUuid, unsigned uOpenFlags, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation); + +/** + * Creates and opens a new differencing image file in HDD container. + * See comments for VDOpen function about differencing images. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param pszBackend Name of the image file backend to use (case insensitive). + * @param pszFilename Name of the differencing image file to create. + * @param uImageFlags Flags specifying special image features. + * @param pszComment Pointer to image comment. NULL is ok. + * @param pUuid New UUID of the image. If NULL, a new UUID is created. + * @param pParentUuid New parent UUID of the image. If NULL, the UUID is queried automatically. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDCreateDiff(PVDISK pDisk, const char *pszBackend, + const char *pszFilename, unsigned uImageFlags, + const char *pszComment, PCRTUUID pUuid, + PCRTUUID pParentUuid, unsigned uOpenFlags, + PVDINTERFACE pVDIfsImage, + PVDINTERFACE pVDIfsOperation); + +/** + * Creates and opens new cache image file in HDD container. + * + * @return VBox status code. + * @param pDisk Name of the cache file backend to use (case insensitive). + * @param pszBackend Name of the image file backend to use (case insensitive). + * @param pszFilename Name of the differencing cache file to create. + * @param cbSize Maximum size of the cache. + * @param uImageFlags Flags specifying special cache features. + * @param pszComment Pointer to image comment. NULL is ok. + * @param pUuid New UUID of the image. If NULL, a new UUID is created. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * @param pVDIfsCache Pointer to the per-cache VD interface list. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDCreateCache(PVDISK pDisk, const char *pszBackend, + const char *pszFilename, uint64_t cbSize, + unsigned uImageFlags, const char *pszComment, + PCRTUUID pUuid, unsigned uOpenFlags, + PVDINTERFACE pVDIfsCache, PVDINTERFACE pVDIfsOperation); + +/** + * Merges two images (not necessarily with direct parent/child relationship). + * As a side effect the source image and potentially the other images which + * are also merged to the destination are deleted from both the disk and the + * images in the HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImageFrom Image number to merge from, counts from 0. 0 is always base image of container. + * @param nImageTo Image number to merge to, counts from 0. 0 is always base image of container. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDMerge(PVDISK pDisk, unsigned nImageFrom, + unsigned nImageTo, PVDINTERFACE pVDIfsOperation); + +/** + * Copies an image from one HDD container to another - extended version. + * + * The copy is opened in the target HDD container. It is possible to convert + * between different image formats, because the backend for the destination may + * be different from the source. If both the source and destination reference + * the same HDD container, then the image is moved (by copying/deleting or + * renaming) to the new location. The source container is unchanged if the move + * operation fails, otherwise the image at the new location is opened in the + * same way as the old one was. + * + * @note The read/write accesses across disks are not synchronized, just the + * accesses to each disk. Once there is a use case which requires a defined + * read/write behavior in this situation this needs to be extended. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * + * @param pDiskFrom Pointer to source HDD container. + * @param nImage Image number, counts from 0. 0 is always base image + * of container. + * @param pDiskTo Pointer to destination HDD container. + * @param pszBackend Name of the image file backend to use (may be NULL + * to use the same as the source, case insensitive). + * @param pszFilename New name of the image (may be NULL to specify that + * the copy destination is the destination container, + * or if pDiskFrom == pDiskTo, i.e. when moving). + * @param fMoveByRename If true, attempt to perform a move by renaming (if + * successful the new size is ignored). + * @param cbSize New image size (0 means leave unchanged). + * @param nImageFromSame The number of the last image in the source chain + * having the same content as the image in the + * destination chain given by nImageToSame or + * VD_IMAGE_CONTENT_UNKNOWN to indicate that the + * content of both containers is unknown. See the + * notes for further information. + * @param nImageToSame The number of the last image in the destination + * chain having the same content as the image in the + * source chain given by nImageFromSame or + * VD_IMAGE_CONTENT_UNKNOWN to indicate that the + * content of both containers is unknown. See the notes + * for further information. + * @param uImageFlags Flags specifying special destination image features. + * @param pDstUuid New UUID of the destination image. If NULL, a new + * UUID is created. This parameter is used if and only + * if a true copy is created. In all rename/move cases + * or copy to existing image cases the modification + * UUIDs are copied over. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * Only used if the destination image is created. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + * @param pDstVDIfsImage Pointer to the per-image VD interface list, for the + * destination image. + * @param pDstVDIfsOperation Pointer to the per-operation VD interface list, + * for the destination operation. + * + * @note Using nImageFromSame and nImageToSame can lead to a significant speedup + * when copying an image but can also lead to a corrupted copy if used + * incorrectly. It is mainly useful when cloning a chain of images and it + * is known that the virtual disk content of the two chains is exactly the + * same upto a certain image. Example: + * Imagine the chain of images which consist of a base and one diff + * image. Copying the chain starts with the base image. When copying + * the first diff image VDCopy() will read the data from the diff of + * the source chain and probably from the base image again in case the + * diff doesn't has data for the block. However the block will be + * optimized away because VDCopy() reads data from the base image of + * the destination chain compares the to and suppresses the write + * because the data is unchanged. For a lot of diff images this will be + * a huge waste of I/O bandwidth if the diff images contain only few + * changes. Because it is known that the base image of the source and + * the destination chain have the same content it is enough to check + * the diff image for changed data and copy it to the destination diff + * image which is achieved with nImageFromSame and nImageToSame. + * Setting both to 0 can suppress a lot of I/O. + */ +VBOXDDU_DECL(int) VDCopyEx(PVDISK pDiskFrom, unsigned nImage, PVDISK pDiskTo, + const char *pszBackend, const char *pszFilename, + bool fMoveByRename, uint64_t cbSize, + unsigned nImageFromSame, unsigned nImageToSame, + unsigned uImageFlags, PCRTUUID pDstUuid, + unsigned uOpenFlags, PVDINTERFACE pVDIfsOperation, + PVDINTERFACE pDstVDIfsImage, + PVDINTERFACE pDstVDIfsOperation); + +/** + * Copies an image from one HDD container to another. + * The copy is opened in the target HDD container. + * It is possible to convert between different image formats, because the + * backend for the destination may be different from the source. + * If both the source and destination reference the same HDD container, + * then the image is moved (by copying/deleting or renaming) to the new location. + * The source container is unchanged if the move operation fails, otherwise + * the image at the new location is opened in the same way as the old one was. + * + * @note The read/write accesses across disks are not synchronized, just the + * accesses to each disk. Once there is a use case which requires a defined + * read/write behavior in this situation this needs to be extended. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDiskFrom Pointer to source HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pDiskTo Pointer to destination HDD container. + * @param pszBackend Name of the image file backend to use (may be NULL to use the same as the source, case insensitive). + * @param pszFilename New name of the image (may be NULL to specify that the + * copy destination is the destination container, or + * if pDiskFrom == pDiskTo, i.e. when moving). + * @param fMoveByRename If true, attempt to perform a move by renaming (if successful the new size is ignored). + * @param cbSize New image size (0 means leave unchanged). + * @param uImageFlags Flags specifying special destination image features. + * @param pDstUuid New UUID of the destination image. If NULL, a new UUID is created. + * This parameter is used if and only if a true copy is created. + * In all rename/move cases or copy to existing image cases the modification UUIDs are copied over. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + * Only used if the destination image is created. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + * @param pDstVDIfsImage Pointer to the per-image VD interface list, for the + * destination image. + * @param pDstVDIfsOperation Pointer to the per-operation VD interface list, + * for the destination operation. + */ +VBOXDDU_DECL(int) VDCopy(PVDISK pDiskFrom, unsigned nImage, PVDISK pDiskTo, + const char *pszBackend, const char *pszFilename, + bool fMoveByRename, uint64_t cbSize, + unsigned uImageFlags, PCRTUUID pDstUuid, + unsigned uOpenFlags, PVDINTERFACE pVDIfsOperation, + PVDINTERFACE pDstVDIfsImage, + PVDINTERFACE pDstVDIfsOperation); + +/** + * Optimizes the storage consumption of an image. Typically the unused blocks + * have to be wiped with zeroes to achieve a substantial reduced storage use. + * Another optimization done is reordering the image blocks, which can provide + * a significant performance boost, as reads and writes tend to use less random + * file offsets. + * + * @note Compaction is treated as a single operation with regard to thread + * synchronization, which means that it potentially blocks other activities for + * a long time. The complexity of compaction would grow even more if concurrent + * accesses have to be handled. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @return VERR_VD_IMAGE_READ_ONLY if image is not writable. + * @return VERR_NOT_SUPPORTED if this kind of image can be compacted, but + * this isn't supported yet. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDCompact(PVDISK pDisk, unsigned nImage, PVDINTERFACE pVDIfsOperation); + +/** + * Resizes the given disk image to the given size. It is OK if there are + * multiple images open in the container. In this case the last disk image + * will be resized. + * + * @return VBox status + * @return VERR_VD_IMAGE_READ_ONLY if image is not writable. + * @return VERR_NOT_SUPPORTED if this kind of image can't be compacted. + * + * @param pDisk Pointer to the HDD container. + * @param cbSize New size of the image. + * @param pPCHSGeometry Pointer to the new physical disk geometry <= (16383,16,63). Not NULL. + * @param pLCHSGeometry Pointer to the new logical disk geometry <= (x,255,63). Not NULL. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDResize(PVDISK pDisk, uint64_t cbSize, + PCVDGEOMETRY pPCHSGeometry, + PCVDGEOMETRY pLCHSGeometry, + PVDINTERFACE pVDIfsOperation); + +/** + * Prepares the given disk for use by the added filters. This applies to all + * opened images in the chain which might be opened read/write temporary. + * + * @return VBox status code. + * + * @param pDisk Pointer to the HDD container. + * @param pVDIfsOperation Pointer to the per-operation VD interface list. + */ +VBOXDDU_DECL(int) VDPrepareWithFilters(PVDISK pDisk, PVDINTERFACE pVDIfsOperation); + +/** + * Closes the last opened image file in HDD container. + * If previous image file was opened in read-only mode (the normal case) and + * the last opened image is in read-write mode then the previous image will be + * reopened in read/write mode. + * + * @return VBox status code. + * @return VERR_VD_NOT_OPENED if no image is opened in HDD container. + * @param pDisk Pointer to HDD container. + * @param fDelete If true, delete the image from the host disk. + */ +VBOXDDU_DECL(int) VDClose(PVDISK pDisk, bool fDelete); + +/** + * Removes the last added filter in the HDD container from the specified chain. + * + * @return VBox status code. + * @retval VERR_VD_NOT_OPENED if no filter is present for the disk. + * @param pDisk Pointer to HDD container. + * @param fFlags Combination of VD_FILTER_FLAGS_* defines. + */ +VBOXDDU_DECL(int) VDFilterRemove(PVDISK pDisk, uint32_t fFlags); + +/** + * Closes the currently opened cache image file in HDD container. + * + * @return VBox status code. + * @return VERR_VD_NOT_OPENED if no cache is opened in HDD container. + * @param pDisk Pointer to HDD container. + * @param fDelete If true, delete the image from the host disk. + */ +VBOXDDU_DECL(int) VDCacheClose(PVDISK pDisk, bool fDelete); + +/** + * Closes all opened image files in HDD container. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(int) VDCloseAll(PVDISK pDisk); + +/** + * Removes all filters of the given HDD container. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(int) VDFilterRemoveAll(PVDISK pDisk); + +/** + * Read data from virtual HDD. + * + * @return VBox status code. + * @retval VERR_VD_NOT_OPENED if no image is opened in HDD container. + * @param pDisk Pointer to HDD container. + * @param uOffset Offset of first reading byte from start of disk. + * Must be aligned to a sector boundary. + * @param pvBuf Pointer to buffer for reading data. + * @param cbRead Number of bytes to read. + * Must be aligned to a sector boundary. + */ +VBOXDDU_DECL(int) VDRead(PVDISK pDisk, uint64_t uOffset, void *pvBuf, size_t cbRead); + +/** + * Write data to virtual HDD. + * + * @return VBox status code. + * @retval VERR_VD_NOT_OPENED if no image is opened in HDD container. + * @param pDisk Pointer to HDD container. + * @param uOffset Offset of first writing byte from start of disk. + * Must be aligned to a sector boundary. + * @param pvBuf Pointer to buffer for writing data. + * @param cbWrite Number of bytes to write. + * Must be aligned to a sector boundary. + */ +VBOXDDU_DECL(int) VDWrite(PVDISK pDisk, uint64_t uOffset, const void *pvBuf, size_t cbWrite); + +/** + * Make sure the on disk representation of a virtual HDD is up to date. + * + * @return VBox status code. + * @retval VERR_VD_NOT_OPENED if no image is opened in HDD container. + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(int) VDFlush(PVDISK pDisk); + +/** + * Get number of opened images in HDD container. + * + * @return Number of opened images for HDD container. 0 if no images have been opened. + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(unsigned) VDGetCount(PVDISK pDisk); + +/** + * Get read/write mode of HDD container. + * + * @return Virtual disk ReadOnly status. + * @return true if no image is opened in HDD container. + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(bool) VDIsReadOnly(PVDISK pDisk); + +/** + * Get sector size of an image in HDD container. + * + * @return Virtual disk sector size in bytes. + * @return 0 if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + */ +VBOXDDU_DECL(uint32_t) VDGetSectorSize(PVDISK pDisk, unsigned nImage); + +/** + * Get total capacity of an image in HDD container. + * + * @return Virtual disk size in bytes. + * @return 0 if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + */ +VBOXDDU_DECL(uint64_t) VDGetSize(PVDISK pDisk, unsigned nImage); + +/** + * Get total file size of an image in HDD container. + * + * @return Virtual disk size in bytes. + * @return 0 if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + */ +VBOXDDU_DECL(uint64_t) VDGetFileSize(PVDISK pDisk, unsigned nImage); + +/** + * Get virtual disk PCHS geometry of an image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @return VERR_VD_GEOMETRY_NOT_SET if no geometry present in the HDD container. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pPCHSGeometry Where to store PCHS geometry. Not NULL. + */ +VBOXDDU_DECL(int) VDGetPCHSGeometry(PVDISK pDisk, unsigned nImage, PVDGEOMETRY pPCHSGeometry); + +/** + * Store virtual disk PCHS geometry of an image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pPCHSGeometry Where to load PCHS geometry from. Not NULL. + */ +VBOXDDU_DECL(int) VDSetPCHSGeometry(PVDISK pDisk, unsigned nImage, PCVDGEOMETRY pPCHSGeometry); + +/** + * Get virtual disk LCHS geometry of an image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @return VERR_VD_GEOMETRY_NOT_SET if no geometry present in the HDD container. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pLCHSGeometry Where to store LCHS geometry. Not NULL. + */ +VBOXDDU_DECL(int) VDGetLCHSGeometry(PVDISK pDisk, unsigned nImage, PVDGEOMETRY pLCHSGeometry); + +/** + * Store virtual disk LCHS geometry of an image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pLCHSGeometry Where to load LCHS geometry from. Not NULL. + */ +VBOXDDU_DECL(int) VDSetLCHSGeometry(PVDISK pDisk, unsigned nImage, PCVDGEOMETRY pLCHSGeometry); + +/** + * Queries the available regions of an image in the given VD container. + * + * @return VBox status code. + * @retval VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @retval VERR_NOT_SUPPORTED if the image backend doesn't support region lists. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param fFlags Combination of VD_REGION_LIST_F_* flags. + * @param ppRegionList Where to store the pointer to the region list on success, must be freed + * with VDRegionListFree(). + */ +VBOXDDU_DECL(int) VDQueryRegions(PVDISK pDisk, unsigned nImage, uint32_t fFlags, + PPVDREGIONLIST ppRegionList); + +/** + * Frees a region list previously queried with VDQueryRegions(). + * + * @return nothing. + * @param pRegionList The region list to free. + */ +VBOXDDU_DECL(void) VDRegionListFree(PVDREGIONLIST pRegionList); + +/** + * Get version of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param puVersion Where to store the image version. + */ +VBOXDDU_DECL(int) VDGetVersion(PVDISK pDisk, unsigned nImage, unsigned *puVersion); + +/** + * List the capabilities of image backend in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to the HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pBackendInfo Where to store the backend information. + */ +VBOXDDU_DECL(int) VDBackendInfoSingle(PVDISK pDisk, unsigned nImage, PVDBACKENDINFO pBackendInfo); + +/** + * Get flags of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param puImageFlags Where to store the image flags. + */ +VBOXDDU_DECL(int) VDGetImageFlags(PVDISK pDisk, unsigned nImage, unsigned *puImageFlags); + +/** + * Get open flags of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param puOpenFlags Where to store the image open flags. + */ +VBOXDDU_DECL(int) VDGetOpenFlags(PVDISK pDisk, unsigned nImage, unsigned *puOpenFlags); + +/** + * Set open flags of image in HDD container. + * This operation may cause file locking changes and/or files being reopened. + * Note that in case of unrecoverable error all images in HDD container will be closed. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param uOpenFlags Image file open mode, see VD_OPEN_FLAGS_* constants. + */ +VBOXDDU_DECL(int) VDSetOpenFlags(PVDISK pDisk, unsigned nImage, unsigned uOpenFlags); + +/** + * Get base filename of image in HDD container. Some image formats use + * other filenames as well, so don't use this for anything but informational + * purposes. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @return VERR_BUFFER_OVERFLOW if pszFilename buffer too small to hold filename. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pszFilename Where to store the image file name. + * @param cbFilename Size of buffer pszFilename points to. + */ +VBOXDDU_DECL(int) VDGetFilename(PVDISK pDisk, unsigned nImage, char *pszFilename, unsigned cbFilename); + +/** + * Get the comment line of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @return VERR_BUFFER_OVERFLOW if pszComment buffer too small to hold comment text. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pszComment Where to store the comment string of image. NULL is ok. + * @param cbComment The size of pszComment buffer. 0 is ok. + */ +VBOXDDU_DECL(int) VDGetComment(PVDISK pDisk, unsigned nImage, char *pszComment, unsigned cbComment); + +/** + * Changes the comment line of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pszComment New comment string (UTF-8). NULL is allowed to reset the comment. + */ +VBOXDDU_DECL(int) VDSetComment(PVDISK pDisk, unsigned nImage, const char *pszComment); + +/** + * Get UUID of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pUuid Where to store the image UUID. + */ +VBOXDDU_DECL(int) VDGetUuid(PVDISK pDisk, unsigned nImage, PRTUUID pUuid); + +/** + * Set the image's UUID. Should not be used by normal applications. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pUuid New UUID of the image. If NULL, a new UUID is created. + */ +VBOXDDU_DECL(int) VDSetUuid(PVDISK pDisk, unsigned nImage, PCRTUUID pUuid); + +/** + * Get last modification UUID of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pUuid Where to store the image modification UUID. + */ +VBOXDDU_DECL(int) VDGetModificationUuid(PVDISK pDisk, unsigned nImage, PRTUUID pUuid); + +/** + * Set the image's last modification UUID. Should not be used by normal applications. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pUuid New modification UUID of the image. If NULL, a new UUID is created. + */ +VBOXDDU_DECL(int) VDSetModificationUuid(PVDISK pDisk, unsigned nImage, PCRTUUID pUuid); + +/** + * Get parent UUID of image in HDD container. + * + * @return VBox status code. + * @return VERR_VD_IMAGE_NOT_FOUND if image with specified number was not opened. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of the container. + * @param pUuid Where to store the parent image UUID. + */ +VBOXDDU_DECL(int) VDGetParentUuid(PVDISK pDisk, unsigned nImage, PRTUUID pUuid); + +/** + * Set the image's parent UUID. Should not be used by normal applications. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param nImage Image number, counts from 0. 0 is always base image of container. + * @param pUuid New parent UUID of the image. If NULL, a new UUID is created. + */ +VBOXDDU_DECL(int) VDSetParentUuid(PVDISK pDisk, unsigned nImage, PCRTUUID pUuid); + + +/** + * Debug helper - dumps all opened images in HDD container into the log file. + * + * @param pDisk Pointer to HDD container. + */ +VBOXDDU_DECL(void) VDDumpImages(PVDISK pDisk); + + +/** + * Discards unused ranges given as a list. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param paRanges The array of ranges to discard. + * @param cRanges Number of entries in the array. + * + * @note In contrast to VDCompact() the ranges are always discarded even if they + * appear to contain data. This method is mainly used to implement TRIM support. + */ +VBOXDDU_DECL(int) VDDiscardRanges(PVDISK pDisk, PCRTRANGE paRanges, unsigned cRanges); + + +/** + * Start an asynchronous read request. + * + * @return VBox status code. + * @param pDisk Pointer to the HDD container. + * @param off The offset of the virtual disk to read from. + * @param cbRead How many bytes to read. + * @param pSgBuf Pointer to the S/G buffer to read into. + * @param pfnComplete Completion callback. + * @param pvUser1 User data which is passed on completion. + * @param pvUser2 User data which is passed on completion. + */ +VBOXDDU_DECL(int) VDAsyncRead(PVDISK pDisk, uint64_t off, size_t cbRead, + PCRTSGBUF pSgBuf, + PFNVDASYNCTRANSFERCOMPLETE pfnComplete, + void *pvUser1, void *pvUser2); + + +/** + * Start an asynchronous write request. + * + * @return VBox status code. + * @param pDisk Pointer to the HDD container. + * @param off The offset of the virtual disk to write to. + * @param cbWrite How many bytes to write. + * @param pSgBuf Pointer to the S/G buffer to write from. + * @param pfnComplete Completion callback. + * @param pvUser1 User data which is passed on completion. + * @param pvUser2 User data which is passed on completion. + */ +VBOXDDU_DECL(int) VDAsyncWrite(PVDISK pDisk, uint64_t off, size_t cbWrite, + PCRTSGBUF pSgBuf, + PFNVDASYNCTRANSFERCOMPLETE pfnComplete, + void *pvUser1, void *pvUser2); + + +/** + * Start an asynchronous flush request. + * + * @return VBox status code. + * @param pDisk Pointer to the HDD container. + * @param pfnComplete Completion callback. + * @param pvUser1 User data which is passed on completion. + * @param pvUser2 User data which is passed on completion. + */ +VBOXDDU_DECL(int) VDAsyncFlush(PVDISK pDisk, + PFNVDASYNCTRANSFERCOMPLETE pfnComplete, + void *pvUser1, void *pvUser2); + +/** + * Start an asynchronous discard request. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param paRanges The array of ranges to discard. + * @param cRanges Number of entries in the array. + * @param pfnComplete Completion callback. + * @param pvUser1 User data which is passed on completion. + * @param pvUser2 User data which is passed on completion. + */ +VBOXDDU_DECL(int) VDAsyncDiscardRanges(PVDISK pDisk, PCRTRANGE paRanges, unsigned cRanges, + PFNVDASYNCTRANSFERCOMPLETE pfnComplete, + void *pvUser1, void *pvUser2); + +/** + * Tries to repair a corrupted image. + * + * @return VBox status code. + * @retval VERR_VD_IMAGE_REPAIR_NOT_SUPPORTED if the backend does not support repairing the image. + * @retval VERR_VD_IMAGE_REPAIR_IMPOSSIBLE if the corruption is to severe to repair the image. + * @param pVDIfsDisk Pointer to the per-disk VD interface list. + * @param pVDIfsImage Pointer to the per-image VD interface list. + * @param pszFilename Name of the image file to repair. + * @param pszBackend The backend to use. + * @param fFlags Combination of the VD_REPAIR_* flags. + */ +VBOXDDU_DECL(int) VDRepair(PVDINTERFACE pVDIfsDisk, PVDINTERFACE pVDIfsImage, + const char *pszFilename, const char *pszBackend, uint32_t fFlags); + +/** + * Create a VFS file handle from the given HDD container. + * + * @return VBox status code. + * @param pDisk Pointer to HDD container. + * @param fFlags Combination of the VD_VFSFILE_* flags. + * @param phVfsFile Where to store the handle to the VFS file on + * success. + */ +VBOXDDU_DECL(int) VDCreateVfsFileFromDisk(PVDISK pDisk, uint32_t fFlags, + PRTVFSFILE phVfsFile); + + + +/** @defgroup grp_vd_ifs_def Default implementations for certain VD interfaces. + * @{ + */ +/** Internal per interface instance data. */ +typedef struct VDIFINSTINT *VDIFINST; +/** Pointer to the per instance interface data. */ +typedef VDIFINST *PVDIFINST; + +/** + * Creates a new VD TCP/IP interface instance and adds it to the given interface list. + * + * @returns VBox status code. + * @param phTcpNetInst Where to store the TCP/IP interface handle on success. + * @param ppVdIfs Pointer to the VD interface list. + */ +VBOXDDU_DECL(int) VDIfTcpNetInstDefaultCreate(PVDIFINST phTcpNetInst, PVDINTERFACE *ppVdIfs); + +/** + * Destroys the given VD TCP/IP interface instance. + * + * @returns nothing. + * @param hTcpNetInst The TCP/IP interface instance handle. + */ +VBOXDDU_DECL(void) VDIfTcpNetInstDefaultDestroy(VDIFINST hTcpNetInst); +/** @} */ + + + +/** @defgroup grp_vd_ioiter I/O iterator + * @{ + */ + +/** Read metadata coming before each main data block addressed in the segment. */ +#define VD_IOITER_SEG_F_PRE_METADATA RT_BIT_32(0) +/** Read the main user data of each addressed block in the segment. */ +#define VD_IOITER_SEG_F_MAIN_DATA RT_BIT_32(1) +/** Read metadata coming after each main data block addressed in the segment. */ +#define VD_IOITER_SEG_F_POST_METADATA RT_BIT_32(2) +/** Read checksum data of each data block addressed in the segment. */ +#define VD_IOITER_SEG_F_CHKSUM RT_BIT_32(3) +/** Read all available data for each addressed block in the segment. */ +#define VD_IOITER_SEG_F_AVAILABLE RT_BIT_32(4) + +/** The offset and size members in the segments use byte granularity instead of a + * block address and number of blocks respectively. */ +#define VDIOITER_F_BYTE_OFFSET_AND_SIZE RT_BIT_32(0) + +/** + * VD I/O iterator segment. + */ +typedef struct VDIOITERSEG +{ + /** Start offset for this segment. */ + uint64_t offStartSeg; + /** Size of the segment (bytes or blocks). */ + uint64_t cSizeSeg; + /** Flags for this segment, see VD_IOITER_SEG_F_*. */ + uint32_t fFlags; +} VDIOITERSEG; +/** Pointer to a I/O iterator segment. */ +typedef VDIOITERSEG *PVDIOITERSEG; +/** Pointer to a constant I/O iterator segment. */ +typedef VDIOITERSEG *PCVDIOITERSEG; + +/** I/O iterator handle. */ +typedef struct VDIOITERINT *VDIOITER; +/** Pointer to a I/O iterator handle. */ +typedef VDIOITER *PVDIOITER; + +/** + * Create a new I/O iterator. + * + * @returns VBox status code. + * @param pDisk The disk to create the iterator for. + * @param phVdIoIter Where to store the handle to the I/O iterator on success. + * @param paIoIterSegs The segments for the iterator, can be destroyed after the call. + * @param cIoIterSegs Number of segments. + * @param fFlags Flags for the iterator, see VDIOITER_F_* + */ +VBOXDDU_DECL(int) VDIoIterCreate(PVDISK pDisk, PVDIOITER phVdIoIter, PCVDIOITERSEG paIoIterSegs, + uint32_t cIoIterSegs, uint32_t fFlags); + +/** + * Retains the reference count of the given I/O iterator. + * + * @returns New reference count. + * @param hVdIoIter The I/O iterator handle. + */ +VBOXDDU_DECL(uint32_t) VDIoIterRetain(VDIOITER hVdIoIter); + +/** + * Releases the reference count of the given I/O iterator. + * + * @returns New reference count, on 0 the iterator is destroyed. + * @param hVdIoIter The I/O iterator handle. + */ +VBOXDDU_DECL(uint32_t) VDIoIterRelease(VDIOITER hVdIoIter); + +/** + * Returns the number of segments in the given I/O iterator. + * + * @returns Number of segments. + * @param hVdIoIter The I/O iterator handle. + */ +VBOXDDU_DECL(uint32_t) VDIoIterGetSegmentCount(VDIOITER hVdIoIter); + +/** + * Returns the flags of the given I/O iterator. + * + * @returns Flags. + * @param hVdIoIter The I/O iterator handle. + */ +VBOXDDU_DECL(uint32_t) VDIoIterGetFlags(VDIOITER hVdIoIter); + +/** + * Queries the properties of the given segment for the given I/O iterator. + * + * @returns VBox status code. + * @param hVdIoIter The I/O iterator handle. + * @param idx The segment index to query. + * @param pSegment Where to store the segment properties on success. + */ +VBOXDDU_DECL(int) VDIoIterQuerySegment(VDIOITER hVdIoIter, uint32_t idx, PVDIOITERSEG pSegment); + +/** @} */ + + +/** @defgroup grp_vd_io_buf I/O buffer management API. + * @{ + */ + +/** VD I/O buffer manager handle. */ +typedef struct VDIOBUFMGRINT *VDIOBUFMGR; +/** Pointer to VD I/O buffer manager handle. */ +typedef VDIOBUFMGR *PVDIOBUFMGR; + +/** VD I/O buffer handle. */ +typedef struct VDIOBUFINT *VDIOBUF; +/** Pointer to a VD I/O buffer handle. */ +typedef VDIOBUF *PVDIOBUF; + +/** Default I/O buffer manager flags. */ +#define VD_IOBUFMGR_F_DEFAULT (0) +/** I/O buffer memory needs to be non pageable (for example because it contains sensitive data + * which shouldn't end up in swap unencrypted). */ +#define VD_IOBUFMGR_F_REQUIRE_NOT_PAGABLE RT_BIT(0) + +/** Pointer to VD I/O buffer callbacks. */ +typedef struct VDIOBUFCALLBACKS *PVDIOBUFCALLBACKS; +/** Pointer to const VD I/O buffer callbacks. */ +typedef const struct VDIOBUFCALLBACKS *PCVDIOBUFCALLBACKS; + +/** + * VD I/O buffer callbacks. + */ +typedef struct VDIOBUFCALLBACKS +{ + /** + * Copy data from the memory buffer of the caller to the callees memory buffer for the given request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOBUF_OVERFLOW if there is not enough room to store the data. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoBuf The I/O request handle. + * @param pvIoBufAlloc The allocator specific memory for this request. + * @param offDst The destination offset from the start to write the data to. + * @param pSgBuf The S/G buffer to read the data from. + * @param cbCopy How many bytes to copy. + */ + DECLR3CALLBACKMEMBER(int, pfnIoBufCopyFromBuf, (PVDIOBUFCALLBACKS pInterface, VDIOBUF hIoBuf, + void *pvIoBufAlloc, uint32_t offDst, PRTSGBUF pSgBuf, + size_t cbCopy)); + + /** + * Copy data to the memory buffer of the caller from the callees memory buffer for the given request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOBUF_UNDERRUN if there is not enough data to copy from the buffer. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoBuf The I/O request handle. + * @param pvIoBufAlloc The allocator specific memory for this request. + * @param offSrc The offset from the start of the buffer to read the data from. + * @param pSgBuf The S/G buffer to write the data to. + * @param cbCopy How many bytes to copy. + */ + DECLR3CALLBACKMEMBER(int, pfnIoBufCopyToBuf, (PVDIOBUFCALLBACKS pInterface, VDIOBUF hIoBuf, + void *pvIoBufAlloc, uint32_t offSrc, PRTSGBUF pSgBuf, + size_t cbCopy)); + + /** + * Queries a pointer to the memory buffer for the request from the drive/device above. + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if this is not supported for this request. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoBuf The I/O request handle. + * @param pvIoBufAlloc The allocator specific memory for this request. + * @param offBuf The offset from the start of the buffer to get the buffer address. + * @param cbBuf The number of bytes requested. + * @param ppvBuf Where to store the pointer to the guest buffer on success. + * @param pcbBuf Where to store the size of the buffer on success. + * + * @note This is an optional feature of the entity implementing this interface to avoid overhead + * by copying the data between buffers. If NULL it is not supported at all and the caller + * has to resort to VDIOBUFCALLBACKS::pfnIoBufCopyToBuf and VDIOBUFCALLBACKS::pfnIoBufCopyFromBuf. + * The same holds when VERR_NOT_SUPPORTED is returned. + * + * On the upside the caller of this interface might not call this method at all and just + * use the before mentioned methods to copy the data between the buffers. + */ + DECLR3CALLBACKMEMBER(int, pfnIoBufQueryBuf, (PVDIOBUFCALLBACKS pInterface, VDIOBUF hIoBuf, + void *pvIoBufAlloc, uint32_t offBuf, size_t cbBuf, + void **ppvBuf, size_t *pcbBuf)); + +} VDIOBUFCALLBACKS; + +/** + * Creates a new I/O buffer manager. + * + * @returns VBox status code. + * @param phIoBufMgr Where to store the handle to the I/O buffer manager on success. + * @param cbMax The maximum amount of I/O memory to allow. Trying to allocate more than + * this will lead to out of memory errors. 0 for "unlimited" size (only restriction + * is the available memory on the host). + * @param fFlags Combination of VD_IOBUFMGR_F_*. + * @param pIoBufClbks Memory copy callbacks between source and target memory regions, optional. + * When NULL all I/O buffers must be allocated with a valid S/G buffer laying out the + * memory. + * @param cbIoBufAlloc How much to allocate extra in the I/O buffer for private use. + */ +VBOXDDU_DECL(int) VDIoBufMgrCreate(PVDIOBUFMGR phIoBufMgr, size_t cbMax, uint32_t fFlags, + PVDIOBUFCALLBACKS pIoBufClbks, size_t cbIoBufAlloc); + +/** + * Destroys the given I/O buffer manager. + * + * @returns VBox status code. + * @retval VERR_INVALID_STATE if there are still buffers allocated by the given manager. + * @param hIoBufMgr The I/O buffer manager. + */ +VBOXDDU_DECL(int) VDIoBufMgrDestroy(VDIOBUFMGR hIoBufMgr); + +/** + * Allocate a new I/O buffer handle. + * + * @returns VBox status code. + * @param hIoBufMgr The I/O buffer manager to use. + * @param phIoBuf Where to store the I/O buffer handle on success. + * @param ppvIoBufAlloc Where to store the pointe to the private party on success. + * @param pSgBuf The S/G buffer to use, optional. If NULL the I/O buffer callbacks + * supplied when creating the owning manager are used to transfer the + * data. + * @param cbBuf Size of the buffer in bytes. + */ +VBOXDDU_DECL(int) VDIoBufMgrAllocBuf(VDIOBUFMGR hIoBufMgr, PVDIOBUF phIoBuf, void **ppvIoBufAlloc, + PCRTSGBUF pSgBuf, size_t cbBuf); + +/** + * Retains the I/O buffer reference count. + * + * @returns New reference count. + * @param hIoBuf The I/O buffer handle. + */ +VBOXDDU_DECL(uint32_t) VDIoBufRetain(VDIOBUF hIoBuf); + +/** + * Releases the given I/O buffer reference. + * + * @returns New reference count, on 0 the I/O buffer is destroyed. + * @param hIoBuf The I/O buffer handle. + */ +VBOXDDU_DECL(uint32_t) VDIoBufRelease(VDIOBUF hIoBuf); + +/** @} */ + + +/** @defgroup grp_vd_ioqueue I/O queues + * @{ + */ + +/** VD I/O queue handle. */ +typedef struct VDIOQUEUEINT *VDIOQUEUE; +/** Pointer to an VD I/O queue handle. */ +typedef VDIOQUEUE *PVDIOQUEUE; + +/** VD I/O queue request handle. */ +typedef struct VDIOREQINT *VDIOREQ; +/** Pointer to an VD I/O queue request handle. */ +typedef VDIOREQ *PVDIOREQ; + +/** A I/O request ID. */ +typedef uint64_t VDIOREQID; + +/** + * I/O request type. + */ +typedef enum VDIOREQTYPE +{ + /** Invalid request type. */ + VDIOREQTYPE_INVALID = 0, + /** Read request. */ + VDIOREQTYPE_READ, + /** Write request. */ + VDIOREQTYPE_WRITE, + /** Flush request. */ + VDIOREQTYPE_FLUSH, + /** Discard request. */ + VDIOREQTYPE_DISCARD, + /** 32bit hack. */ + VDIOREQTYPE_32BIT_HACK = 0x7fffffff +} VDIOREQTYPE; +/** Pointer to a request type. */ +typedef VDIOREQTYPE *PVDIOREQTYPE; + +/** + * I/O queue request completion callback. + * + * @returns nothing. + * @param hVdIoQueue The VD I/O queue handle. + * @param pDisk The disk the queue is attached to. + * @param hVdIoReq The VD I/O request which completed. + * @param pvVdIoReq Pointer to the allocator specific memory for this request. + * @param rcReq The completion status code. + */ +typedef DECLCALLBACKTYPE(void, FNVDIOQUEUEREQCOMPLETE,(VDIOQUEUE hVdIoQueue, PVDISK pDisk, + VDIOREQ hVdIoReq, void *pvVdIoReq, int rcReq)); +/** Pointer to a VD I/O queue request completion callback. */ +typedef FNVDIOQUEUEREQCOMPLETE *PFNVDIOQUEUEREQCOMPLETE; + + +/** + * Creates a new I/O queue. + * + * @returns VBox status code. + * @param phVdIoQueue Where to store the handle to the I/O queue on success. + * @param pfnIoReqComplete The completion handle to call when a request on the specified queue completes. + * @param cbIoReqAlloc The extra amount of memory to allocate and associate with allocated requests + * for use by the caller. + * @param iPriority The priority of the queue from 0..UINT32_MAX. The lower the number the higher + * the priority of the queue. + */ +VBOXDDU_DECL(int) VDIoQueueCreate(PVDIOQUEUE phVdIoQueue, PFNVDIOQUEUEREQCOMPLETE pfnIoReqComplete, + size_t cbIoReqAlloc, uint32_t iPriority); + +/** + * Destroys the given I/O queue. + * + * @returns VBox status code. + * @param hVdIoQueue The I/O queue handle. + */ +VBOXDDU_DECL(int) VDIoQueueDestroy(VDIOQUEUE hVdIoQueue); + +/** + * Attaches the given I/O queue to the given virtual disk container. + * + * @returns VBox status code. + * @param pDisk The disk container handle. + * @param hVdIoQueue The I/O queue to attach. + */ +VBOXDDU_DECL(int) VDIoQueueAttach(PVDISK pDisk, VDIOQUEUE hVdIoQueue); + +/** + * Detaches the given I/O queue from the currently attached disk container. + * + * @returns VBox status code. + * @param hVdIoQueue The I/O queue. + * @param fPurge Flag whether to cancel all active requests on this queue + * before detaching. + */ +VBOXDDU_DECL(int) VDIoQueueDetach(VDIOQUEUE hVdIoQueue, bool fPurge); + +/** + * Purges all requests on the given queue. + * + * @returns VBox status code. + * @param hVdIoQueue The I/O queue. + */ +VBOXDDU_DECL(int) VDIoQueuePurge(VDIOQUEUE hVdIoQueue); + +/** + * Allocates a new request from the given queue. + * + * @returns VBox status code. + * @param hVdIoQueue The I/O queue. + * @param phVdIoReq Where to store the handle of the request on success. + * @param ppvVdIoReq Where to store the pointer to the allocator usable memory on success. + * @param uIoReqId The request ID to assign to the request for canceling. + */ +VBOXDDU_DECL(int) VDIoQueueReqAlloc(VDIOQUEUE hVdIoQueue, PVDIOREQ phVdIoReq, + void **ppvVdIoReq, VDIOREQID uIoReqId); + +/** + * Frees a given non active request. + * + * @returns VBox status code. + * @param hVdIoReq The I/O request to free. + */ +VBOXDDU_DECL(int) VDIoQueueReqFree(VDIOREQ hVdIoReq); + +/** + * Cancels an active request by the given request ID. + * + * @returns VBox status code. + * @param hVdIoQueue The I/O queue to cancel the request on. + * @param uIoReqId The request ID. + */ +VBOXDDU_DECL(int) VDIoQueueReqCancelById(VDIOQUEUE hVdIoQueue, VDIOREQID uIoReqId); + +/** + * Cancels an active request by the given handle. + * + * @returns VBox status code. + * @param hVdIoReq The I/O request handle to cancel. + */ +VBOXDDU_DECL(int) VDIoQueueReqCancelByHandle(VDIOREQ hVdIoReq); + +/** + * Submit a new request to the queue the request was allocated from. + * + * @returns VBox status code. + * @param hVdIoReq The I/O request handle to submit. + * @param enmType The type of the request. + * @param hVdIoIter The iterator to use, NULL for flush requests. + * @param hVdIoBuf The I/O buffer handle to use, NULL for flush and discard requests. + */ +VBOXDDU_DECL(int) VDIoQueueReqSubmit(VDIOREQ hVdIoReq, VDIOREQTYPE enmType, + VDIOITER hVdIoIter, VDIOBUF hVdIoBuf); + +/** @} */ + + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vd_h */ + diff --git a/include/VBox/vdmedia.h b/include/VBox/vdmedia.h new file mode 100644 index 00000000..89886efb --- /dev/null +++ b/include/VBox/vdmedia.h @@ -0,0 +1,226 @@ +/** @file + * Virtual Disk Container API - Media type definitions shared with PDM. + */ + +/* + * Copyright (C) 2017-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vdmedia_h +#define VBOX_INCLUDED_vdmedia_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @name VD container type. + * @{ + */ +typedef enum VDTYPE +{ + /** Invalid. */ + VDTYPE_INVALID = 0, + /** HardDisk */ + VDTYPE_HDD, + /** Any kind of optical disc (CD/DVD etc.). */ + VDTYPE_OPTICAL_DISC, + /** Floppy. */ + VDTYPE_FLOPPY +} VDTYPE; +/** @}*/ + +/** @name VD medium type. + * @{ + */ +typedef enum VDMEDIUMTYPE +{ + /** Invalid. */ + VDMEDIUMTYPE_INVALID = 0, + /** HardDisk (spinning platter or SSD). */ + VDMEDIUMTYPE_HDD, + /** CD-ROM */ + VDMEDIUMTYPE_CDROM, + /** DVD-ROM */ + VDMEDIUMTYPE_DVDROM, + /** BluRay. */ + VDMEDIUMTYPE_BD, + /** 360KB 5 1/4" floppy. */ + VDMEDIUMTYPE_FLOPPY_360, + /** 720KB 3 1/2" floppy. */ + VDMEDIUMTYPE_FLOPPY_720, + /** 1.2MB 5 1/4" floppy. */ + VDMEDIUMTYPE_FLOPPY_1_20, + /** 1.44MB 3 1/2" floppy. */ + VDMEDIUMTYPE_FLOPPY_1_44, + /** 2.88MB 3 1/2" floppy. */ + VDMEDIUMTYPE_FLOPPY_2_88, + /** Fake disk that can take up to 15.6 MB images. + * C=255, H=2, S=63. */ + VDMEDIUMTYPE_FLOPPY_FAKE_15_6, + /** Fake disk that can take up to 63.5 MB images. + * C=255, H=2, S=255. */ + VDMEDIUMTYPE_FLOPPY_FAKE_63_5 +} VDMEDIUMTYPE; +/** @} */ + +/** Check if the given medium type is a floppy. */ +#define VDMEDIUMTYPE_IS_FLOPPY(a_enmType) ( (a_enmType) >= VDMEDIUMTYPE_FLOPPY_360 && (a_enmType) <= VDMEDIUMTYPE_FLOPPY_2_88 ) + +/** + * Disk geometry. + */ +typedef struct VDGEOMETRY +{ + /** Number of cylinders. */ + uint32_t cCylinders; + /** Number of heads. */ + uint32_t cHeads; + /** Number of sectors. */ + uint32_t cSectors; +} VDGEOMETRY; + +/** Pointer to disk geometry. */ +typedef VDGEOMETRY *PVDGEOMETRY; +/** Pointer to constant disk geometry. */ +typedef const VDGEOMETRY *PCVDGEOMETRY; + +/** + * Disk region data form known to us from various standards. + */ +typedef enum VDREGIONDATAFORM +{ + /** Invalid data form. */ + VDREGIONDATAFORM_INVALID = 0, + /** Raw data, no standardized format. */ + VDREGIONDATAFORM_RAW, + /** CD-DA (audio CD), 2352 bytes of data. */ + VDREGIONDATAFORM_CDDA, + /** CDDA data is pause. */ + VDREGIONDATAFORM_CDDA_PAUSE, + /** Mode 1 with 2048 bytes sector size. */ + VDREGIONDATAFORM_MODE1_2048, + /** Mode 1 with 2352 bytes sector size. */ + VDREGIONDATAFORM_MODE1_2352, + /** Mode 1 with 0 bytes sector size (generated by the drive). */ + VDREGIONDATAFORM_MODE1_0, + /** XA Mode with 2336 bytes sector size. */ + VDREGIONDATAFORM_XA_2336, + /** XA Mode with 2352 bytes sector size. */ + VDREGIONDATAFORM_XA_2352, + /** XA Mode with 0 bytes sector size (generated by the drive). */ + VDREGIONDATAFORM_XA_0, + /** Mode 2 with 2336 bytes sector size. */ + VDREGIONDATAFORM_MODE2_2336, + /** Mode 2 with 2352 bytes sector size. */ + VDREGIONDATAFORM_MODE2_2352, + /** Mode 2 with 0 bytes sector size (generated by the drive). */ + VDREGIONDATAFORM_MODE2_0 +} VDREGIONDATAFORM; +/** Pointer to a region data form. */ +typedef VDREGIONDATAFORM *PVDREGIONDATAFORM; +/** Pointer to a const region data form. */ +typedef const VDREGIONDATAFORM PCVDREGIONDATAFORM; + +/** + * Disk region metadata forms known to us. + */ +typedef enum VDREGIONMETADATAFORM +{ + /** Invalid metadata form. */ + VDREGIONMETADATAFORM_INVALID = 0, + /** No metadata assined to the region. */ + VDREGIONMETADATAFORM_NONE, + /** Raw metadata, no standardized format. */ + VDREGIONMETADATAFORM_RAW +} VDREGIONMETADATAFORM; +/** Pointer to a region metadata form. */ +typedef VDREGIONMETADATAFORM *PVDREGIONMETADATAFORM; +/** Pointer to a const region metadata form. */ +typedef const VDREGIONMETADATAFORM PCVDREGIONMETADATAFORM; + +/** + * Disk region descriptor. + */ +typedef struct VDREGIONDESC +{ + /** Start of the region in bytes or LBA number (depending on the flag in the + * list header). */ + uint64_t offRegion; + /** Overall size of the region in bytes or number of blocks (depending on the + * flag in the list header). */ + uint64_t cRegionBlocksOrBytes; + /** Size of one block in bytes, containing user and metadata. */ + uint64_t cbBlock; + /** User data form of the block. */ + VDREGIONDATAFORM enmDataForm; + /** Metadata form of the block. */ + VDREGIONMETADATAFORM enmMetadataForm; + /** Size of the data block in bytes. */ + uint64_t cbData; + /** Size of the metadata in a block in bytes. */ + uint64_t cbMetadata; +} VDREGIONDESC; +/** Pointer to a region descriptor. */ +typedef VDREGIONDESC *PVDREGIONDESC; +/** Pointer to a constant region descriptor. */ +typedef const VDREGIONDESC *PCVDREGIONDESC; + +/** + * Disk region list. + */ +typedef struct VDREGIONLIST +{ + /** Flags valid for the region list. */ + uint32_t fFlags; + /** Number of regions in the descriptor array. */ + uint32_t cRegions; + /** Region descriptors - variable in size. */ + VDREGIONDESC aRegions[RT_FLEXIBLE_ARRAY_NESTED]; +} VDREGIONLIST; +/** Pointer to a region list. */ +typedef VDREGIONLIST *PVDREGIONLIST; +/** Pointer to a constant region list. */ +typedef const VDREGIONLIST *PCVDREGIONLIST; +/** Pointer to a region list pointer. */ +typedef PVDREGIONLIST *PPVDREGIONLIST; + +/** @name Valid region list flags. + * @{ + */ +/** When set the region start offset and size are given in numbers of blocks + * instead of byte offsets and sizes. */ +#define VD_REGION_LIST_F_LOC_SIZE_BLOCKS RT_BIT_32(0) +/** Mask of all valid flags. */ +#define VD_REGION_LIST_F_VALID (VD_REGION_LIST_F_LOC_SIZE_BLOCKS) +/** @} */ + +#endif /* !VBOX_INCLUDED_vdmedia_h */ + diff --git a/include/VBox/version.h b/include/VBox/version.h new file mode 100644 index 00000000..256e3a0c --- /dev/null +++ b/include/VBox/version.h @@ -0,0 +1,166 @@ +/** @file + * VBox Version Management. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_version_h +#define VBOX_INCLUDED_version_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +/* Product info. */ +#include +#include + +#ifdef RC_INVOKED +/* Some versions of RC has trouble with cdefs.h, so we duplicate these two here. */ +# define RT_STR(str) #str +# define RT_XSTR(str) RT_STR(str) +#else /* !RC_INVOKED */ + +/** Combined version number. */ +# define VBOX_VERSION (VBOX_VERSION_MAJOR << 16 | VBOX_VERSION_MINOR) +/** Get minor version from combined version. */ +# define VBOX_GET_VERSION_MINOR(uVer) ((uVer) & 0xffff) +/** Get major version from combined version. */ +# define VBOX_GET_VERSION_MAJOR(uVer) ((uVer) >> 16) + +/** + * Make a full version number. + * + * The returned number can be used in normal integer comparsions and will yield + * the expected results. + * + * @param uMajor The major version number. + * @param uMinor The minor version number. + * @param uBuild The build number. + * @returns Full version number. + */ +# define VBOX_FULL_VERSION_MAKE(uMajor, uMinor, uBuild) \ + ( (uint32_t)((uMajor) & 0xff) << 24 \ + | (uint32_t)((uMinor) & 0xff) << 16 \ + | (uint32_t)((uBuild) & 0xffff) \ + ) + +/** Combined version number. */ +# define VBOX_FULL_VERSION \ + VBOX_FULL_VERSION_MAKE(VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR, VBOX_VERSION_BUILD) +/** Get the major version number from a VBOX_FULL_VERSION style number. */ +# define VBOX_FULL_VERSION_GET_MAJOR(uFullVer) ( ((uFullVer) >> 24) & 0xffU ) +/** Get the minor version number from a VBOX_FULL_VERSION style number. */ +# define VBOX_FULL_VERSION_GET_MINOR(uFullVer) ( ((uFullVer) >> 16) & 0xffU ) +/** Get the build version number from a VBOX_FULL_VERSION style number. */ +# define VBOX_FULL_VERSION_GET_BUILD(uFullVer) ( ((uFullVer) ) & 0xffffU ) + +/** + * Make a short version number for use in 16 bit version fields. + * + * The returned number can be used in normal integer comparsions and will yield + * the expected results. + * + * @param uMajor The major version number. + * @param uMinor The minor version number. + * @returns Short version number. + */ +# define VBOX_SHORT_VERSION_MAKE(uMajor, uMinor) \ + ( (uint16_t)((uMajor) & 0xff) << 8 \ + | (uint16_t)((uMinor) & 0xff) \ + ) + +/** Combined short version number. */ +# define VBOX_SHORT_VERSION \ + VBOX_SHORT_VERSION_MAKE(VBOX_VERSION_MAJOR, VBOX_VERSION_MINOR) +/** Get the major version number from a VBOX_SHORT_VERSION style number. */ +# define VBOX_SHORT_VERSION_GET_MAJOR(uShortVer) ( ((uShortVer) >> 8) & 0xffU ) +/** Get the minor version number from a VBOX_SHORT_VERSION style number. */ +# define VBOX_SHORT_VERSION_GET_MINOR(uShortVer) ( (uShortVer) & 0xffU ) + +#endif /* !RC_INVOKED */ + +/** @name Prefined strings for Windows resource files + * @{ */ +#define VBOX_RC_COMPANY_NAME VBOX_VENDOR +#define VBOX_RC_LEGAL_COPYRIGHT "Copyright (C) 2009-" VBOX_C_YEAR " Oracle Corporation\0" +#define VBOX_RC_PRODUCT_NAME VBOX_PRODUCT +#define VBOX_RC_PRODUCT_NAME_GA VBOX_PRODUCT " Guest Additions" +#define VBOX_RC_PRODUCT_NAME_PUEL_EXTPACK VBOX_PRODUCT " Extension Pack" +#define VBOX_RC_PRODUCT_NAME_DTRACE_EXTPACK VBOX_PRODUCT " VBoxDTrace Extension Pack" +#define VBOX_RC_PRODUCT_NAME_STR VBOX_RC_PRODUCT_NAME "\0" +#define VBOX_RC_PRODUCT_NAME_GA_STR VBOX_RC_PRODUCT_NAME_GA "\0" +#define VBOX_RC_PRODUCT_NAME_PUEL_EXTPACK_STR VBOX_RC_PRODUCT_NAME_PUEL_EXTPACK "\0" +#define VBOX_RC_PRODUCT_NAME_DTRACE_EXTPACK_STR VBOX_RC_PRODUCT_NAME_DTRACE_EXTPACK "\0" +#define VBOX_RC_PRODUCT_VERSION VBOX_VERSION_MAJOR , VBOX_VERSION_MINOR , VBOX_VERSION_BUILD , VBOX_SVN_REV_MOD_5K +#define VBOX_RC_FILE_VERSION VBOX_VERSION_MAJOR , VBOX_VERSION_MINOR , VBOX_VERSION_BUILD , VBOX_SVN_REV_MOD_5K +#ifndef VBOX_VERSION_PRERELEASE +# define VBOX_RC_PRODUCT_VERSION_STR RT_XSTR(VBOX_VERSION_MAJOR) "." RT_XSTR(VBOX_VERSION_MINOR) "." RT_XSTR(VBOX_VERSION_BUILD) "." RT_XSTR(VBOX_SVN_REV) "\0" +# define VBOX_RC_FILE_VERSION_STR RT_XSTR(VBOX_VERSION_MAJOR) "." RT_XSTR(VBOX_VERSION_MINOR) "." RT_XSTR(VBOX_VERSION_BUILD) "." RT_XSTR(VBOX_SVN_REV) "\0" +#else +# define VBOX_RC_PRODUCT_VERSION_STR RT_XSTR(VBOX_VERSION_MAJOR) "." RT_XSTR(VBOX_VERSION_MINOR) "." RT_XSTR(VBOX_VERSION_BUILD) "." RT_XSTR(VBOX_SVN_REV) " (" VBOX_VERSION_PRERELEASE ")\0" +# define VBOX_RC_FILE_VERSION_STR RT_XSTR(VBOX_VERSION_MAJOR) "." RT_XSTR(VBOX_VERSION_MINOR) "." RT_XSTR(VBOX_VERSION_BUILD) "." RT_XSTR(VBOX_SVN_REV) " (" VBOX_VERSION_PRERELEASE ")\0" +#endif +#define VBOX_RC_FILE_OS VOS_NT_WINDOWS32 +#define VBOX_RC_TYPE_DLL VFT_DLL +#define VBOX_RC_TYPE_APP VFT_APP +#define VBOX_RC_TYPE_DRV VFT_DRV +/* Flags and extra strings depending on the build type and who's building. */ +#if defined(DEBUG) || defined(LOG_ENABLED) || defined(RT_STRICT) || defined(VBOX_STRICT) || defined(VBOX_WITH_STATISTICS) +# define VBOX_RC_FILE_FLAGS_DEBUG VS_FF_DEBUG +#else +# define VBOX_RC_FILE_FLAGS_DEBUG 0 +#endif +#if VBOX_VERSION_MINOR >= 51 || defined(VBOX_VERSION_PRERELEASE) +# define VBOX_RC_FILE_FLAGS_PRERELEASE VS_FF_PRERELEASE +#else +# define VBOX_RC_FILE_FLAGS_PRERELEASE 0 +#endif +#if defined(VBOX_BUILD_SERVER_BUILD) && (VBOX_VERSION_MINOR & 1) == 0 +# define VBOX_RC_FILE_FLAGS_BUILD 0 +# define VBOX_RC_MORE_STRINGS +#elif defined(VBOX_BUILD_SERVER_BUILD) +# define VBOX_RC_FILE_FLAGS_BUILD VS_FF_SPECIALBUILD +# define VBOX_RC_MORE_STRINGS VALUE "SpecialBuild", "r" RT_XSTR(VBOX_SVN_REV) "\0" +#else +# define VBOX_RC_FILE_FLAGS_BUILD VS_FF_PRIVATEBUILD +# ifdef VBOX_PRIVATE_BUILD_DESC +# define VBOX_RC_MORE_STRINGS VALUE "PrivateBuild", VBOX_PRIVATE_BUILD_DESC "\0" +# else +# define VBOX_RC_MORE_STRINGS VALUE "PrivateBuild", "r" RT_XSTR(VBOX_SVN_REV) "\0" +# error +# endif +#endif +#define VBOX_RC_FILE_FLAGS (VBOX_RC_FILE_FLAGS_DEBUG | VBOX_RC_FILE_FLAGS_PRERELEASE | VBOX_RC_FILE_FLAGS_BUILD) +/** @} */ + +#endif /* !VBOX_INCLUDED_version_h */ + diff --git a/include/VBox/vmm/Makefile.kup b/include/VBox/vmm/Makefile.kup new file mode 100644 index 00000000..e69de29b diff --git a/include/VBox/vmm/apic.h b/include/VBox/vmm/apic.h new file mode 100644 index 00000000..6e9c3673 --- /dev/null +++ b/include/VBox/vmm/apic.h @@ -0,0 +1,107 @@ +/** @file + * APIC - Advanced Programmable Interrupt Controller. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_apic_h +#define VBOX_INCLUDED_vmm_apic_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +struct PDMDEVREGCB; + +/** @defgroup grp_apic The local APIC VMM API + * @ingroup grp_vmm + * @{ + */ + +RT_C_DECLS_BEGIN + +#ifdef VBOX_INCLUDED_vmm_pdmdev_h +extern const PDMDEVREG g_DeviceAPIC; +#endif + +/* These functions are exported as they are called from external modules (recompiler). */ +VMMDECL(void) APICUpdatePendingInterrupts(PVMCPUCC pVCpu); +VMMDECL(int) APICGetTpr(PCVMCPUCC pVCpu, uint8_t *pu8Tpr, bool *pfPending, uint8_t *pu8PendingIntr); +VMMDECL(int) APICSetTpr(PVMCPUCC pVCpu, uint8_t u8Tpr); + +/* These functions are VMM internal. */ +VMM_INT_DECL(bool) APICIsEnabled(PCVMCPUCC pVCpu); +VMM_INT_DECL(bool) APICGetHighestPendingInterrupt(PVMCPUCC pVCpu, uint8_t *pu8PendingIntr); +VMM_INT_DECL(bool) APICQueueInterruptToService(PVMCPUCC pVCpu, uint8_t u8PendingIntr); +VMM_INT_DECL(void) APICDequeueInterruptFromService(PVMCPUCC pVCpu, uint8_t u8PendingIntr); +VMM_INT_DECL(VBOXSTRICTRC) APICReadMsr(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t *pu64Value); +VMM_INT_DECL(VBOXSTRICTRC) APICWriteMsr(PVMCPUCC pVCpu, uint32_t u32Reg, uint64_t u64Value); +VMM_INT_DECL(int) APICGetTimerFreq(PVMCC pVM, uint64_t *pu64Value); +VMM_INT_DECL(VBOXSTRICTRC) APICLocalInterrupt(PVMCPUCC pVCpu, uint8_t u8Pin, uint8_t u8Level, int rcRZ); +VMM_INT_DECL(uint64_t) APICGetBaseMsrNoCheck(PCVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) APICGetBaseMsr(PVMCPUCC pVCpu, uint64_t *pu64Value); +VMM_INT_DECL(int) APICSetBaseMsr(PVMCPUCC pVCpu, uint64_t u64BaseMsr); +VMM_INT_DECL(int) APICGetInterrupt(PVMCPUCC pVCpu, uint8_t *pu8Vector, uint32_t *pu32TagSrc); +VMM_INT_DECL(int) APICBusDeliver(PVMCC pVM, uint8_t uDest, uint8_t uDestMode, uint8_t uDeliveryMode, uint8_t uVector, + uint8_t uPolarity, uint8_t uTriggerMode, uint32_t uTagSrc); +VMM_INT_DECL(int) APICGetApicPageForCpu(PCVMCPUCC pVCpu, PRTHCPHYS pHCPhys, PRTR0PTR pR0Ptr, PRTR3PTR pR3Ptr); + +/** @name Hyper-V interface (Ring-3 and all-context API). + * @{ */ +#ifdef IN_RING3 +VMMR3_INT_DECL(void) APICR3HvSetCompatMode(PVM pVM, bool fHyperVCompatMode); +#endif +VMM_INT_DECL(void) APICHvSendInterrupt(PVMCPUCC pVCpu, uint8_t uVector, bool fAutoEoi, XAPICTRIGGERMODE enmTriggerMode); +VMM_INT_DECL(VBOXSTRICTRC) APICHvSetTpr(PVMCPUCC pVCpu, uint8_t uTpr); +VMM_INT_DECL(uint8_t) APICHvGetTpr(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) APICHvSetIcr(PVMCPUCC pVCpu, uint64_t uIcr); +VMM_INT_DECL(uint64_t) APICHvGetIcr(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) APICHvSetEoi(PVMCPUCC pVCpu, uint32_t uEoi); +/** @} */ + +#ifdef IN_RING3 +/** @defgroup grp_apic_r3 The APIC Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) APICR3RegisterDevice(struct PDMDEVREGCB *pCallbacks); +VMMR3_INT_DECL(void) APICR3InitIpi(PVMCPU pVCpu); +VMMR3_INT_DECL(void) APICR3HvEnable(PVM pVM); +/** @} */ +#endif /* IN_RING3 */ + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_apic_h */ + diff --git a/include/VBox/vmm/cfgm.h b/include/VBox/vmm/cfgm.h new file mode 100644 index 00000000..7a84dd94 --- /dev/null +++ b/include/VBox/vmm/cfgm.h @@ -0,0 +1,245 @@ +/** @file + * CFGM - Configuration Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cfgm_h +#define VBOX_INCLUDED_vmm_cfgm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +/** @defgroup grp_cfgm The Configuration Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * Configuration manager value type. + */ +typedef enum CFGMVALUETYPE +{ + /** Integer value. */ + CFGMVALUETYPE_INTEGER = 1, + /** String value. */ + CFGMVALUETYPE_STRING, + /** Bytestring value. */ + CFGMVALUETYPE_BYTES, + /** Password value, same as String but hides the content in dump. */ + CFGMVALUETYPE_PASSWORD +} CFGMVALUETYPE; +/** Pointer to configuration manager property type. */ +typedef CFGMVALUETYPE *PCFGMVALUETYPE; + + + +RT_C_DECLS_BEGIN + +#ifdef IN_RING3 +/** @defgroup grp_cfgm_r3 The CFGM Host Context Ring-3 API + * @{ + */ + +typedef enum CFGMCONFIGTYPE +{ + /** pvConfig points to nothing, use defaults. */ + CFGMCONFIGTYPE_NONE = 0, + /** pvConfig points to a IMachine interface. */ + CFGMCONFIGTYPE_IMACHINE +} CFGMCONFIGTYPE; + + +/** + * CFGM init callback for constructing the configuration tree. + * + * This is called from the emulation thread, and the one interfacing the VM + * can make any necessary per-thread initializations at this point. + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pVM The cross context VM structure. + * @param pVMM The VMM R3 vtable. + * @param pvUser The argument supplied to VMR3Create(). + */ +typedef DECLCALLBACKTYPE(int, FNCFGMCONSTRUCTOR,(PUVM pUVM, PVM pVM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNCFGMCONSTRUCTOR(). */ +typedef FNCFGMCONSTRUCTOR *PFNCFGMCONSTRUCTOR; + +VMMR3DECL(int) CFGMR3Init(PVM pVM, PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUser); +VMMR3DECL(int) CFGMR3Term(PVM pVM); +VMMR3DECL(int) CFGMR3ConstructDefaultTree(PVM pVM); + +VMMR3DECL(PCFGMNODE) CFGMR3CreateTree(PUVM pUVM); +VMMR3DECL(int) CFGMR3DestroyTree(PCFGMNODE pRoot); +VMMR3DECL(void) CFGMR3Dump(PCFGMNODE pRoot); +VMMR3DECL(int) CFGMR3DuplicateSubTree(PCFGMNODE pRoot, PCFGMNODE *ppCopy); +VMMR3DECL(int) CFGMR3ReplaceSubTree(PCFGMNODE pRoot, PCFGMNODE pNewRoot); +VMMR3DECL(int) CFGMR3InsertSubTree(PCFGMNODE pNode, const char *pszName, PCFGMNODE pSubTree, PCFGMNODE *ppChild); +VMMR3DECL(int) CFGMR3InsertNode(PCFGMNODE pNode, const char *pszName, PCFGMNODE *ppChild); +VMMR3DECL(int) CFGMR3InsertNodeF(PCFGMNODE pNode, PCFGMNODE *ppChild, + const char *pszNameFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VMMR3DECL(int) CFGMR3InsertNodeFV(PCFGMNODE pNode, PCFGMNODE *ppChild, + const char *pszNameFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0); +VMMR3DECL(void) CFGMR3SetRestrictedRoot(PCFGMNODE pNode); +VMMR3DECL(void) CFGMR3RemoveNode(PCFGMNODE pNode); +VMMR3DECL(int) CFGMR3InsertInteger(PCFGMNODE pNode, const char *pszName, uint64_t u64Integer); +VMMR3DECL(int) CFGMR3InsertString(PCFGMNODE pNode, const char *pszName, const char *pszString); +VMMR3DECL(int) CFGMR3InsertStringN(PCFGMNODE pNode, const char *pszName, const char *pszString, size_t cchString); +VMMR3DECL(int) CFGMR3InsertStringF(PCFGMNODE pNode, const char *pszName, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VMMR3DECL(int) CFGMR3InsertStringFV(PCFGMNODE pNode, const char *pszName, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); +VMMR3DECL(int) CFGMR3InsertStringW(PCFGMNODE pNode, const char *pszName, PCRTUTF16 pwszValue); +VMMR3DECL(int) CFGMR3InsertBytes(PCFGMNODE pNode, const char *pszName, const void *pvBytes, size_t cbBytes); +VMMR3DECL(int) CFGMR3InsertPassword(PCFGMNODE pNode, const char *pszName, const char *pszString); +VMMR3DECL(int) CFGMR3InsertPasswordN(PCFGMNODE pNode, const char *pszName, const char *pszString, size_t cchString); +VMMR3DECL(int) CFGMR3InsertValue(PCFGMNODE pNode, PCFGMLEAF pValue); +VMMR3DECL(int) CFGMR3RemoveValue(PCFGMNODE pNode, const char *pszName); + +/** @name CFGMR3CopyTree flags. + * @{ */ +/** Reserved value disposition \#0. */ +#define CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_0 UINT32_C(0x00000000) +/** Reserved value disposition \#1. */ +#define CFGM_COPY_FLAGS_RESERVED_VALUE_DISP_1 UINT32_C(0x00000001) +/** Replace exiting values. */ +#define CFGM_COPY_FLAGS_REPLACE_VALUES UINT32_C(0x00000002) +/** Ignore exiting values. */ +#define CFGM_COPY_FLAGS_IGNORE_EXISTING_VALUES UINT32_C(0x00000003) +/** Value disposition mask. */ +#define CFGM_COPY_FLAGS_VALUE_DISP_MASK UINT32_C(0x00000003) + +/** Replace exiting keys. */ +#define CFGM_COPY_FLAGS_RESERVED_KEY_DISP UINT32_C(0x00000000) +/** Replace exiting keys. */ +#define CFGM_COPY_FLAGS_MERGE_KEYS UINT32_C(0x00000010) +/** Replace exiting keys. */ +#define CFGM_COPY_FLAGS_REPLACE_KEYS UINT32_C(0x00000020) +/** Ignore existing keys. */ +#define CFGM_COPY_FLAGS_IGNORE_EXISTING_KEYS UINT32_C(0x00000030) +/** Key disposition. */ +#define CFGM_COPY_FLAGS_KEY_DISP_MASK UINT32_C(0x00000030) +/** @} */ +VMMR3DECL(int) CFGMR3CopyTree(PCFGMNODE pDstTree, PCFGMNODE pSrcTree, uint32_t fFlags); + +VMMR3DECL(bool) CFGMR3Exists( PCFGMNODE pNode, const char *pszName); +VMMR3DECL(int) CFGMR3QueryType( PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType); +VMMR3DECL(int) CFGMR3QuerySize( PCFGMNODE pNode, const char *pszName, size_t *pcb); +VMMR3DECL(int) CFGMR3QueryInteger( PCFGMNODE pNode, const char *pszName, uint64_t *pu64); +VMMR3DECL(int) CFGMR3QueryIntegerDef( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def); +VMMR3DECL(int) CFGMR3QueryString( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString); +VMMR3DECL(int) CFGMR3QueryStringDef( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef); +VMMR3DECL(int) CFGMR3QueryPassword( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString); +VMMR3DECL(int) CFGMR3QueryPasswordDef( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef); +VMMR3DECL(int) CFGMR3QueryBytes( PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData); + + +/** @name Helpers + * @{ + */ +VMMR3DECL(int) CFGMR3QueryU64( PCFGMNODE pNode, const char *pszName, uint64_t *pu64); +VMMR3DECL(int) CFGMR3QueryU64Def( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def); +VMMR3DECL(int) CFGMR3QueryS64( PCFGMNODE pNode, const char *pszName, int64_t *pi64); +VMMR3DECL(int) CFGMR3QueryS64Def( PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def); +VMMR3DECL(int) CFGMR3QueryU32( PCFGMNODE pNode, const char *pszName, uint32_t *pu32); +VMMR3DECL(int) CFGMR3QueryU32Def( PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def); +VMMR3DECL(int) CFGMR3QueryS32( PCFGMNODE pNode, const char *pszName, int32_t *pi32); +VMMR3DECL(int) CFGMR3QueryS32Def( PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def); +VMMR3DECL(int) CFGMR3QueryU16( PCFGMNODE pNode, const char *pszName, uint16_t *pu16); +VMMR3DECL(int) CFGMR3QueryU16Def( PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def); +VMMR3DECL(int) CFGMR3QueryS16( PCFGMNODE pNode, const char *pszName, int16_t *pi16); +VMMR3DECL(int) CFGMR3QueryS16Def( PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def); +VMMR3DECL(int) CFGMR3QueryU8( PCFGMNODE pNode, const char *pszName, uint8_t *pu8); +VMMR3DECL(int) CFGMR3QueryU8Def( PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def); +VMMR3DECL(int) CFGMR3QueryS8( PCFGMNODE pNode, const char *pszName, int8_t *pi8); +VMMR3DECL(int) CFGMR3QueryS8Def( PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def); +VMMR3DECL(int) CFGMR3QueryBool( PCFGMNODE pNode, const char *pszName, bool *pf); +VMMR3DECL(int) CFGMR3QueryBoolDef( PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef); +VMMR3DECL(int) CFGMR3QueryPort( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort); +VMMR3DECL(int) CFGMR3QueryPortDef( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef); +VMMR3DECL(int) CFGMR3QueryUInt( PCFGMNODE pNode, const char *pszName, unsigned int *pu); +VMMR3DECL(int) CFGMR3QueryUIntDef( PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef); +VMMR3DECL(int) CFGMR3QuerySInt( PCFGMNODE pNode, const char *pszName, signed int *pi); +VMMR3DECL(int) CFGMR3QuerySIntDef( PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef); +VMMR3DECL(int) CFGMR3QueryGCPtr( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr); +VMMR3DECL(int) CFGMR3QueryGCPtrDef( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef); +VMMR3DECL(int) CFGMR3QueryGCPtrU( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr); +VMMR3DECL(int) CFGMR3QueryGCPtrUDef( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef); +VMMR3DECL(int) CFGMR3QueryGCPtrS( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr); +VMMR3DECL(int) CFGMR3QueryGCPtrSDef( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef); +VMMR3DECL(int) CFGMR3QueryStringAlloc( PCFGMNODE pNode, const char *pszName, char **ppszString); +VMMR3DECL(int) CFGMR3QueryStringAllocDef(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef); + +/** @} */ + +/** @name Tree Navigation and Enumeration. + * @{ + */ +VMMR3DECL(PCFGMNODE) CFGMR3GetRoot(PVM pVM); +VMMR3DECL(PCFGMNODE) CFGMR3GetRootU(PUVM pUVM); +VMMR3DECL(PCFGMNODE) CFGMR3GetParent(PCFGMNODE pNode); +VMMR3DECL(PCFGMNODE) CFGMR3GetParentEx(PVM pVM, PCFGMNODE pNode); +VMMR3DECL(PCFGMNODE) CFGMR3GetChild(PCFGMNODE pNode, const char *pszPath); +VMMR3DECL(PCFGMNODE) CFGMR3GetChildF(PCFGMNODE pNode, const char *pszPathFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3); +VMMR3DECL(PCFGMNODE) CFGMR3GetChildFV(PCFGMNODE pNode, const char *pszPathFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0); +VMMR3DECL(PCFGMNODE) CFGMR3GetFirstChild(PCFGMNODE pNode); +VMMR3DECL(PCFGMNODE) CFGMR3GetNextChild(PCFGMNODE pCur); +VMMR3DECL(int) CFGMR3GetName(PCFGMNODE pCur, char *pszName, size_t cchName); +VMMR3DECL(size_t) CFGMR3GetNameLen(PCFGMNODE pCur); +VMMR3DECL(bool) CFGMR3AreChildrenValid(PCFGMNODE pNode, const char *pszzValid); +VMMR3DECL(PCFGMLEAF) CFGMR3GetFirstValue(PCFGMNODE pCur); +VMMR3DECL(PCFGMLEAF) CFGMR3GetNextValue(PCFGMLEAF pCur); +VMMR3DECL(int) CFGMR3GetValueName(PCFGMLEAF pCur, char *pszName, size_t cchName); +VMMR3DECL(size_t) CFGMR3GetValueNameLen(PCFGMLEAF pCur); +VMMR3DECL(CFGMVALUETYPE) CFGMR3GetValueType(PCFGMLEAF pCur); +VMMR3DECL(bool) CFGMR3AreValuesValid(PCFGMNODE pNode, const char *pszzValid); +VMMR3DECL(int) CFGMR3ValidateConfig(PCFGMNODE pNode, const char *pszNode, + const char *pszValidValues, const char *pszValidNodes, + const char *pszWho, uint32_t uInstance); + +/** @} */ + + +/** @} */ +#endif /* IN_RING3 */ + + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_cfgm_h */ + diff --git a/include/VBox/vmm/cpuidcall.h b/include/VBox/vmm/cpuidcall.h new file mode 100644 index 00000000..8bcdb8da --- /dev/null +++ b/include/VBox/vmm/cpuidcall.h @@ -0,0 +1,107 @@ +/** @file + * VM - The Virtual Machine, CPU Host Call Interface (AMD64 & x86 only). + * + * @note cpuidcall.mac is generated from this file by running 'kmk incs' in the root. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpuidcall_h +#define VBOX_INCLUDED_vmm_cpuidcall_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/** @defgroup grp_cpuidcall VBox CPUID Host Call Interface (AMD64 & x86) + * + * This describes an interface using CPUID for calling the host from within the + * VM. This is chiefly intended for nested VM debugging at present and is + * therefore disabled by default. + * + * @{ */ + +/** Fixed EAX value for all requests (big-endian 'VBox'). */ +#define VBOX_CPUID_REQ_EAX_FIXED UINT32_C(0x56426f78) +/** Fixed portion of ECX for all requests. */ +#define VBOX_CPUID_REQ_ECX_FIXED UINT32_C(0xc0de0000) +/** Fixed portion of ECX for all requests. */ +#define VBOX_CPUID_REQ_ECX_FIXED_MASK UINT32_C(0xffff0000) +/** Function part of ECX for requests. */ +#define VBOX_CPUID_REQ_ECX_FN_MASK UINT32_C(0x0000ffff) + +/** Generic ECX return value. */ +#define VBOX_CPUID_RESP_GEN_ECX UINT32_C(0x19410612) +/** Generic EDX return value. */ +#define VBOX_CPUID_RESP_GEN_EDX UINT32_C(0x19400412) +/** Generic EBX return value. */ +#define VBOX_CPUID_RESP_GEN_EBX UINT32_C(0x19450508) + +/** @name Function \#1: Interface ID check and max function. + * + * Input: EDX & EBX content is unused and ignored. Best set to zero. + * + * Result: EAX:EDX:EBX forms the little endian string "VBox RuleZ!\0". + * ECX contains the max function number acccepted. + * @{ */ +#define VBOX_CPUID_FN_ID UINT32_C(0x0001) +#define VBOX_CPUID_RESP_ID_EAX UINT32_C(0x786f4256) +#define VBOX_CPUID_RESP_ID_EDX UINT32_C(0x6c755220) +#define VBOX_CPUID_RESP_ID_EBX UINT32_C(0x00215A65) +#define VBOX_CPUID_RESP_ID_ECX UINT32_C(0x00000002) +/** @} */ + +/** Function \#2: Write string to host Log. + * + * Input: EDX gives the number of bytes to log (max 2MB). + * EBX indicates the log to write to: 0 for debug, 1 for release. + * RSI is the FLAT pointer to the UTF-8 string to log. + * + * Output: EAX contains IPRT status code. ECX, EDX and EBX are set to the + * generic their response values (VBOX_CPUID_RESP_GEN_XXX). RSI is + * advanced EDX bytes on success. + * + * Except: May raise \#PF when reading the string. RSI and EDX is then be + * updated to the point where the page fault triggered, allowing paging + * in of logging buffer and such like. + * + * @note Buffer is not accessed if the target logger isn't enabled. + */ +#define VBOX_CPUID_FN_LOG UINT32_C(0x0002) + + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_cpuidcall_h */ + diff --git a/include/VBox/vmm/cpuidcall.mac b/include/VBox/vmm/cpuidcall.mac new file mode 100644 index 00000000..5965550c --- /dev/null +++ b/include/VBox/vmm/cpuidcall.mac @@ -0,0 +1,55 @@ +;; @file +; VM - The Virtual Machine, CPU Host Call Interface (AMD64 & x86 only). +; +; Automatically generated by various.sed. DO NOT EDIT! +; + +; +; Copyright (C) 2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef VBOX_INCLUDED_vmm_cpuidcall_h +%define VBOX_INCLUDED_vmm_cpuidcall_h +%ifndef RT_WITHOUT_PRAGMA_ONCE +%endif +%define VBOX_CPUID_REQ_EAX_FIXED 0x56426f78 +%define VBOX_CPUID_REQ_ECX_FIXED 0xc0de0000 +%define VBOX_CPUID_REQ_ECX_FIXED_MASK 0xffff0000 +%define VBOX_CPUID_REQ_ECX_FN_MASK 0x0000ffff +%define VBOX_CPUID_RESP_GEN_ECX 0x19410612 +%define VBOX_CPUID_RESP_GEN_EDX 0x19400412 +%define VBOX_CPUID_RESP_GEN_EBX 0x19450508 +%define VBOX_CPUID_FN_ID 0x0001 +%define VBOX_CPUID_RESP_ID_EAX 0x786f4256 +%define VBOX_CPUID_RESP_ID_EDX 0x6c755220 +%define VBOX_CPUID_RESP_ID_EBX 0x00215A65 +%define VBOX_CPUID_RESP_ID_ECX 0x00000002 +%define VBOX_CPUID_FN_LOG 0x0002 +%endif diff --git a/include/VBox/vmm/cpum.h b/include/VBox/vmm/cpum.h new file mode 100644 index 00000000..1f5f28e3 --- /dev/null +++ b/include/VBox/vmm/cpum.h @@ -0,0 +1,3248 @@ +/** @file + * CPUM - CPU Monitor(/ Manager). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpum_h +#define VBOX_INCLUDED_vmm_cpum_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_cpum The CPU Monitor / Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * CPUID feature to set or clear. + */ +typedef enum CPUMCPUIDFEATURE +{ + CPUMCPUIDFEATURE_INVALID = 0, + /** The APIC feature bit. (Std+Ext) + * Note! There is a per-cpu flag for masking this CPUID feature bit when the + * APICBASE.ENABLED bit is zero. So, this feature is only set/cleared + * at VM construction time like all the others. This didn't used to be + * that way, this is new with 5.1. */ + CPUMCPUIDFEATURE_APIC, + /** The sysenter/sysexit feature bit. (Std) */ + CPUMCPUIDFEATURE_SEP, + /** The SYSCALL/SYSEXIT feature bit (64 bits mode only for Intel CPUs). (Ext) */ + CPUMCPUIDFEATURE_SYSCALL, + /** The PAE feature bit. (Std+Ext) */ + CPUMCPUIDFEATURE_PAE, + /** The NX feature bit. (Ext) */ + CPUMCPUIDFEATURE_NX, + /** The LAHF/SAHF feature bit (64 bits mode only). (Ext) */ + CPUMCPUIDFEATURE_LAHF, + /** The LONG MODE feature bit. (Ext) */ + CPUMCPUIDFEATURE_LONG_MODE, + /** The x2APIC feature bit. (Std) */ + CPUMCPUIDFEATURE_X2APIC, + /** The RDTSCP feature bit. (Ext) */ + CPUMCPUIDFEATURE_RDTSCP, + /** The Hypervisor Present bit. (Std) */ + CPUMCPUIDFEATURE_HVP, + /** The speculation control feature bits. (StExt) */ + CPUMCPUIDFEATURE_SPEC_CTRL, + /** 32bit hackishness. */ + CPUMCPUIDFEATURE_32BIT_HACK = 0x7fffffff +} CPUMCPUIDFEATURE; + +/** + * CPU Vendor. + */ +typedef enum CPUMCPUVENDOR +{ + CPUMCPUVENDOR_INVALID = 0, + CPUMCPUVENDOR_INTEL, + CPUMCPUVENDOR_AMD, + CPUMCPUVENDOR_VIA, + CPUMCPUVENDOR_CYRIX, + CPUMCPUVENDOR_SHANGHAI, + CPUMCPUVENDOR_HYGON, + CPUMCPUVENDOR_UNKNOWN, + /** 32bit hackishness. */ + CPUMCPUVENDOR_32BIT_HACK = 0x7fffffff +} CPUMCPUVENDOR; + + +/** + * X86 and AMD64 CPU microarchitectures and in processor generations. + * + * @remarks The separation here is sometimes a little bit too finely grained, + * and the differences is more like processor generation than micro + * arch. This can be useful, so we'll provide functions for getting at + * more coarse grained info. + */ +typedef enum CPUMMICROARCH +{ + kCpumMicroarch_Invalid = 0, + + kCpumMicroarch_Intel_First, + + kCpumMicroarch_Intel_8086 = kCpumMicroarch_Intel_First, + kCpumMicroarch_Intel_80186, + kCpumMicroarch_Intel_80286, + kCpumMicroarch_Intel_80386, + kCpumMicroarch_Intel_80486, + kCpumMicroarch_Intel_P5, + + kCpumMicroarch_Intel_P6_Core_Atom_First, + kCpumMicroarch_Intel_P6 = kCpumMicroarch_Intel_P6_Core_Atom_First, + kCpumMicroarch_Intel_P6_II, + kCpumMicroarch_Intel_P6_III, + + kCpumMicroarch_Intel_P6_M_Banias, + kCpumMicroarch_Intel_P6_M_Dothan, + kCpumMicroarch_Intel_Core_Yonah, /**< Core, also known as Enhanced Pentium M. */ + + kCpumMicroarch_Intel_Core2_First, + kCpumMicroarch_Intel_Core2_Merom = kCpumMicroarch_Intel_Core2_First, /**< 65nm, Merom/Conroe/Kentsfield/Tigerton */ + kCpumMicroarch_Intel_Core2_Penryn, /**< 45nm, Penryn/Wolfdale/Yorkfield/Harpertown */ + kCpumMicroarch_Intel_Core2_End, + + kCpumMicroarch_Intel_Core7_First, + kCpumMicroarch_Intel_Core7_Nehalem = kCpumMicroarch_Intel_Core7_First, + kCpumMicroarch_Intel_Core7_Westmere, + kCpumMicroarch_Intel_Core7_SandyBridge, + kCpumMicroarch_Intel_Core7_IvyBridge, + kCpumMicroarch_Intel_Core7_Haswell, + kCpumMicroarch_Intel_Core7_Broadwell, + kCpumMicroarch_Intel_Core7_Skylake, + kCpumMicroarch_Intel_Core7_KabyLake, + kCpumMicroarch_Intel_Core7_CoffeeLake, + kCpumMicroarch_Intel_Core7_WhiskeyLake, + kCpumMicroarch_Intel_Core7_CascadeLake, + kCpumMicroarch_Intel_Core7_CannonLake, /**< Limited 10nm. */ + kCpumMicroarch_Intel_Core7_CometLake, /**< 10th gen, 14nm desktop + high power mobile. */ + kCpumMicroarch_Intel_Core7_IceLake, /**< 10th gen, 10nm mobile and some Xeons. Actually 'Sunny Cove' march. */ + kCpumMicroarch_Intel_Core7_SunnyCove = kCpumMicroarch_Intel_Core7_IceLake, + kCpumMicroarch_Intel_Core7_RocketLake, /**< 11th gen, 14nm desktop + high power mobile. Aka 'Cypress Cove', backport of 'Willow Cove' to 14nm. */ + kCpumMicroarch_Intel_Core7_CypressCove = kCpumMicroarch_Intel_Core7_RocketLake, + kCpumMicroarch_Intel_Core7_TigerLake, /**< 11th gen, 10nm mobile. Actually 'Willow Cove' march. */ + kCpumMicroarch_Intel_Core7_WillowCove = kCpumMicroarch_Intel_Core7_TigerLake, + kCpumMicroarch_Intel_Core7_AlderLake, /**< 12th gen, 10nm all platforms(?). */ + kCpumMicroarch_Intel_Core7_SapphireRapids, /**< 12th? gen, 10nm server? */ + kCpumMicroarch_Intel_Core7_End, + + kCpumMicroarch_Intel_Atom_First, + kCpumMicroarch_Intel_Atom_Bonnell = kCpumMicroarch_Intel_Atom_First, + kCpumMicroarch_Intel_Atom_Lincroft, /**< Second generation bonnell (44nm). */ + kCpumMicroarch_Intel_Atom_Saltwell, /**< 32nm shrink of Bonnell. */ + kCpumMicroarch_Intel_Atom_Silvermont, /**< 22nm */ + kCpumMicroarch_Intel_Atom_Airmount, /**< 14nm */ + kCpumMicroarch_Intel_Atom_Goldmont, /**< 14nm */ + kCpumMicroarch_Intel_Atom_GoldmontPlus, /**< 14nm */ + kCpumMicroarch_Intel_Atom_Unknown, + kCpumMicroarch_Intel_Atom_End, + + + kCpumMicroarch_Intel_Phi_First, + kCpumMicroarch_Intel_Phi_KnightsFerry = kCpumMicroarch_Intel_Phi_First, + kCpumMicroarch_Intel_Phi_KnightsCorner, + kCpumMicroarch_Intel_Phi_KnightsLanding, + kCpumMicroarch_Intel_Phi_KnightsHill, + kCpumMicroarch_Intel_Phi_KnightsMill, + kCpumMicroarch_Intel_Phi_End, + + kCpumMicroarch_Intel_P6_Core_Atom_End, + + kCpumMicroarch_Intel_NB_First, + kCpumMicroarch_Intel_NB_Willamette = kCpumMicroarch_Intel_NB_First, /**< 180nm */ + kCpumMicroarch_Intel_NB_Northwood, /**< 130nm */ + kCpumMicroarch_Intel_NB_Prescott, /**< 90nm */ + kCpumMicroarch_Intel_NB_Prescott2M, /**< 90nm */ + kCpumMicroarch_Intel_NB_CedarMill, /**< 65nm */ + kCpumMicroarch_Intel_NB_Gallatin, /**< 90nm Xeon, Pentium 4 Extreme Edition ("Emergency Edition"). */ + kCpumMicroarch_Intel_NB_Unknown, + kCpumMicroarch_Intel_NB_End, + + kCpumMicroarch_Intel_Unknown, + kCpumMicroarch_Intel_End, + + kCpumMicroarch_AMD_First, + kCpumMicroarch_AMD_Am286 = kCpumMicroarch_AMD_First, + kCpumMicroarch_AMD_Am386, + kCpumMicroarch_AMD_Am486, + kCpumMicroarch_AMD_Am486Enh, /**< Covers Am5x86 as well. */ + kCpumMicroarch_AMD_K5, + kCpumMicroarch_AMD_K6, + + kCpumMicroarch_AMD_K7_First, + kCpumMicroarch_AMD_K7_Palomino = kCpumMicroarch_AMD_K7_First, + kCpumMicroarch_AMD_K7_Spitfire, + kCpumMicroarch_AMD_K7_Thunderbird, + kCpumMicroarch_AMD_K7_Morgan, + kCpumMicroarch_AMD_K7_Thoroughbred, + kCpumMicroarch_AMD_K7_Barton, + kCpumMicroarch_AMD_K7_Unknown, + kCpumMicroarch_AMD_K7_End, + + kCpumMicroarch_AMD_K8_First, + kCpumMicroarch_AMD_K8_130nm = kCpumMicroarch_AMD_K8_First, /**< 130nm Clawhammer, Sledgehammer, Newcastle, Paris, Odessa, Dublin */ + kCpumMicroarch_AMD_K8_90nm, /**< 90nm shrink */ + kCpumMicroarch_AMD_K8_90nm_DualCore, /**< 90nm with two cores. */ + kCpumMicroarch_AMD_K8_90nm_AMDV, /**< 90nm with AMD-V (usually) and two cores (usually). */ + kCpumMicroarch_AMD_K8_65nm, /**< 65nm shrink. */ + kCpumMicroarch_AMD_K8_End, + + kCpumMicroarch_AMD_K10, + kCpumMicroarch_AMD_K10_Lion, + kCpumMicroarch_AMD_K10_Llano, + kCpumMicroarch_AMD_Bobcat, + kCpumMicroarch_AMD_Jaguar, + + kCpumMicroarch_AMD_15h_First, + kCpumMicroarch_AMD_15h_Bulldozer = kCpumMicroarch_AMD_15h_First, + kCpumMicroarch_AMD_15h_Piledriver, + kCpumMicroarch_AMD_15h_Steamroller, /**< Yet to be released, might have different family. */ + kCpumMicroarch_AMD_15h_Excavator, /**< Yet to be released, might have different family. */ + kCpumMicroarch_AMD_15h_Unknown, + kCpumMicroarch_AMD_15h_End, + + kCpumMicroarch_AMD_16h_First, + kCpumMicroarch_AMD_16h_End, + + kCpumMicroarch_AMD_Zen_First, + kCpumMicroarch_AMD_Zen_Ryzen = kCpumMicroarch_AMD_Zen_First, + kCpumMicroarch_AMD_Zen_End, + + kCpumMicroarch_AMD_Unknown, + kCpumMicroarch_AMD_End, + + kCpumMicroarch_Hygon_First, + kCpumMicroarch_Hygon_Dhyana = kCpumMicroarch_Hygon_First, + kCpumMicroarch_Hygon_Unknown, + kCpumMicroarch_Hygon_End, + + kCpumMicroarch_VIA_First, + kCpumMicroarch_Centaur_C6 = kCpumMicroarch_VIA_First, + kCpumMicroarch_Centaur_C2, + kCpumMicroarch_Centaur_C3, + kCpumMicroarch_VIA_C3_M2, + kCpumMicroarch_VIA_C3_C5A, /**< 180nm Samuel - Cyrix III, C3, 1GigaPro. */ + kCpumMicroarch_VIA_C3_C5B, /**< 150nm Samuel 2 - Cyrix III, C3, 1GigaPro, Eden ESP, XP 2000+. */ + kCpumMicroarch_VIA_C3_C5C, /**< 130nm Ezra - C3, Eden ESP. */ + kCpumMicroarch_VIA_C3_C5N, /**< 130nm Ezra-T - C3. */ + kCpumMicroarch_VIA_C3_C5XL, /**< 130nm Nehemiah - C3, Eden ESP, Eden-N. */ + kCpumMicroarch_VIA_C3_C5P, /**< 130nm Nehemiah+ - C3. */ + kCpumMicroarch_VIA_C7_C5J, /**< 90nm Esther - C7, C7-D, C7-M, Eden, Eden ULV. */ + kCpumMicroarch_VIA_Isaiah, + kCpumMicroarch_VIA_Unknown, + kCpumMicroarch_VIA_End, + + kCpumMicroarch_Shanghai_First, + kCpumMicroarch_Shanghai_Wudaokou = kCpumMicroarch_Shanghai_First, + kCpumMicroarch_Shanghai_Unknown, + kCpumMicroarch_Shanghai_End, + + kCpumMicroarch_Cyrix_First, + kCpumMicroarch_Cyrix_5x86 = kCpumMicroarch_Cyrix_First, + kCpumMicroarch_Cyrix_M1, + kCpumMicroarch_Cyrix_MediaGX, + kCpumMicroarch_Cyrix_MediaGXm, + kCpumMicroarch_Cyrix_M2, + kCpumMicroarch_Cyrix_Unknown, + kCpumMicroarch_Cyrix_End, + + kCpumMicroarch_NEC_First, + kCpumMicroarch_NEC_V20 = kCpumMicroarch_NEC_First, + kCpumMicroarch_NEC_V30, + kCpumMicroarch_NEC_End, + + kCpumMicroarch_Unknown, + + kCpumMicroarch_32BitHack = 0x7fffffff +} CPUMMICROARCH; + + +/** Predicate macro for catching netburst CPUs. */ +#define CPUMMICROARCH_IS_INTEL_NETBURST(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_Intel_NB_First && (a_enmMicroarch) <= kCpumMicroarch_Intel_NB_End) + +/** Predicate macro for catching Core7 CPUs. */ +#define CPUMMICROARCH_IS_INTEL_CORE7(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_Intel_Core7_First && (a_enmMicroarch) <= kCpumMicroarch_Intel_Core7_End) + +/** Predicate macro for catching Core 2 CPUs. */ +#define CPUMMICROARCH_IS_INTEL_CORE2(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_Intel_Core2_First && (a_enmMicroarch) <= kCpumMicroarch_Intel_Core2_End) + +/** Predicate macro for catching Atom CPUs, Silvermont and upwards. */ +#define CPUMMICROARCH_IS_INTEL_SILVERMONT_PLUS(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_Intel_Atom_Silvermont && (a_enmMicroarch) <= kCpumMicroarch_Intel_Atom_End) + +/** Predicate macro for catching AMD Family OFh CPUs (aka K8). */ +#define CPUMMICROARCH_IS_AMD_FAM_0FH(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_AMD_K8_First && (a_enmMicroarch) <= kCpumMicroarch_AMD_K8_End) + +/** Predicate macro for catching AMD Family 10H CPUs (aka K10). */ +#define CPUMMICROARCH_IS_AMD_FAM_10H(a_enmMicroarch) ((a_enmMicroarch) == kCpumMicroarch_AMD_K10) + +/** Predicate macro for catching AMD Family 11H CPUs (aka Lion). */ +#define CPUMMICROARCH_IS_AMD_FAM_11H(a_enmMicroarch) ((a_enmMicroarch) == kCpumMicroarch_AMD_K10_Lion) + +/** Predicate macro for catching AMD Family 12H CPUs (aka Llano). */ +#define CPUMMICROARCH_IS_AMD_FAM_12H(a_enmMicroarch) ((a_enmMicroarch) == kCpumMicroarch_AMD_K10_Llano) + +/** Predicate macro for catching AMD Family 14H CPUs (aka Bobcat). */ +#define CPUMMICROARCH_IS_AMD_FAM_14H(a_enmMicroarch) ((a_enmMicroarch) == kCpumMicroarch_AMD_Bobcat) + +/** Predicate macro for catching AMD Family 15H CPUs (bulldozer and it's + * decendants). */ +#define CPUMMICROARCH_IS_AMD_FAM_15H(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_AMD_15h_First && (a_enmMicroarch) <= kCpumMicroarch_AMD_15h_End) + +/** Predicate macro for catching AMD Family 16H CPUs. */ +#define CPUMMICROARCH_IS_AMD_FAM_16H(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_AMD_16h_First && (a_enmMicroarch) <= kCpumMicroarch_AMD_16h_End) + +/** Predicate macro for catching AMD Zen Family CPUs. */ +#define CPUMMICROARCH_IS_AMD_FAM_ZEN(a_enmMicroarch) \ + ((a_enmMicroarch) >= kCpumMicroarch_AMD_Zen_First && (a_enmMicroarch) <= kCpumMicroarch_AMD_Zen_End) + + +/** + * CPUID leaf. + * + * @remarks This structure is used by the patch manager and is therefore + * more or less set in stone. + */ +typedef struct CPUMCPUIDLEAF +{ + /** The leaf number. */ + uint32_t uLeaf; + /** The sub-leaf number. */ + uint32_t uSubLeaf; + /** Sub-leaf mask. This is 0 when sub-leaves aren't used. */ + uint32_t fSubLeafMask; + + /** The EAX value. */ + uint32_t uEax; + /** The EBX value. */ + uint32_t uEbx; + /** The ECX value. */ + uint32_t uEcx; + /** The EDX value. */ + uint32_t uEdx; + + /** Flags. */ + uint32_t fFlags; +} CPUMCPUIDLEAF; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMCPUIDLEAF, 32); +#endif +/** Pointer to a CPUID leaf. */ +typedef CPUMCPUIDLEAF *PCPUMCPUIDLEAF; +/** Pointer to a const CPUID leaf. */ +typedef CPUMCPUIDLEAF const *PCCPUMCPUIDLEAF; + +/** @name CPUMCPUIDLEAF::fFlags + * @{ */ +/** Indicates working intel leaf 0xb where the lower 8 ECX bits are not modified + * and EDX containing the extended APIC ID. */ +#define CPUMCPUIDLEAF_F_INTEL_TOPOLOGY_SUBLEAVES RT_BIT_32(0) +/** The leaf contains an APIC ID that needs changing to that of the current CPU. */ +#define CPUMCPUIDLEAF_F_CONTAINS_APIC_ID RT_BIT_32(1) +/** The leaf contains an OSXSAVE which needs individual handling on each CPU. */ +#define CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE RT_BIT_32(2) +/** The leaf contains an APIC feature bit which is tied to APICBASE.EN. */ +#define CPUMCPUIDLEAF_F_CONTAINS_APIC RT_BIT_32(3) +/** Mask of the valid flags. */ +#define CPUMCPUIDLEAF_F_VALID_MASK UINT32_C(0xf) +/** @} */ + +/** + * Method used to deal with unknown CPUID leaves. + * @remarks Used in patch code. + */ +typedef enum CPUMUNKNOWNCPUID +{ + /** Invalid zero value. */ + CPUMUNKNOWNCPUID_INVALID = 0, + /** Use given default values (DefCpuId). */ + CPUMUNKNOWNCPUID_DEFAULTS, + /** Return the last standard leaf. + * Intel Sandy Bridge has been observed doing this. */ + CPUMUNKNOWNCPUID_LAST_STD_LEAF, + /** Return the last standard leaf, with ecx observed. + * Intel Sandy Bridge has been observed doing this. */ + CPUMUNKNOWNCPUID_LAST_STD_LEAF_WITH_ECX, + /** The register values are passed thru unmodified. */ + CPUMUNKNOWNCPUID_PASSTHRU, + /** End of valid value. */ + CPUMUNKNOWNCPUID_END, + /** Ensure 32-bit type. */ + CPUMUNKNOWNCPUID_32BIT_HACK = 0x7fffffff +} CPUMUNKNOWNCPUID; +/** Pointer to unknown CPUID leaf method. */ +typedef CPUMUNKNOWNCPUID *PCPUMUNKNOWNCPUID; + + +/** + * The register set returned by a CPUID operation. + */ +typedef struct CPUMCPUID +{ + uint32_t uEax; + uint32_t uEbx; + uint32_t uEcx; + uint32_t uEdx; +} CPUMCPUID; +/** Pointer to a CPUID leaf. */ +typedef CPUMCPUID *PCPUMCPUID; +/** Pointer to a const CPUID leaf. */ +typedef const CPUMCPUID *PCCPUMCPUID; + + +/** + * MSR read functions. + */ +typedef enum CPUMMSRRDFN +{ + /** Invalid zero value. */ + kCpumMsrRdFn_Invalid = 0, + /** Return the CPUMMSRRANGE::uValue. */ + kCpumMsrRdFn_FixedValue, + /** Alias to the MSR range starting at the MSR given by + * CPUMMSRRANGE::uValue. Must be used in pair with + * kCpumMsrWrFn_MsrAlias. */ + kCpumMsrRdFn_MsrAlias, + /** Write only register, GP all read attempts. */ + kCpumMsrRdFn_WriteOnly, + + kCpumMsrRdFn_Ia32P5McAddr, + kCpumMsrRdFn_Ia32P5McType, + kCpumMsrRdFn_Ia32TimestampCounter, + kCpumMsrRdFn_Ia32PlatformId, /**< Takes real CPU value for reference. */ + kCpumMsrRdFn_Ia32ApicBase, + kCpumMsrRdFn_Ia32FeatureControl, + kCpumMsrRdFn_Ia32BiosSignId, /**< Range value returned. */ + kCpumMsrRdFn_Ia32SmmMonitorCtl, + kCpumMsrRdFn_Ia32PmcN, + kCpumMsrRdFn_Ia32MonitorFilterLineSize, + kCpumMsrRdFn_Ia32MPerf, + kCpumMsrRdFn_Ia32APerf, + kCpumMsrRdFn_Ia32MtrrCap, /**< Takes real CPU value for reference. */ + kCpumMsrRdFn_Ia32MtrrPhysBaseN, /**< Takes register number. */ + kCpumMsrRdFn_Ia32MtrrPhysMaskN, /**< Takes register number. */ + kCpumMsrRdFn_Ia32MtrrFixed, /**< Takes CPUMCPU offset. */ + kCpumMsrRdFn_Ia32MtrrDefType, + kCpumMsrRdFn_Ia32Pat, + kCpumMsrRdFn_Ia32SysEnterCs, + kCpumMsrRdFn_Ia32SysEnterEsp, + kCpumMsrRdFn_Ia32SysEnterEip, + kCpumMsrRdFn_Ia32McgCap, + kCpumMsrRdFn_Ia32McgStatus, + kCpumMsrRdFn_Ia32McgCtl, + kCpumMsrRdFn_Ia32DebugCtl, + kCpumMsrRdFn_Ia32SmrrPhysBase, + kCpumMsrRdFn_Ia32SmrrPhysMask, + kCpumMsrRdFn_Ia32PlatformDcaCap, + kCpumMsrRdFn_Ia32CpuDcaCap, + kCpumMsrRdFn_Ia32Dca0Cap, + kCpumMsrRdFn_Ia32PerfEvtSelN, /**< Range value indicates the register number. */ + kCpumMsrRdFn_Ia32PerfStatus, /**< Range value returned. */ + kCpumMsrRdFn_Ia32PerfCtl, /**< Range value returned. */ + kCpumMsrRdFn_Ia32FixedCtrN, /**< Takes register number of start of range. */ + kCpumMsrRdFn_Ia32PerfCapabilities, /**< Takes reference value. */ + kCpumMsrRdFn_Ia32FixedCtrCtrl, + kCpumMsrRdFn_Ia32PerfGlobalStatus, /**< Takes reference value. */ + kCpumMsrRdFn_Ia32PerfGlobalCtrl, + kCpumMsrRdFn_Ia32PerfGlobalOvfCtrl, + kCpumMsrRdFn_Ia32PebsEnable, + kCpumMsrRdFn_Ia32ClockModulation, /**< Range value returned. */ + kCpumMsrRdFn_Ia32ThermInterrupt, /**< Range value returned. */ + kCpumMsrRdFn_Ia32ThermStatus, /**< Range value returned. */ + kCpumMsrRdFn_Ia32Therm2Ctl, /**< Range value returned. */ + kCpumMsrRdFn_Ia32MiscEnable, /**< Range value returned. */ + kCpumMsrRdFn_Ia32McCtlStatusAddrMiscN, /**< Takes bank number. */ + kCpumMsrRdFn_Ia32McNCtl2, /**< Takes register number of start of range. */ + kCpumMsrRdFn_Ia32DsArea, + kCpumMsrRdFn_Ia32TscDeadline, + kCpumMsrRdFn_Ia32X2ApicN, + kCpumMsrRdFn_Ia32DebugInterface, + kCpumMsrRdFn_Ia32VmxBasic, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxPinbasedCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxProcbasedCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxExitCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxEntryCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxMisc, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxCr0Fixed0, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxCr0Fixed1, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxCr4Fixed0, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxCr4Fixed1, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxVmcsEnum, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxProcBasedCtls2, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxEptVpidCap, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxTruePinbasedCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxTrueProcbasedCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxTrueExitCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxTrueEntryCtls, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32VmxVmFunc, /**< Takes real value as reference. */ + kCpumMsrRdFn_Ia32SpecCtrl, + kCpumMsrRdFn_Ia32ArchCapabilities, + + kCpumMsrRdFn_Amd64Efer, + kCpumMsrRdFn_Amd64SyscallTarget, + kCpumMsrRdFn_Amd64LongSyscallTarget, + kCpumMsrRdFn_Amd64CompSyscallTarget, + kCpumMsrRdFn_Amd64SyscallFlagMask, + kCpumMsrRdFn_Amd64FsBase, + kCpumMsrRdFn_Amd64GsBase, + kCpumMsrRdFn_Amd64KernelGsBase, + kCpumMsrRdFn_Amd64TscAux, + + kCpumMsrRdFn_IntelEblCrPowerOn, + kCpumMsrRdFn_IntelI7CoreThreadCount, + kCpumMsrRdFn_IntelP4EbcHardPowerOn, + kCpumMsrRdFn_IntelP4EbcSoftPowerOn, + kCpumMsrRdFn_IntelP4EbcFrequencyId, + kCpumMsrRdFn_IntelP6FsbFrequency, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelPlatformInfo, + kCpumMsrRdFn_IntelFlexRatio, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelPkgCStConfigControl, + kCpumMsrRdFn_IntelPmgIoCaptureBase, + kCpumMsrRdFn_IntelLastBranchFromToN, + kCpumMsrRdFn_IntelLastBranchFromN, + kCpumMsrRdFn_IntelLastBranchToN, + kCpumMsrRdFn_IntelLastBranchTos, + kCpumMsrRdFn_IntelBblCrCtl, + kCpumMsrRdFn_IntelBblCrCtl3, + kCpumMsrRdFn_IntelI7TemperatureTarget, /**< Range value returned. */ + kCpumMsrRdFn_IntelI7MsrOffCoreResponseN,/**< Takes register number. */ + kCpumMsrRdFn_IntelI7MiscPwrMgmt, + kCpumMsrRdFn_IntelP6CrN, + kCpumMsrRdFn_IntelCpuId1FeatureMaskEcdx, + kCpumMsrRdFn_IntelCpuId1FeatureMaskEax, + kCpumMsrRdFn_IntelCpuId80000001FeatureMaskEcdx, + kCpumMsrRdFn_IntelI7SandyAesNiCtl, + kCpumMsrRdFn_IntelI7TurboRatioLimit, /**< Returns range value. */ + kCpumMsrRdFn_IntelI7LbrSelect, + kCpumMsrRdFn_IntelI7SandyErrorControl, + kCpumMsrRdFn_IntelI7VirtualLegacyWireCap,/**< Returns range value. */ + kCpumMsrRdFn_IntelI7PowerCtl, + kCpumMsrRdFn_IntelI7SandyPebsNumAlt, + kCpumMsrRdFn_IntelI7PebsLdLat, + kCpumMsrRdFn_IntelI7PkgCnResidencyN, /**< Takes C-state number. */ + kCpumMsrRdFn_IntelI7CoreCnResidencyN, /**< Takes C-state number. */ + kCpumMsrRdFn_IntelI7SandyVrCurrentConfig,/**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7SandyVrMiscConfig, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7SandyRaplPowerUnit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7SandyPkgCnIrtlN, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7SandyPkgC2Residency, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPkgPowerLimit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPkgEnergyStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPkgPerfStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPkgPowerInfo, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplDramPowerLimit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplDramEnergyStatus,/**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplDramPerfStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplDramPowerInfo, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp0PowerLimit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp0EnergyStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp0Policy, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp0PerfStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp1PowerLimit, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp1EnergyStatus, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7RaplPp1Policy, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7IvyConfigTdpNominal, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7IvyConfigTdpLevel1, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7IvyConfigTdpLevel2, /**< Takes real value as reference. */ + kCpumMsrRdFn_IntelI7IvyConfigTdpControl, + kCpumMsrRdFn_IntelI7IvyTurboActivationRatio, + kCpumMsrRdFn_IntelI7UncPerfGlobalCtrl, + kCpumMsrRdFn_IntelI7UncPerfGlobalStatus, + kCpumMsrRdFn_IntelI7UncPerfGlobalOvfCtrl, + kCpumMsrRdFn_IntelI7UncPerfFixedCtrCtrl, + kCpumMsrRdFn_IntelI7UncPerfFixedCtr, + kCpumMsrRdFn_IntelI7UncCBoxConfig, + kCpumMsrRdFn_IntelI7UncArbPerfCtrN, + kCpumMsrRdFn_IntelI7UncArbPerfEvtSelN, + kCpumMsrRdFn_IntelI7SmiCount, + kCpumMsrRdFn_IntelCore2EmttmCrTablesN, /**< Range value returned. */ + kCpumMsrRdFn_IntelCore2SmmCStMiscInfo, + kCpumMsrRdFn_IntelCore1ExtConfig, + kCpumMsrRdFn_IntelCore1DtsCalControl, + kCpumMsrRdFn_IntelCore2PeciControl, + kCpumMsrRdFn_IntelAtSilvCoreC1Recidency, + + kCpumMsrRdFn_P6LastBranchFromIp, + kCpumMsrRdFn_P6LastBranchToIp, + kCpumMsrRdFn_P6LastIntFromIp, + kCpumMsrRdFn_P6LastIntToIp, + + kCpumMsrRdFn_AmdFam15hTscRate, + kCpumMsrRdFn_AmdFam15hLwpCfg, + kCpumMsrRdFn_AmdFam15hLwpCbAddr, + kCpumMsrRdFn_AmdFam10hMc4MiscN, + kCpumMsrRdFn_AmdK8PerfCtlN, + kCpumMsrRdFn_AmdK8PerfCtrN, + kCpumMsrRdFn_AmdK8SysCfg, /**< Range value returned. */ + kCpumMsrRdFn_AmdK8HwCr, + kCpumMsrRdFn_AmdK8IorrBaseN, + kCpumMsrRdFn_AmdK8IorrMaskN, + kCpumMsrRdFn_AmdK8TopOfMemN, + kCpumMsrRdFn_AmdK8NbCfg1, + kCpumMsrRdFn_AmdK8McXcptRedir, + kCpumMsrRdFn_AmdK8CpuNameN, + kCpumMsrRdFn_AmdK8HwThermalCtrl, /**< Range value returned. */ + kCpumMsrRdFn_AmdK8SwThermalCtrl, + kCpumMsrRdFn_AmdK8FidVidControl, /**< Range value returned. */ + kCpumMsrRdFn_AmdK8FidVidStatus, /**< Range value returned. */ + kCpumMsrRdFn_AmdK8McCtlMaskN, + kCpumMsrRdFn_AmdK8SmiOnIoTrapN, + kCpumMsrRdFn_AmdK8SmiOnIoTrapCtlSts, + kCpumMsrRdFn_AmdK8IntPendingMessage, + kCpumMsrRdFn_AmdK8SmiTriggerIoCycle, + kCpumMsrRdFn_AmdFam10hMmioCfgBaseAddr, + kCpumMsrRdFn_AmdFam10hTrapCtlMaybe, + kCpumMsrRdFn_AmdFam10hPStateCurLimit, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hPStateControl, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hPStateStatus, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hPStateN, /**< Returns range value. This isn't an register index! */ + kCpumMsrRdFn_AmdFam10hCofVidControl, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hCofVidStatus, /**< Returns range value. */ + kCpumMsrRdFn_AmdFam10hCStateIoBaseAddr, + kCpumMsrRdFn_AmdFam10hCpuWatchdogTimer, + kCpumMsrRdFn_AmdK8SmmBase, + kCpumMsrRdFn_AmdK8SmmAddr, + kCpumMsrRdFn_AmdK8SmmMask, + kCpumMsrRdFn_AmdK8VmCr, + kCpumMsrRdFn_AmdK8IgnNe, + kCpumMsrRdFn_AmdK8SmmCtl, + kCpumMsrRdFn_AmdK8VmHSavePa, + kCpumMsrRdFn_AmdFam10hVmLockKey, + kCpumMsrRdFn_AmdFam10hSmmLockKey, + kCpumMsrRdFn_AmdFam10hLocalSmiStatus, + kCpumMsrRdFn_AmdFam10hOsVisWrkIdLength, + kCpumMsrRdFn_AmdFam10hOsVisWrkStatus, + kCpumMsrRdFn_AmdFam16hL2IPerfCtlN, + kCpumMsrRdFn_AmdFam16hL2IPerfCtrN, + kCpumMsrRdFn_AmdFam15hNorthbridgePerfCtlN, + kCpumMsrRdFn_AmdFam15hNorthbridgePerfCtrN, + kCpumMsrRdFn_AmdK7MicrocodeCtl, /**< Returns range value. */ + kCpumMsrRdFn_AmdK7ClusterIdMaybe, /**< Returns range value. */ + kCpumMsrRdFn_AmdK8CpuIdCtlStd07hEbax, + kCpumMsrRdFn_AmdK8CpuIdCtlStd06hEcx, + kCpumMsrRdFn_AmdK8CpuIdCtlStd01hEdcx, + kCpumMsrRdFn_AmdK8CpuIdCtlExt01hEdcx, + kCpumMsrRdFn_AmdK8PatchLevel, /**< Returns range value. */ + kCpumMsrRdFn_AmdK7DebugStatusMaybe, + kCpumMsrRdFn_AmdK7BHTraceBaseMaybe, + kCpumMsrRdFn_AmdK7BHTracePtrMaybe, + kCpumMsrRdFn_AmdK7BHTraceLimitMaybe, + kCpumMsrRdFn_AmdK7HardwareDebugToolCfgMaybe, + kCpumMsrRdFn_AmdK7FastFlushCountMaybe, + kCpumMsrRdFn_AmdK7NodeId, + kCpumMsrRdFn_AmdK7DrXAddrMaskN, /**< Takes register index. */ + kCpumMsrRdFn_AmdK7Dr0DataMatchMaybe, + kCpumMsrRdFn_AmdK7Dr0DataMaskMaybe, + kCpumMsrRdFn_AmdK7LoadStoreCfg, + kCpumMsrRdFn_AmdK7InstrCacheCfg, + kCpumMsrRdFn_AmdK7DataCacheCfg, + kCpumMsrRdFn_AmdK7BusUnitCfg, + kCpumMsrRdFn_AmdK7DebugCtl2Maybe, + kCpumMsrRdFn_AmdFam15hFpuCfg, + kCpumMsrRdFn_AmdFam15hDecoderCfg, + kCpumMsrRdFn_AmdFam10hBusUnitCfg2, + kCpumMsrRdFn_AmdFam15hCombUnitCfg, + kCpumMsrRdFn_AmdFam15hCombUnitCfg2, + kCpumMsrRdFn_AmdFam15hCombUnitCfg3, + kCpumMsrRdFn_AmdFam15hExecUnitCfg, + kCpumMsrRdFn_AmdFam15hLoadStoreCfg2, + kCpumMsrRdFn_AmdFam10hIbsFetchCtl, + kCpumMsrRdFn_AmdFam10hIbsFetchLinAddr, + kCpumMsrRdFn_AmdFam10hIbsFetchPhysAddr, + kCpumMsrRdFn_AmdFam10hIbsOpExecCtl, + kCpumMsrRdFn_AmdFam10hIbsOpRip, + kCpumMsrRdFn_AmdFam10hIbsOpData, + kCpumMsrRdFn_AmdFam10hIbsOpData2, + kCpumMsrRdFn_AmdFam10hIbsOpData3, + kCpumMsrRdFn_AmdFam10hIbsDcLinAddr, + kCpumMsrRdFn_AmdFam10hIbsDcPhysAddr, + kCpumMsrRdFn_AmdFam10hIbsCtl, + kCpumMsrRdFn_AmdFam14hIbsBrTarget, + + kCpumMsrRdFn_Gim, + + /** End of valid MSR read function indexes. */ + kCpumMsrRdFn_End +} CPUMMSRRDFN; + +/** + * MSR write functions. + */ +typedef enum CPUMMSRWRFN +{ + /** Invalid zero value. */ + kCpumMsrWrFn_Invalid = 0, + /** Writes are ignored, the fWrGpMask is observed though. */ + kCpumMsrWrFn_IgnoreWrite, + /** Writes cause GP(0) to be raised, the fWrGpMask should be UINT64_MAX. */ + kCpumMsrWrFn_ReadOnly, + /** Alias to the MSR range starting at the MSR given by + * CPUMMSRRANGE::uValue. Must be used in pair with + * kCpumMsrRdFn_MsrAlias. */ + kCpumMsrWrFn_MsrAlias, + + kCpumMsrWrFn_Ia32P5McAddr, + kCpumMsrWrFn_Ia32P5McType, + kCpumMsrWrFn_Ia32TimestampCounter, + kCpumMsrWrFn_Ia32ApicBase, + kCpumMsrWrFn_Ia32FeatureControl, + kCpumMsrWrFn_Ia32BiosSignId, + kCpumMsrWrFn_Ia32BiosUpdateTrigger, + kCpumMsrWrFn_Ia32SmmMonitorCtl, + kCpumMsrWrFn_Ia32PmcN, + kCpumMsrWrFn_Ia32MonitorFilterLineSize, + kCpumMsrWrFn_Ia32MPerf, + kCpumMsrWrFn_Ia32APerf, + kCpumMsrWrFn_Ia32MtrrPhysBaseN, /**< Takes register number. */ + kCpumMsrWrFn_Ia32MtrrPhysMaskN, /**< Takes register number. */ + kCpumMsrWrFn_Ia32MtrrFixed, /**< Takes CPUMCPU offset. */ + kCpumMsrWrFn_Ia32MtrrDefType, + kCpumMsrWrFn_Ia32Pat, + kCpumMsrWrFn_Ia32SysEnterCs, + kCpumMsrWrFn_Ia32SysEnterEsp, + kCpumMsrWrFn_Ia32SysEnterEip, + kCpumMsrWrFn_Ia32McgStatus, + kCpumMsrWrFn_Ia32McgCtl, + kCpumMsrWrFn_Ia32DebugCtl, + kCpumMsrWrFn_Ia32SmrrPhysBase, + kCpumMsrWrFn_Ia32SmrrPhysMask, + kCpumMsrWrFn_Ia32PlatformDcaCap, + kCpumMsrWrFn_Ia32Dca0Cap, + kCpumMsrWrFn_Ia32PerfEvtSelN, /**< Range value indicates the register number. */ + kCpumMsrWrFn_Ia32PerfStatus, + kCpumMsrWrFn_Ia32PerfCtl, + kCpumMsrWrFn_Ia32FixedCtrN, /**< Takes register number of start of range. */ + kCpumMsrWrFn_Ia32PerfCapabilities, + kCpumMsrWrFn_Ia32FixedCtrCtrl, + kCpumMsrWrFn_Ia32PerfGlobalStatus, + kCpumMsrWrFn_Ia32PerfGlobalCtrl, + kCpumMsrWrFn_Ia32PerfGlobalOvfCtrl, + kCpumMsrWrFn_Ia32PebsEnable, + kCpumMsrWrFn_Ia32ClockModulation, + kCpumMsrWrFn_Ia32ThermInterrupt, + kCpumMsrWrFn_Ia32ThermStatus, + kCpumMsrWrFn_Ia32Therm2Ctl, + kCpumMsrWrFn_Ia32MiscEnable, + kCpumMsrWrFn_Ia32McCtlStatusAddrMiscN, /**< Takes bank number. */ + kCpumMsrWrFn_Ia32McNCtl2, /**< Takes register number of start of range. */ + kCpumMsrWrFn_Ia32DsArea, + kCpumMsrWrFn_Ia32TscDeadline, + kCpumMsrWrFn_Ia32X2ApicN, + kCpumMsrWrFn_Ia32DebugInterface, + kCpumMsrWrFn_Ia32SpecCtrl, + kCpumMsrWrFn_Ia32PredCmd, + kCpumMsrWrFn_Ia32FlushCmd, + + kCpumMsrWrFn_Amd64Efer, + kCpumMsrWrFn_Amd64SyscallTarget, + kCpumMsrWrFn_Amd64LongSyscallTarget, + kCpumMsrWrFn_Amd64CompSyscallTarget, + kCpumMsrWrFn_Amd64SyscallFlagMask, + kCpumMsrWrFn_Amd64FsBase, + kCpumMsrWrFn_Amd64GsBase, + kCpumMsrWrFn_Amd64KernelGsBase, + kCpumMsrWrFn_Amd64TscAux, + kCpumMsrWrFn_IntelEblCrPowerOn, + kCpumMsrWrFn_IntelP4EbcHardPowerOn, + kCpumMsrWrFn_IntelP4EbcSoftPowerOn, + kCpumMsrWrFn_IntelP4EbcFrequencyId, + kCpumMsrWrFn_IntelFlexRatio, + kCpumMsrWrFn_IntelPkgCStConfigControl, + kCpumMsrWrFn_IntelPmgIoCaptureBase, + kCpumMsrWrFn_IntelLastBranchFromToN, + kCpumMsrWrFn_IntelLastBranchFromN, + kCpumMsrWrFn_IntelLastBranchToN, + kCpumMsrWrFn_IntelLastBranchTos, + kCpumMsrWrFn_IntelBblCrCtl, + kCpumMsrWrFn_IntelBblCrCtl3, + kCpumMsrWrFn_IntelI7TemperatureTarget, + kCpumMsrWrFn_IntelI7MsrOffCoreResponseN, /**< Takes register number. */ + kCpumMsrWrFn_IntelI7MiscPwrMgmt, + kCpumMsrWrFn_IntelP6CrN, + kCpumMsrWrFn_IntelCpuId1FeatureMaskEcdx, + kCpumMsrWrFn_IntelCpuId1FeatureMaskEax, + kCpumMsrWrFn_IntelCpuId80000001FeatureMaskEcdx, + kCpumMsrWrFn_IntelI7SandyAesNiCtl, + kCpumMsrWrFn_IntelI7TurboRatioLimit, + kCpumMsrWrFn_IntelI7LbrSelect, + kCpumMsrWrFn_IntelI7SandyErrorControl, + kCpumMsrWrFn_IntelI7PowerCtl, + kCpumMsrWrFn_IntelI7SandyPebsNumAlt, + kCpumMsrWrFn_IntelI7PebsLdLat, + kCpumMsrWrFn_IntelI7SandyVrCurrentConfig, + kCpumMsrWrFn_IntelI7SandyVrMiscConfig, + kCpumMsrWrFn_IntelI7SandyRaplPowerUnit, /**< R/O but found writable bits on a Silvermont CPU here. */ + kCpumMsrWrFn_IntelI7SandyPkgCnIrtlN, + kCpumMsrWrFn_IntelI7SandyPkgC2Residency, /**< R/O but found writable bits on a Silvermont CPU here. */ + kCpumMsrWrFn_IntelI7RaplPkgPowerLimit, + kCpumMsrWrFn_IntelI7RaplDramPowerLimit, + kCpumMsrWrFn_IntelI7RaplPp0PowerLimit, + kCpumMsrWrFn_IntelI7RaplPp0Policy, + kCpumMsrWrFn_IntelI7RaplPp1PowerLimit, + kCpumMsrWrFn_IntelI7RaplPp1Policy, + kCpumMsrWrFn_IntelI7IvyConfigTdpControl, + kCpumMsrWrFn_IntelI7IvyTurboActivationRatio, + kCpumMsrWrFn_IntelI7UncPerfGlobalCtrl, + kCpumMsrWrFn_IntelI7UncPerfGlobalStatus, + kCpumMsrWrFn_IntelI7UncPerfGlobalOvfCtrl, + kCpumMsrWrFn_IntelI7UncPerfFixedCtrCtrl, + kCpumMsrWrFn_IntelI7UncPerfFixedCtr, + kCpumMsrWrFn_IntelI7UncArbPerfCtrN, + kCpumMsrWrFn_IntelI7UncArbPerfEvtSelN, + kCpumMsrWrFn_IntelCore2EmttmCrTablesN, + kCpumMsrWrFn_IntelCore2SmmCStMiscInfo, + kCpumMsrWrFn_IntelCore1ExtConfig, + kCpumMsrWrFn_IntelCore1DtsCalControl, + kCpumMsrWrFn_IntelCore2PeciControl, + + kCpumMsrWrFn_P6LastIntFromIp, + kCpumMsrWrFn_P6LastIntToIp, + + kCpumMsrWrFn_AmdFam15hTscRate, + kCpumMsrWrFn_AmdFam15hLwpCfg, + kCpumMsrWrFn_AmdFam15hLwpCbAddr, + kCpumMsrWrFn_AmdFam10hMc4MiscN, + kCpumMsrWrFn_AmdK8PerfCtlN, + kCpumMsrWrFn_AmdK8PerfCtrN, + kCpumMsrWrFn_AmdK8SysCfg, + kCpumMsrWrFn_AmdK8HwCr, + kCpumMsrWrFn_AmdK8IorrBaseN, + kCpumMsrWrFn_AmdK8IorrMaskN, + kCpumMsrWrFn_AmdK8TopOfMemN, + kCpumMsrWrFn_AmdK8NbCfg1, + kCpumMsrWrFn_AmdK8McXcptRedir, + kCpumMsrWrFn_AmdK8CpuNameN, + kCpumMsrWrFn_AmdK8HwThermalCtrl, + kCpumMsrWrFn_AmdK8SwThermalCtrl, + kCpumMsrWrFn_AmdK8FidVidControl, + kCpumMsrWrFn_AmdK8McCtlMaskN, + kCpumMsrWrFn_AmdK8SmiOnIoTrapN, + kCpumMsrWrFn_AmdK8SmiOnIoTrapCtlSts, + kCpumMsrWrFn_AmdK8IntPendingMessage, + kCpumMsrWrFn_AmdK8SmiTriggerIoCycle, + kCpumMsrWrFn_AmdFam10hMmioCfgBaseAddr, + kCpumMsrWrFn_AmdFam10hTrapCtlMaybe, + kCpumMsrWrFn_AmdFam10hPStateControl, + kCpumMsrWrFn_AmdFam10hPStateStatus, + kCpumMsrWrFn_AmdFam10hPStateN, + kCpumMsrWrFn_AmdFam10hCofVidControl, + kCpumMsrWrFn_AmdFam10hCofVidStatus, + kCpumMsrWrFn_AmdFam10hCStateIoBaseAddr, + kCpumMsrWrFn_AmdFam10hCpuWatchdogTimer, + kCpumMsrWrFn_AmdK8SmmBase, + kCpumMsrWrFn_AmdK8SmmAddr, + kCpumMsrWrFn_AmdK8SmmMask, + kCpumMsrWrFn_AmdK8VmCr, + kCpumMsrWrFn_AmdK8IgnNe, + kCpumMsrWrFn_AmdK8SmmCtl, + kCpumMsrWrFn_AmdK8VmHSavePa, + kCpumMsrWrFn_AmdFam10hVmLockKey, + kCpumMsrWrFn_AmdFam10hSmmLockKey, + kCpumMsrWrFn_AmdFam10hLocalSmiStatus, + kCpumMsrWrFn_AmdFam10hOsVisWrkIdLength, + kCpumMsrWrFn_AmdFam10hOsVisWrkStatus, + kCpumMsrWrFn_AmdFam16hL2IPerfCtlN, + kCpumMsrWrFn_AmdFam16hL2IPerfCtrN, + kCpumMsrWrFn_AmdFam15hNorthbridgePerfCtlN, + kCpumMsrWrFn_AmdFam15hNorthbridgePerfCtrN, + kCpumMsrWrFn_AmdK7MicrocodeCtl, + kCpumMsrWrFn_AmdK7ClusterIdMaybe, + kCpumMsrWrFn_AmdK8CpuIdCtlStd07hEbax, + kCpumMsrWrFn_AmdK8CpuIdCtlStd06hEcx, + kCpumMsrWrFn_AmdK8CpuIdCtlStd01hEdcx, + kCpumMsrWrFn_AmdK8CpuIdCtlExt01hEdcx, + kCpumMsrWrFn_AmdK8PatchLoader, + kCpumMsrWrFn_AmdK7DebugStatusMaybe, + kCpumMsrWrFn_AmdK7BHTraceBaseMaybe, + kCpumMsrWrFn_AmdK7BHTracePtrMaybe, + kCpumMsrWrFn_AmdK7BHTraceLimitMaybe, + kCpumMsrWrFn_AmdK7HardwareDebugToolCfgMaybe, + kCpumMsrWrFn_AmdK7FastFlushCountMaybe, + kCpumMsrWrFn_AmdK7NodeId, + kCpumMsrWrFn_AmdK7DrXAddrMaskN, /**< Takes register index. */ + kCpumMsrWrFn_AmdK7Dr0DataMatchMaybe, + kCpumMsrWrFn_AmdK7Dr0DataMaskMaybe, + kCpumMsrWrFn_AmdK7LoadStoreCfg, + kCpumMsrWrFn_AmdK7InstrCacheCfg, + kCpumMsrWrFn_AmdK7DataCacheCfg, + kCpumMsrWrFn_AmdK7BusUnitCfg, + kCpumMsrWrFn_AmdK7DebugCtl2Maybe, + kCpumMsrWrFn_AmdFam15hFpuCfg, + kCpumMsrWrFn_AmdFam15hDecoderCfg, + kCpumMsrWrFn_AmdFam10hBusUnitCfg2, + kCpumMsrWrFn_AmdFam15hCombUnitCfg, + kCpumMsrWrFn_AmdFam15hCombUnitCfg2, + kCpumMsrWrFn_AmdFam15hCombUnitCfg3, + kCpumMsrWrFn_AmdFam15hExecUnitCfg, + kCpumMsrWrFn_AmdFam15hLoadStoreCfg2, + kCpumMsrWrFn_AmdFam10hIbsFetchCtl, + kCpumMsrWrFn_AmdFam10hIbsFetchLinAddr, + kCpumMsrWrFn_AmdFam10hIbsFetchPhysAddr, + kCpumMsrWrFn_AmdFam10hIbsOpExecCtl, + kCpumMsrWrFn_AmdFam10hIbsOpRip, + kCpumMsrWrFn_AmdFam10hIbsOpData, + kCpumMsrWrFn_AmdFam10hIbsOpData2, + kCpumMsrWrFn_AmdFam10hIbsOpData3, + kCpumMsrWrFn_AmdFam10hIbsDcLinAddr, + kCpumMsrWrFn_AmdFam10hIbsDcPhysAddr, + kCpumMsrWrFn_AmdFam10hIbsCtl, + kCpumMsrWrFn_AmdFam14hIbsBrTarget, + + kCpumMsrWrFn_Gim, + + /** End of valid MSR write function indexes. */ + kCpumMsrWrFn_End +} CPUMMSRWRFN; + +/** + * MSR range. + */ +typedef struct CPUMMSRRANGE +{ + /** The first MSR. [0] */ + uint32_t uFirst; + /** The last MSR. [4] */ + uint32_t uLast; + /** The read function (CPUMMSRRDFN). [8] */ + uint16_t enmRdFn; + /** The write function (CPUMMSRWRFN). [10] */ + uint16_t enmWrFn; + /** The offset of the 64-bit MSR value relative to the start of CPUMCPU. + * UINT16_MAX if not used by the read and write functions. [12] */ + uint32_t offCpumCpu : 24; + /** Reserved for future hacks. [15] */ + uint32_t fReserved : 8; + /** The init/read value. [16] + * When enmRdFn is kCpumMsrRdFn_INIT_VALUE, this is the value returned on RDMSR. + * offCpumCpu must be UINT16_MAX in that case, otherwise it must be a valid + * offset into CPUM. */ + uint64_t uValue; + /** The bits to ignore when writing. [24] */ + uint64_t fWrIgnMask; + /** The bits that will cause a GP(0) when writing. [32] + * This is always checked prior to calling the write function. Using + * UINT64_MAX effectively marks the MSR as read-only. */ + uint64_t fWrGpMask; + /** The register name, if applicable. [40] */ + char szName[56]; + + /** The number of reads. */ + STAMCOUNTER cReads; + /** The number of writes. */ + STAMCOUNTER cWrites; + /** The number of times ignored bits were written. */ + STAMCOUNTER cIgnoredBits; + /** The number of GPs generated. */ + STAMCOUNTER cGps; +} CPUMMSRRANGE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMMSRRANGE, 128); +#endif +/** Pointer to an MSR range. */ +typedef CPUMMSRRANGE *PCPUMMSRRANGE; +/** Pointer to a const MSR range. */ +typedef CPUMMSRRANGE const *PCCPUMMSRRANGE; + + +/** + * MSRs which are required while exploding features. + */ +typedef struct CPUMMSRS +{ + union + { + VMXMSRS vmx; + SVMMSRS svm; + } hwvirt; +} CPUMMSRS; +/** Pointer to an CPUMMSRS struct. */ +typedef CPUMMSRS *PCPUMMSRS; +/** Pointer to a const CPUMMSRS struct. */ +typedef CPUMMSRS const *PCCPUMMSRS; + + +/** + * CPU features and quirks. + * This is mostly exploded CPUID info. + */ +typedef struct CPUMFEATURES +{ + /** The CPU vendor (CPUMCPUVENDOR). */ + uint8_t enmCpuVendor; + /** The CPU family. */ + uint8_t uFamily; + /** The CPU model. */ + uint8_t uModel; + /** The CPU stepping. */ + uint8_t uStepping; + /** The microarchitecture. */ +#ifndef VBOX_FOR_DTRACE_LIB + CPUMMICROARCH enmMicroarch; +#else + uint32_t enmMicroarch; +#endif + /** The maximum physical address width of the CPU. */ + uint8_t cMaxPhysAddrWidth; + /** The maximum linear address width of the CPU. */ + uint8_t cMaxLinearAddrWidth; + /** Max size of the extended state (or FPU state if no XSAVE). */ + uint16_t cbMaxExtendedState; + + /** Supports MSRs. */ + uint32_t fMsr : 1; + /** Supports the page size extension (4/2 MB pages). */ + uint32_t fPse : 1; + /** Supports 36-bit page size extension (4 MB pages can map memory above + * 4GB). */ + uint32_t fPse36 : 1; + /** Supports physical address extension (PAE). */ + uint32_t fPae : 1; + /** Supports page-global extension (PGE). */ + uint32_t fPge : 1; + /** Page attribute table (PAT) support (page level cache control). */ + uint32_t fPat : 1; + /** Supports the FXSAVE and FXRSTOR instructions. */ + uint32_t fFxSaveRstor : 1; + /** Supports the XSAVE and XRSTOR instructions. */ + uint32_t fXSaveRstor : 1; + /** Supports the XSAVEOPT instruction. */ + uint32_t fXSaveOpt : 1; + /** The XSAVE/XRSTOR bit in CR4 has been set (only applicable for host!). */ + uint32_t fOpSysXSaveRstor : 1; + /** Supports MMX. */ + uint32_t fMmx : 1; + /** Supports AMD extensions to MMX instructions. */ + uint32_t fAmdMmxExts : 1; + /** Supports SSE. */ + uint32_t fSse : 1; + /** Supports SSE2. */ + uint32_t fSse2 : 1; + /** Supports SSE3. */ + uint32_t fSse3 : 1; + /** Supports SSSE3. */ + uint32_t fSsse3 : 1; + /** Supports SSE4.1. */ + uint32_t fSse41 : 1; + /** Supports SSE4.2. */ + uint32_t fSse42 : 1; + /** Supports AVX. */ + uint32_t fAvx : 1; + /** Supports AVX2. */ + uint32_t fAvx2 : 1; + /** Supports AVX512 foundation. */ + uint32_t fAvx512Foundation : 1; + /** Supports RDTSC. */ + uint32_t fTsc : 1; + /** Intel SYSENTER/SYSEXIT support */ + uint32_t fSysEnter : 1; + /** First generation APIC. */ + uint32_t fApic : 1; + /** Second generation APIC. */ + uint32_t fX2Apic : 1; + /** Hypervisor present. */ + uint32_t fHypervisorPresent : 1; + /** MWAIT & MONITOR instructions supported. */ + uint32_t fMonitorMWait : 1; + /** MWAIT Extensions present. */ + uint32_t fMWaitExtensions : 1; + /** Supports CMPXCHG16B in 64-bit mode. */ + uint32_t fMovCmpXchg16b : 1; + /** Supports CLFLUSH. */ + uint32_t fClFlush : 1; + /** Supports CLFLUSHOPT. */ + uint32_t fClFlushOpt : 1; + /** Supports IA32_PRED_CMD.IBPB. */ + uint32_t fIbpb : 1; + /** Supports IA32_SPEC_CTRL.IBRS. */ + uint32_t fIbrs : 1; + /** Supports IA32_SPEC_CTRL.STIBP. */ + uint32_t fStibp : 1; + /** Supports IA32_FLUSH_CMD. */ + uint32_t fFlushCmd : 1; + /** Supports IA32_ARCH_CAP. */ + uint32_t fArchCap : 1; + /** Supports MD_CLEAR functionality (VERW, IA32_FLUSH_CMD). */ + uint32_t fMdsClear : 1; + /** Supports PCID. */ + uint32_t fPcid : 1; + /** Supports INVPCID. */ + uint32_t fInvpcid : 1; + /** Supports read/write FSGSBASE instructions. */ + uint32_t fFsGsBase : 1; + /** Supports BMI1 instructions (ANDN, BEXTR, BLSI, BLSMSK, BLSR, and TZCNT). */ + uint32_t fBmi1 : 1; + /** Supports BMI2 instructions (BZHI, MULX, PDEP, PEXT, RORX, SARX, SHRX, + * and SHLX). */ + uint32_t fBmi2 : 1; + /** Supports POPCNT instruction. */ + uint32_t fPopCnt : 1; + /** Supports RDRAND instruction. */ + uint32_t fRdRand : 1; + /** Supports RDSEED instruction. */ + uint32_t fRdSeed : 1; + /** Supports Hardware Lock Elision (HLE). */ + uint32_t fHle : 1; + /** Supports Restricted Transactional Memory (RTM - XBEGIN, XEND, XABORT). */ + uint32_t fRtm : 1; + /** Supports PCLMULQDQ instruction. */ + uint32_t fPclMul : 1; + /** Supports AES-NI (six AESxxx instructions). */ + uint32_t fAesNi : 1; + /** Support MOVBE instruction. */ + uint32_t fMovBe : 1; + + /** Supports AMD 3DNow instructions. */ + uint32_t f3DNow : 1; + /** Supports the 3DNow/AMD64 prefetch instructions (could be nops). */ + uint32_t f3DNowPrefetch : 1; + + /** AMD64: Supports long mode. */ + uint32_t fLongMode : 1; + /** AMD64: SYSCALL/SYSRET support. */ + uint32_t fSysCall : 1; + /** AMD64: No-execute page table bit. */ + uint32_t fNoExecute : 1; + /** AMD64: Supports LAHF & SAHF instructions in 64-bit mode. */ + uint32_t fLahfSahf : 1; + /** AMD64: Supports RDTSCP. */ + uint32_t fRdTscP : 1; + /** AMD64: Supports MOV CR8 in 32-bit code (lock prefix hack). */ + uint32_t fMovCr8In32Bit : 1; + /** AMD64: Supports XOP (similar to VEX3/AVX). */ + uint32_t fXop : 1; + /** AMD64: Supports ABM, i.e. the LZCNT instruction. */ + uint32_t fAbm : 1; + /** AMD64: Supports TBM (BEXTR, BLCFILL, BLCI, BLCIC, BLCMSK, BLCS, + * BLSFILL, BLSIC, T1MSKC, and TZMSK). */ + uint32_t fTbm : 1; + + /** Indicates that FPU instruction and data pointers may leak. + * This generally applies to recent AMD CPUs, where the FPU IP and DP pointer + * is only saved and restored if an exception is pending. */ + uint32_t fLeakyFxSR : 1; + + /** AMD64: Supports AMD SVM. */ + uint32_t fSvm : 1; + + /** Support for Intel VMX. */ + uint32_t fVmx : 1; + + /** Indicates that speculative execution control CPUID bits and MSRs are exposed. + * The details are different for Intel and AMD but both have similar + * functionality. */ + uint32_t fSpeculationControl : 1; + + /** MSR_IA32_ARCH_CAPABILITIES: RDCL_NO (bit 0). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchRdclNo : 1; + /** MSR_IA32_ARCH_CAPABILITIES: IBRS_ALL (bit 1). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchIbrsAll : 1; + /** MSR_IA32_ARCH_CAPABILITIES: RSB Override (bit 2). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchRsbOverride : 1; + /** MSR_IA32_ARCH_CAPABILITIES: RSB Override (bit 3). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchVmmNeedNotFlushL1d : 1; + /** MSR_IA32_ARCH_CAPABILITIES: MDS_NO (bit 4). + * @remarks Only safe use after CPUM ring-0 init! */ + uint32_t fArchMdsNo : 1; + + /** Alignment padding / reserved for future use (96 bits total, plus 12 bytes + * prior to the bit fields -> total of 24 bytes) */ + uint32_t fPadding0 : 26; + + + /** @name SVM + * @{ */ + /** SVM: Supports Nested-paging. */ + uint32_t fSvmNestedPaging : 1; + /** SVM: Support LBR (Last Branch Record) virtualization. */ + uint32_t fSvmLbrVirt : 1; + /** SVM: Supports SVM lock. */ + uint32_t fSvmSvmLock : 1; + /** SVM: Supports Next RIP save. */ + uint32_t fSvmNextRipSave : 1; + /** SVM: Supports TSC rate MSR. */ + uint32_t fSvmTscRateMsr : 1; + /** SVM: Supports VMCB clean bits. */ + uint32_t fSvmVmcbClean : 1; + /** SVM: Supports Flush-by-ASID. */ + uint32_t fSvmFlusbByAsid : 1; + /** SVM: Supports decode assist. */ + uint32_t fSvmDecodeAssists : 1; + /** SVM: Supports Pause filter. */ + uint32_t fSvmPauseFilter : 1; + /** SVM: Supports Pause filter threshold. */ + uint32_t fSvmPauseFilterThreshold : 1; + /** SVM: Supports AVIC (Advanced Virtual Interrupt Controller). */ + uint32_t fSvmAvic : 1; + /** SVM: Supports Virtualized VMSAVE/VMLOAD. */ + uint32_t fSvmVirtVmsaveVmload : 1; + /** SVM: Supports VGIF (Virtual Global Interrupt Flag). */ + uint32_t fSvmVGif : 1; + /** SVM: Supports GMET (Guest Mode Execute Trap Extension). */ + uint32_t fSvmGmet : 1; + /** SVM: Supports SSSCheck (SVM Supervisor Shadow Stack). */ + uint32_t fSvmSSSCheck : 1; + /** SVM: Supports SPEC_CTRL virtualization. */ + uint32_t fSvmSpecCtrl : 1; + /** SVM: Supports HOST_MCE_OVERRIDE. */ + uint32_t fSvmHostMceOverride : 1; + /** SVM: Supports TlbiCtl (INVLPGB/TLBSYNC in VMCB and TLBSYNC intercept). */ + uint32_t fSvmTlbiCtl : 1; + /** SVM: Padding / reserved for future features (64 bits total w/ max ASID). */ + uint32_t fSvmPadding0 : 14; + /** SVM: Maximum supported ASID. */ + uint32_t uSvmMaxAsid; + /** @} */ + + + /** VMX: Maximum physical address width. */ + uint32_t cVmxMaxPhysAddrWidth : 8; + + /** @name VMX basic controls. + * @{ */ + /** VMX: Supports INS/OUTS VM-exit instruction info. */ + uint32_t fVmxInsOutInfo : 1; + /** @} */ + + /** @name VMX Pin-based controls. + * @{ */ + /** VMX: Supports external interrupt VM-exit. */ + uint32_t fVmxExtIntExit : 1; + /** VMX: Supports NMI VM-exit. */ + uint32_t fVmxNmiExit : 1; + /** VMX: Supports Virtual NMIs. */ + uint32_t fVmxVirtNmi : 1; + /** VMX: Supports preemption timer. */ + uint32_t fVmxPreemptTimer : 1; + /** VMX: Supports posted interrupts. */ + uint32_t fVmxPostedInt : 1; + /** @} */ + + /** @name VMX Processor-based controls. + * @{ */ + /** VMX: Supports Interrupt-window exiting. */ + uint32_t fVmxIntWindowExit : 1; + /** VMX: Supports TSC offsetting. */ + uint32_t fVmxTscOffsetting : 1; + /** VMX: Supports HLT exiting. */ + uint32_t fVmxHltExit : 1; + /** VMX: Supports INVLPG exiting. */ + uint32_t fVmxInvlpgExit : 1; + /** VMX: Supports MWAIT exiting. */ + uint32_t fVmxMwaitExit : 1; + /** VMX: Supports RDPMC exiting. */ + uint32_t fVmxRdpmcExit : 1; + /** VMX: Supports RDTSC exiting. */ + uint32_t fVmxRdtscExit : 1; + /** VMX: Supports CR3-load exiting. */ + uint32_t fVmxCr3LoadExit : 1; + /** VMX: Supports CR3-store exiting. */ + uint32_t fVmxCr3StoreExit : 1; + /** VMX: Supports tertiary processor-based VM-execution controls. */ + uint32_t fVmxTertiaryExecCtls : 1; + /** VMX: Supports CR8-load exiting. */ + uint32_t fVmxCr8LoadExit : 1; + /** VMX: Supports CR8-store exiting. */ + uint32_t fVmxCr8StoreExit : 1; + /** VMX: Supports TPR shadow. */ + uint32_t fVmxUseTprShadow : 1; + /** VMX: Supports NMI-window exiting. */ + uint32_t fVmxNmiWindowExit : 1; + /** VMX: Supports Mov-DRx exiting. */ + uint32_t fVmxMovDRxExit : 1; + /** VMX: Supports Unconditional I/O exiting. */ + uint32_t fVmxUncondIoExit : 1; + /** VMX: Supportgs I/O bitmaps. */ + uint32_t fVmxUseIoBitmaps : 1; + /** VMX: Supports Monitor Trap Flag. */ + uint32_t fVmxMonitorTrapFlag : 1; + /** VMX: Supports MSR bitmap. */ + uint32_t fVmxUseMsrBitmaps : 1; + /** VMX: Supports MONITOR exiting. */ + uint32_t fVmxMonitorExit : 1; + /** VMX: Supports PAUSE exiting. */ + uint32_t fVmxPauseExit : 1; + /** VMX: Supports secondary processor-based VM-execution controls. */ + uint32_t fVmxSecondaryExecCtls : 1; + /** @} */ + + /** @name VMX Secondary processor-based controls. + * @{ */ + /** VMX: Supports virtualize-APIC access. */ + uint32_t fVmxVirtApicAccess : 1; + /** VMX: Supports EPT (Extended Page Tables). */ + uint32_t fVmxEpt : 1; + /** VMX: Supports descriptor-table exiting. */ + uint32_t fVmxDescTableExit : 1; + /** VMX: Supports RDTSCP. */ + uint32_t fVmxRdtscp : 1; + /** VMX: Supports virtualize-x2APIC mode. */ + uint32_t fVmxVirtX2ApicMode : 1; + /** VMX: Supports VPID. */ + uint32_t fVmxVpid : 1; + /** VMX: Supports WBIND exiting. */ + uint32_t fVmxWbinvdExit : 1; + /** VMX: Supports Unrestricted guest. */ + uint32_t fVmxUnrestrictedGuest : 1; + /** VMX: Supports APIC-register virtualization. */ + uint32_t fVmxApicRegVirt : 1; + /** VMX: Supports virtual-interrupt delivery. */ + uint32_t fVmxVirtIntDelivery : 1; + /** VMX: Supports Pause-loop exiting. */ + uint32_t fVmxPauseLoopExit : 1; + /** VMX: Supports RDRAND exiting. */ + uint32_t fVmxRdrandExit : 1; + /** VMX: Supports INVPCID. */ + uint32_t fVmxInvpcid : 1; + /** VMX: Supports VM functions. */ + uint32_t fVmxVmFunc : 1; + /** VMX: Supports VMCS shadowing. */ + uint32_t fVmxVmcsShadowing : 1; + /** VMX: Supports RDSEED exiting. */ + uint32_t fVmxRdseedExit : 1; + /** VMX: Supports PML. */ + uint32_t fVmxPml : 1; + /** VMX: Supports EPT-violations \#VE. */ + uint32_t fVmxEptXcptVe : 1; + /** VMX: Supports conceal VMX from PT. */ + uint32_t fVmxConcealVmxFromPt : 1; + /** VMX: Supports XSAVES/XRSTORS. */ + uint32_t fVmxXsavesXrstors : 1; + /** VMX: Supports mode-based execute control for EPT. */ + uint32_t fVmxModeBasedExecuteEpt : 1; + /** VMX: Supports sub-page write permissions for EPT. */ + uint32_t fVmxSppEpt : 1; + /** VMX: Supports Intel PT to output guest-physical addresses for EPT. */ + uint32_t fVmxPtEpt : 1; + /** VMX: Supports TSC scaling. */ + uint32_t fVmxUseTscScaling : 1; + /** VMX: Supports TPAUSE, UMONITOR, or UMWAIT. */ + uint32_t fVmxUserWaitPause : 1; + /** VMX: Supports enclave (ENCLV) exiting. */ + uint32_t fVmxEnclvExit : 1; + /** @} */ + + /** @name VMX Tertiary processor-based controls. + * @{ */ + /** VMX: Supports LOADIWKEY exiting. */ + uint32_t fVmxLoadIwKeyExit : 1; + /** @} */ + + /** @name VMX VM-entry controls. + * @{ */ + /** VMX: Supports load-debug controls on VM-entry. */ + uint32_t fVmxEntryLoadDebugCtls : 1; + /** VMX: Supports IA32e mode guest. */ + uint32_t fVmxIa32eModeGuest : 1; + /** VMX: Supports load guest EFER MSR on VM-entry. */ + uint32_t fVmxEntryLoadEferMsr : 1; + /** VMX: Supports load guest PAT MSR on VM-entry. */ + uint32_t fVmxEntryLoadPatMsr : 1; + /** @} */ + + /** @name VMX VM-exit controls. + * @{ */ + /** VMX: Supports save debug controls on VM-exit. */ + uint32_t fVmxExitSaveDebugCtls : 1; + /** VMX: Supports host-address space size. */ + uint32_t fVmxHostAddrSpaceSize : 1; + /** VMX: Supports acknowledge external interrupt on VM-exit. */ + uint32_t fVmxExitAckExtInt : 1; + /** VMX: Supports save guest PAT MSR on VM-exit. */ + uint32_t fVmxExitSavePatMsr : 1; + /** VMX: Supports load hsot PAT MSR on VM-exit. */ + uint32_t fVmxExitLoadPatMsr : 1; + /** VMX: Supports save guest EFER MSR on VM-exit. */ + uint32_t fVmxExitSaveEferMsr : 1; + /** VMX: Supports load host EFER MSR on VM-exit. */ + uint32_t fVmxExitLoadEferMsr : 1; + /** VMX: Supports save VMX preemption timer on VM-exit. */ + uint32_t fVmxSavePreemptTimer : 1; + /** VMX: Supports secondary VM-exit controls. */ + uint32_t fVmxSecondaryExitCtls : 1; + /** @} */ + + /** @name VMX Miscellaneous data. + * @{ */ + /** VMX: Supports storing EFER.LMA into IA32e-mode guest field on VM-exit. */ + uint32_t fVmxExitSaveEferLma : 1; + /** VMX: Whether Intel PT (Processor Trace) is supported in VMX mode or not. */ + uint32_t fVmxPt : 1; + /** VMX: Supports VMWRITE to any valid VMCS field incl. read-only fields, otherwise + * VMWRITE cannot modify read-only VM-exit information fields. */ + uint32_t fVmxVmwriteAll : 1; + /** VMX: Supports injection of software interrupts, ICEBP on VM-entry for zero + * length instructions. */ + uint32_t fVmxEntryInjectSoftInt : 1; + /** @} */ + + /** VMX: Padding / reserved for future features. */ + uint32_t fVmxPadding0 : 16; + /** VMX: Padding / reserved for future, making it a total of 128 bits. */ + uint32_t fVmxPadding1; +} CPUMFEATURES; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMFEATURES, 48); +#endif +/** Pointer to a CPU feature structure. */ +typedef CPUMFEATURES *PCPUMFEATURES; +/** Pointer to a const CPU feature structure. */ +typedef CPUMFEATURES const *PCCPUMFEATURES; + +/** + * Chameleon wrapper structure for the host CPU features. + * + * This is used for the globally readable g_CpumHostFeatures variable, which is + * initialized once during VMMR0 load for ring-0 and during CPUMR3Init in + * ring-3. To reflect this immutability after load/init, we use this wrapper + * structure to switch it between const and non-const depending on the context. + * Only two files sees it as non-const (CPUMR0.cpp and CPUM.cpp). + */ +typedef struct CPUHOSTFEATURES +{ + CPUMFEATURES +#ifndef CPUM_WITH_NONCONST_HOST_FEATURES + const +#endif + s; +} CPUHOSTFEATURES; +/** Pointer to a const host CPU feature structure. */ +typedef CPUHOSTFEATURES const *PCCPUHOSTFEATURES; + +/** Host CPU features. + * @note In ring-3, only valid after CPUMR3Init. In ring-0, valid after + * module init. */ +extern CPUHOSTFEATURES g_CpumHostFeatures; + + +/** + * CPU database entry. + */ +typedef struct CPUMDBENTRY +{ + /** The CPU name. */ + const char *pszName; + /** The full CPU name. */ + const char *pszFullName; + /** The CPU vendor (CPUMCPUVENDOR). */ + uint8_t enmVendor; + /** The CPU family. */ + uint8_t uFamily; + /** The CPU model. */ + uint8_t uModel; + /** The CPU stepping. */ + uint8_t uStepping; + /** The microarchitecture. */ + CPUMMICROARCH enmMicroarch; + /** Scalable bus frequency used for reporting other frequencies. */ + uint64_t uScalableBusFreq; + /** Flags - CPUMDB_F_XXX. */ + uint32_t fFlags; + /** The maximum physical address with of the CPU. This should correspond to + * the value in CPUID leaf 0x80000008 when present. */ + uint8_t cMaxPhysAddrWidth; + /** The MXCSR mask. */ + uint32_t fMxCsrMask; + /** Pointer to an array of CPUID leaves. */ + PCCPUMCPUIDLEAF paCpuIdLeaves; + /** The number of CPUID leaves in the array paCpuIdLeaves points to. */ + uint32_t cCpuIdLeaves; + /** The method used to deal with unknown CPUID leaves. */ + CPUMUNKNOWNCPUID enmUnknownCpuId; + /** The default unknown CPUID value. */ + CPUMCPUID DefUnknownCpuId; + + /** MSR mask. Several microarchitectures ignore the higher bits of ECX in + * the RDMSR and WRMSR instructions. */ + uint32_t fMsrMask; + + /** The number of ranges in the table pointed to b paMsrRanges. */ + uint32_t cMsrRanges; + /** MSR ranges for this CPU. */ + PCCPUMMSRRANGE paMsrRanges; +} CPUMDBENTRY; +/** Pointer to a const CPU database entry. */ +typedef CPUMDBENTRY const *PCCPUMDBENTRY; + +/** @name CPUMDB_F_XXX - CPUDBENTRY::fFlags + * @{ */ +/** Should execute all in IEM. + * @todo Implement this - currently done in Main... */ +#define CPUMDB_F_EXECUTE_ALL_IN_IEM RT_BIT_32(0) +/** @} */ + + + +#ifndef VBOX_FOR_DTRACE_LIB + +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +VMMDECL(int) CPUMCpuIdCollectLeavesX86(PCPUMCPUIDLEAF *ppaLeaves, uint32_t *pcLeaves); +VMMDECL(CPUMCPUVENDOR) CPUMCpuIdDetectX86VendorEx(uint32_t uEAX, uint32_t uEBX, uint32_t uECX, uint32_t uEDX); +#endif + +VMM_INT_DECL(bool) CPUMAssertGuestRFlagsCookie(PVM pVM, PVMCPU pVCpu); + + +/** @name Guest Register Getters. + * @{ */ +VMMDECL(void) CPUMGetGuestGDTR(PCVMCPU pVCpu, PVBOXGDTR pGDTR); +VMMDECL(RTGCPTR) CPUMGetGuestIDTR(PCVMCPU pVCpu, uint16_t *pcbLimit); +VMMDECL(RTSEL) CPUMGetGuestTR(PCVMCPU pVCpu, PCPUMSELREGHID pHidden); +VMMDECL(RTSEL) CPUMGetGuestLDTR(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestLdtrEx(PCVMCPU pVCpu, uint64_t *pGCPtrBase, uint32_t *pcbLimit); +VMMDECL(uint64_t) CPUMGetGuestCR0(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR2(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR3(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR4(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestCR8(PCVMCPUCC pVCpu); +VMMDECL(int) CPUMGetGuestCRx(PCVMCPUCC pVCpu, unsigned iReg, uint64_t *pValue); +VMMDECL(uint32_t) CPUMGetGuestEFlags(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEIP(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestRIP(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEAX(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEBX(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestECX(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEDX(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestESI(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEDI(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestESP(PCVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestEBP(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestCS(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestDS(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestES(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestFS(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestGS(PCVMCPU pVCpu); +VMMDECL(RTSEL) CPUMGetGuestSS(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestFlatPC(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestFlatSP(PVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR0(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR1(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR2(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR3(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR6(PCVMCPU pVCpu); +VMMDECL(uint64_t) CPUMGetGuestDR7(PCVMCPU pVCpu); +VMMDECL(int) CPUMGetGuestDRx(PCVMCPU pVCpu, uint32_t iReg, uint64_t *pValue); +VMMDECL(void) CPUMGetGuestCpuId(PVMCPUCC pVCpu, uint32_t iLeaf, uint32_t iSubLeaf, int f64BitMode, + uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx); +VMMDECL(uint64_t) CPUMGetGuestEFER(PCVMCPU pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestIa32FeatCtrl(PCVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestIa32MtrrCap(PCVMCPU pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestIa32SmmMonitorCtl(PCVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestIa32VmxEptVpidCap(PCVMCPUCC pVCpu); +VMMDECL(VBOXSTRICTRC) CPUMQueryGuestMsr(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t *puValue); +VMMDECL(VBOXSTRICTRC) CPUMSetGuestMsr(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t uValue); +VMMDECL(CPUMCPUVENDOR) CPUMGetGuestCpuVendor(PVM pVM); +VMMDECL(CPUMMICROARCH) CPUMGetGuestMicroarch(PCVM pVM); +VMMDECL(void) CPUMGetGuestAddrWidths(PCVM pVM, uint8_t *pcPhysAddrWidth, uint8_t *pcLinearAddrWidth); +VMMDECL(CPUMCPUVENDOR) CPUMGetHostCpuVendor(PVM pVM); +VMMDECL(CPUMMICROARCH) CPUMGetHostMicroarch(PCVM pVM); +/** @} */ + +/** @name Guest Register Setters. + * @{ */ +VMMDECL(int) CPUMSetGuestGDTR(PVMCPU pVCpu, uint64_t GCPtrBase, uint16_t cbLimit); +VMMDECL(int) CPUMSetGuestIDTR(PVMCPU pVCpu, uint64_t GCPtrBase, uint16_t cbLimit); +VMMDECL(int) CPUMSetGuestTR(PVMCPU pVCpu, uint16_t tr); +VMMDECL(int) CPUMSetGuestLDTR(PVMCPU pVCpu, uint16_t ldtr); +VMMDECL(int) CPUMSetGuestCR0(PVMCPUCC pVCpu, uint64_t cr0); +VMMDECL(int) CPUMSetGuestCR2(PVMCPU pVCpu, uint64_t cr2); +VMMDECL(int) CPUMSetGuestCR3(PVMCPU pVCpu, uint64_t cr3); +VMMDECL(int) CPUMSetGuestCR4(PVMCPU pVCpu, uint64_t cr4); +VMMDECL(int) CPUMSetGuestDR0(PVMCPUCC pVCpu, uint64_t uDr0); +VMMDECL(int) CPUMSetGuestDR1(PVMCPUCC pVCpu, uint64_t uDr1); +VMMDECL(int) CPUMSetGuestDR2(PVMCPUCC pVCpu, uint64_t uDr2); +VMMDECL(int) CPUMSetGuestDR3(PVMCPUCC pVCpu, uint64_t uDr3); +VMMDECL(int) CPUMSetGuestDR6(PVMCPU pVCpu, uint64_t uDr6); +VMMDECL(int) CPUMSetGuestDR7(PVMCPUCC pVCpu, uint64_t uDr7); +VMMDECL(int) CPUMSetGuestDRx(PVMCPUCC pVCpu, uint32_t iReg, uint64_t Value); +VMM_INT_DECL(int) CPUMSetGuestXcr0(PVMCPUCC pVCpu, uint64_t uNewValue); +VMMDECL(int) CPUMSetGuestEFlags(PVMCPU pVCpu, uint32_t eflags); +VMMDECL(int) CPUMSetGuestEIP(PVMCPU pVCpu, uint32_t eip); +VMMDECL(int) CPUMSetGuestEAX(PVMCPU pVCpu, uint32_t eax); +VMMDECL(int) CPUMSetGuestEBX(PVMCPU pVCpu, uint32_t ebx); +VMMDECL(int) CPUMSetGuestECX(PVMCPU pVCpu, uint32_t ecx); +VMMDECL(int) CPUMSetGuestEDX(PVMCPU pVCpu, uint32_t edx); +VMMDECL(int) CPUMSetGuestESI(PVMCPU pVCpu, uint32_t esi); +VMMDECL(int) CPUMSetGuestEDI(PVMCPU pVCpu, uint32_t edi); +VMMDECL(int) CPUMSetGuestESP(PVMCPU pVCpu, uint32_t esp); +VMMDECL(int) CPUMSetGuestEBP(PVMCPU pVCpu, uint32_t ebp); +VMMDECL(int) CPUMSetGuestCS(PVMCPU pVCpu, uint16_t cs); +VMMDECL(int) CPUMSetGuestDS(PVMCPU pVCpu, uint16_t ds); +VMMDECL(int) CPUMSetGuestES(PVMCPU pVCpu, uint16_t es); +VMMDECL(int) CPUMSetGuestFS(PVMCPU pVCpu, uint16_t fs); +VMMDECL(int) CPUMSetGuestGS(PVMCPU pVCpu, uint16_t gs); +VMMDECL(int) CPUMSetGuestSS(PVMCPU pVCpu, uint16_t ss); +VMMDECL(void) CPUMSetGuestEFER(PVMCPU pVCpu, uint64_t val); +VMMR3_INT_DECL(void) CPUMR3SetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature); +VMMR3_INT_DECL(void) CPUMR3ClearGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature); +VMMR3_INT_DECL(bool) CPUMR3GetGuestCpuIdFeature(PVM pVM, CPUMCPUIDFEATURE enmFeature); +VMMDECL(bool) CPUMSetGuestCpuIdPerCpuApicFeature(PVMCPU pVCpu, bool fVisible); +VMMDECL(void) CPUMSetGuestCtx(PVMCPU pVCpu, const PCPUMCTX pCtx); +VMM_INT_DECL(void) CPUMSetGuestTscAux(PVMCPUCC pVCpu, uint64_t uValue); +VMM_INT_DECL(uint64_t) CPUMGetGuestTscAux(PVMCPUCC pVCpu); +VMM_INT_DECL(void) CPUMSetGuestSpecCtrl(PVMCPUCC pVCpu, uint64_t uValue); +VMM_INT_DECL(uint64_t) CPUMGetGuestSpecCtrl(PVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestCR4ValidMask(PVM pVM); +VMM_INT_DECL(void) CPUMSetGuestPaePdpes(PVMCPU pVCpu, PCX86PDPE paPaePdpes); +VMM_INT_DECL(void) CPUMGetGuestPaePdpes(PVMCPU pVCpu, PX86PDPE paPaePdpes); +/** @} */ + + +/** @name Misc Guest Predicate Functions. + * @{ */ +VMMDECL(bool) CPUMIsGuestIn64BitCode(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestNXEnabled(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestPageSizeExtEnabled(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestPagingEnabled(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestR0WriteProtEnabled(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInRealMode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInRealOrV86Mode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInProtectedMode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInPagedProtectedMode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInLongMode(PCVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestInPAEMode(PCVMCPU pVCpu); +/** @} */ + +/** @name Nested Hardware-Virtualization Helpers. + * @{ */ +VMM_INT_DECL(bool) CPUMIsGuestPhysIntrEnabled(PVMCPU pVCpu); +VMM_INT_DECL(bool) CPUMIsGuestVirtIntrEnabled(PVMCPU pVCpu); +VMM_INT_DECL(uint64_t) CPUMApplyNestedGuestTscOffset(PCVMCPU pVCpu, uint64_t uTscValue); +VMM_INT_DECL(uint64_t) CPUMRemoveNestedGuestTscOffset(PCVMCPU pVCpu, uint64_t uTscValue); + +/* SVM helpers. */ +VMM_INT_DECL(bool) CPUMIsGuestSvmPhysIntrEnabled(PCVMCPU pVCpu, PCCPUMCTX pCtx); +VMM_INT_DECL(bool) CPUMIsGuestSvmVirtIntrEnabled(PCVMCPU pVCpu, PCCPUMCTX pCtx); +VMM_INT_DECL(uint8_t) CPUMGetGuestSvmVirtIntrVector(PCCPUMCTX pCtx); +VMM_INT_DECL(void) CPUMSvmVmExitRestoreHostState(PVMCPUCC pVCpu, PCPUMCTX pCtx); +VMM_INT_DECL(void) CPUMSvmVmRunSaveHostState(PCPUMCTX pCtx, uint8_t cbInstr); +VMM_INT_DECL(bool) CPUMIsSvmIoInterceptSet(void *pvIoBitmap, uint16_t u16Port, SVMIOIOTYPE enmIoType, uint8_t cbReg, + uint8_t cAddrSizeBits, uint8_t iEffSeg, bool fRep, bool fStrIo, + PSVMIOIOEXITINFO pIoExitInfo); +VMM_INT_DECL(int) CPUMGetSvmMsrpmOffsetAndBit(uint32_t idMsr, uint16_t *pbOffMsrpm, uint8_t *puMsrpmBit); + +/* VMX helpers. */ +VMM_INT_DECL(bool) CPUMIsGuestVmxVmcsFieldValid(PVMCC pVM, uint64_t u64VmcsField); +VMM_INT_DECL(bool) CPUMIsGuestVmxIoInterceptSet(PCVMCPU pVCpu, uint16_t u16Port, uint8_t cbAccess); +VMM_INT_DECL(bool) CPUMIsGuestVmxMovToCr3InterceptSet(PVMCPU pVCpu, uint64_t uNewCr3); +VMM_INT_DECL(bool) CPUMIsGuestVmxVmreadVmwriteInterceptSet(PCVMCPU pVCpu, uint32_t uExitReason, uint64_t u64FieldEnc); +VMM_INT_DECL(int) CPUMStartGuestVmxPremptTimer(PVMCPUCC pVCpu, uint32_t uTimer, uint8_t cShift, uint64_t *pu64EntryTick); +VMM_INT_DECL(int) CPUMStopGuestVmxPremptTimer(PVMCPUCC pVCpu); +VMM_INT_DECL(uint32_t) CPUMGetVmxMsrPermission(void const *pvMsrBitmap, uint32_t idMsr); +VMM_INT_DECL(bool) CPUMIsGuestVmxEptPagingEnabled(PCVMCPUCC pVCpu); +VMM_INT_DECL(bool) CPUMIsGuestVmxEptPaePagingEnabled(PCVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) CPUMGetGuestVmxApicAccessPageAddr(PCVMCPUCC pVCpu); +/** @} */ + +/** @name Externalized State Helpers. + * @{ */ +/** @def CPUM_ASSERT_NOT_EXTRN + * Macro for asserting that @a a_fNotExtrn are present. + * + * @param a_pVCpu The cross context virtual CPU structure of the calling EMT. + * @param a_fNotExtrn Mask of CPUMCTX_EXTRN_XXX bits to check. + * + * @remarks Requires VMCPU_INCL_CPUM_GST_CTX to be defined. + */ +#define CPUM_ASSERT_NOT_EXTRN(a_pVCpu, a_fNotExtrn) \ + AssertMsg(!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fNotExtrn)), \ + ("%#RX64; a_fNotExtrn=%#RX64\n", (a_pVCpu)->cpum.GstCtx.fExtrn, (a_fNotExtrn))) + +/** @def CPUMCTX_ASSERT_NOT_EXTRN + * Macro for asserting that @a a_fNotExtrn are present in @a a_pCtx. + * + * @param a_pCtx The CPU context of the calling EMT. + * @param a_fNotExtrn Mask of CPUMCTX_EXTRN_XXX bits to check. + */ +#define CPUMCTX_ASSERT_NOT_EXTRN(a_pCtx, a_fNotExtrn) \ + AssertMsg(!((a_pCtx)->fExtrn & (a_fNotExtrn)), \ + ("%#RX64; a_fNotExtrn=%#RX64\n", (a_pCtx)->fExtrn, (a_fNotExtrn))) + +/** @def CPUM_IMPORT_EXTRN_RET + * Macro for making sure the state specified by @a fExtrnImport is present, + * calling CPUMImportGuestStateOnDemand() to get it if necessary. + * + * Will return if CPUMImportGuestStateOnDemand() fails. + * + * @param a_pVCpu The cross context virtual CPU structure of the calling EMT. + * @param a_fExtrnImport Mask of CPUMCTX_EXTRN_XXX bits to get. + * @thread EMT(a_pVCpu) + * + * @remarks Requires VMCPU_INCL_CPUM_GST_CTX to be defined. + */ +#define CPUM_IMPORT_EXTRN_RET(a_pVCpu, a_fExtrnImport) \ + do { \ + if (!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fExtrnImport))) \ + { /* already present, consider this likely */ } \ + else \ + { \ + int rcCpumImport = CPUMImportGuestStateOnDemand(a_pVCpu, a_fExtrnImport); \ + AssertRCReturn(rcCpumImport, rcCpumImport); \ + } \ + } while (0) + +/** @def CPUM_IMPORT_EXTRN_RCSTRICT + * Macro for making sure the state specified by @a fExtrnImport is present, + * calling CPUMImportGuestStateOnDemand() to get it if necessary. + * + * Will update a_rcStrict if CPUMImportGuestStateOnDemand() fails. + * + * @param a_pVCpu The cross context virtual CPU structure of the calling EMT. + * @param a_fExtrnImport Mask of CPUMCTX_EXTRN_XXX bits to get. + * @param a_rcStrict Strict status code variable to update on failure. + * @thread EMT(a_pVCpu) + * + * @remarks Requires VMCPU_INCL_CPUM_GST_CTX to be defined. + */ +#define CPUM_IMPORT_EXTRN_RCSTRICT(a_pVCpu, a_fExtrnImport, a_rcStrict) \ + do { \ + if (!((a_pVCpu)->cpum.GstCtx.fExtrn & (a_fExtrnImport))) \ + { /* already present, consider this likely */ } \ + else \ + { \ + int rcCpumImport = CPUMImportGuestStateOnDemand(a_pVCpu, a_fExtrnImport); \ + AssertStmt(RT_SUCCESS(rcCpumImport) || RT_FAILURE_NP(a_rcStrict), a_rcStrict = rcCpumImport); \ + } \ + } while (0) + +VMM_INT_DECL(int) CPUMImportGuestStateOnDemand(PVMCPUCC pVCpu, uint64_t fExtrnImport); +/** @} */ + +#if !defined(IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS) || defined(DOXYGEN_RUNNING) +/** @name Inlined Guest Getters and predicates Functions. + * @{ */ + +/** + * Gets valid CR0 bits for the guest. + * + * @returns Valid CR0 bits. + */ +DECLINLINE(uint64_t) CPUMGetGuestCR0ValidMask(void) +{ + return ( X86_CR0_PE | X86_CR0_MP | X86_CR0_EM | X86_CR0_TS + | X86_CR0_ET | X86_CR0_NE | X86_CR0_WP | X86_CR0_AM + | X86_CR0_NW | X86_CR0_CD | X86_CR0_PG); +} + +/** + * Tests if the guest is running in real mode or not. + * + * @returns true if in real mode, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInRealModeEx(PCCPUMCTX pCtx) +{ + return !(pCtx->cr0 & X86_CR0_PE); +} + +/** + * Tests if the guest is running in real or virtual 8086 mode. + * + * @returns @c true if it is, @c false if not. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInRealOrV86ModeEx(PCCPUMCTX pCtx) +{ + return !(pCtx->cr0 & X86_CR0_PE) + || pCtx->eflags.Bits.u1VM; /* Cannot be set in long mode. Intel spec 2.3.1 "System Flags and Fields in IA-32e Mode". */ +} + +/** + * Tests if the guest is running in virtual 8086 mode. + * + * @returns @c true if it is, @c false if not. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInV86ModeEx(PCCPUMCTX pCtx) +{ + return (pCtx->eflags.Bits.u1VM == 1); +} + +/** + * Tests if the guest is running in paged protected or not. + * + * @returns true if in paged protected mode, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInPagedProtectedModeEx(PCPUMCTX pCtx) +{ + return (pCtx->cr0 & (X86_CR0_PE | X86_CR0_PG)) == (X86_CR0_PE | X86_CR0_PG); +} + +/** + * Tests if the guest is running in long mode or not. + * + * @returns true if in long mode, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInLongModeEx(PCCPUMCTX pCtx) +{ + return (pCtx->msrEFER & MSR_K6_EFER_LMA) == MSR_K6_EFER_LMA; +} + +VMM_INT_DECL(bool) CPUMIsGuestIn64BitCodeSlow(PCPUMCTX pCtx); + +/** + * Tests if the guest is running in 64 bits mode or not. + * + * @returns true if in 64 bits protected mode, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestIn64BitCodeEx(PCPUMCTX pCtx) +{ + if (!(pCtx->msrEFER & MSR_K6_EFER_LMA)) + return false; + if (!CPUMSELREG_ARE_HIDDEN_PARTS_VALID(NULL, &pCtx->cs)) + return CPUMIsGuestIn64BitCodeSlow(pCtx); + return pCtx->cs.Attr.n.u1Long; +} + +/** + * Tests if the guest has paging enabled or not. + * + * @returns true if paging is enabled, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestPagingEnabledEx(PCCPUMCTX pCtx) +{ + return !!(pCtx->cr0 & X86_CR0_PG); +} + +/** + * Tests if PAE paging is enabled given the relevant control registers. + * + * @returns @c true if in PAE mode, @c false otherwise. + * @param uCr0 The CR0 value. + * @param uCr4 The CR4 value. + * @param uEferMsr The EFER value. + */ +DECLINLINE(bool) CPUMIsPaePagingEnabled(uint64_t uCr0, uint64_t uCr4, uint64_t uEferMsr) +{ + /* Intel mentions EFER.LMA and EFER.LME in different parts of their spec. We shall use EFER.LMA rather + than EFER.LME as it reflects if the CPU has entered paging with EFER.LME set. */ + return ( (uCr4 & X86_CR4_PAE) + && (uCr0 & X86_CR0_PG) + && !(uEferMsr & MSR_K6_EFER_LMA)); +} + +/** + * Tests if the guest is running in PAE mode or not. + * + * @returns @c true if in PAE mode, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInPAEModeEx(PCCPUMCTX pCtx) +{ + return CPUMIsPaePagingEnabled(pCtx->cr0, pCtx->cr4, pCtx->msrEFER); +} + +/** + * Tests if the guest has AMD SVM enabled or not. + * + * @returns true if SMV is enabled, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestSvmEnabled(PCCPUMCTX pCtx) +{ + return RT_BOOL(pCtx->msrEFER & MSR_K6_EFER_SVME); +} + +/** + * Tests if the guest has Intel VT-x enabled or not. + * + * @returns true if VMX is enabled, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxEnabled(PCCPUMCTX pCtx) +{ + return RT_BOOL(pCtx->cr4 & X86_CR4_VMXE); +} + +/** + * Returns the guest's global-interrupt (GIF) flag. + * + * @returns true when global-interrupts are enabled, otherwise false. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMGetGuestGif(PCCPUMCTX pCtx) +{ + return pCtx->hwvirt.fGif; +} + +/** + * Sets the guest's global-interrupt flag (GIF). + * + * @param pCtx Current CPU context. + * @param fGif The value to set. + */ +DECLINLINE(void) CPUMSetGuestGif(PCPUMCTX pCtx, bool fGif) +{ + pCtx->hwvirt.fGif = fGif; +} + +/** + * Checks if we're in an "interrupt shadow", i.e. after a STI, POP SS or MOV SS. + * + * This also inhibit NMIs, except perhaps for nested guests. + * + * @returns true if interrupts are inhibited by interrupt shadow, false if not. + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + * @note Does NOT clear CPUMCTX_INHIBIT_SHADOW when CPUMCTX::uRipInhibitInt + * differs from CPUMCTX::rip. + */ +DECLINLINE(bool) CPUMIsInInterruptShadow(PCCPUMCTX pCtx) +{ + if (!(pCtx->eflags.uBoth & CPUMCTX_INHIBIT_SHADOW)) + return false; + + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + return pCtx->uRipInhibitInt == pCtx->rip; +} + +/** + * Checks if we're in an "interrupt shadow", i.e. after a STI, POP SS or MOV SS, + * updating the state if stale. + * + * This also inhibit NMIs, except perhaps for nested guests. + * + * @retval true if interrupts are inhibited by interrupt shadow. + * @retval false if not. + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(bool) CPUMIsInInterruptShadowWithUpdate(PCPUMCTX pCtx) +{ + if (!(pCtx->eflags.uBoth & CPUMCTX_INHIBIT_SHADOW)) + return false; + + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + if (pCtx->uRipInhibitInt == pCtx->rip) + return true; + + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; + return false; +} + +/** + * Checks if we're in an "interrupt shadow" due to a POP SS or MOV SS + * instruction. + * + * This also inhibit NMIs, except perhaps for nested guests. + * + * @retval true if interrupts are inhibited due to POP/MOV SS. + * @retval false if not. + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + * @note Does NOT clear CPUMCTX_INHIBIT_SHADOW when CPUMCTX::uRipInhibitInt + * differs from CPUMCTX::rip. + * @note Both CPUMIsInInterruptShadowAfterSti() and this function may return + * true depending on the execution engine being used. + */ +DECLINLINE(bool) CPUMIsInInterruptShadowAfterSs(PCCPUMCTX pCtx) +{ + if (!(pCtx->eflags.uBoth & CPUMCTX_INHIBIT_SHADOW_SS)) + return false; + + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + return pCtx->uRipInhibitInt == pCtx->rip; +} + +/** + * Checks if we're in an "interrupt shadow" due to an STI instruction. + * + * This also inhibit NMIs, except perhaps for nested guests. + * + * @retval true if interrupts are inhibited due to STI. + * @retval false if not. + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + * @note Does NOT clear CPUMCTX_INHIBIT_SHADOW when CPUMCTX::uRipInhibitInt + * differs from CPUMCTX::rip. + * @note Both CPUMIsInInterruptShadowAfterSs() and this function may return + * true depending on the execution engine being used. + */ +DECLINLINE(bool) CPUMIsInInterruptShadowAfterSti(PCCPUMCTX pCtx) +{ + if (!(pCtx->eflags.uBoth & CPUMCTX_INHIBIT_SHADOW_STI)) + return false; + + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + return pCtx->uRipInhibitInt == pCtx->rip; +} + +/** + * Sets the "interrupt shadow" flag, after a STI, POP SS or MOV SS instruction. + * + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(void) CPUMSetInInterruptShadow(PCPUMCTX pCtx) +{ + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW; + pCtx->uRipInhibitInt = pCtx->rip; +} + +/** + * Sets the "interrupt shadow" flag, after a STI, POP SS or MOV SS instruction, + * extended version. + * + * @param pCtx Current guest CPU context. + * @param rip The RIP for which it is inhibited. + */ +DECLINLINE(void) CPUMSetInInterruptShadowEx(PCPUMCTX pCtx, uint64_t rip) +{ + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW; + pCtx->uRipInhibitInt = rip; +} + +/** + * Sets the "interrupt shadow" flag after a POP SS or MOV SS instruction. + * + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(void) CPUMSetInInterruptShadowSs(PCPUMCTX pCtx) +{ + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW_SS; + pCtx->uRipInhibitInt = pCtx->rip; +} + +/** + * Sets the "interrupt shadow" flag after an STI instruction. + * + * @param pCtx Current guest CPU context. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(void) CPUMSetInInterruptShadowSti(PCPUMCTX pCtx) +{ + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW_STI; + pCtx->uRipInhibitInt = pCtx->rip; +} + +/** + * Clears the "interrupt shadow" flag. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMClearInterruptShadow(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; +} + +/** + * Update the "interrupt shadow" flag. + * + * @param pCtx Current guest CPU context. + * @param fInhibited The new state. + * @note Requires pCtx->rip to be up to date. + */ +DECLINLINE(void) CPUMUpdateInterruptShadow(PCPUMCTX pCtx, bool fInhibited) +{ + CPUMCTX_ASSERT_NOT_EXTRN(pCtx, CPUMCTX_EXTRN_RIP); + if (!fInhibited) + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; + else + { + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW; + pCtx->uRipInhibitInt = pCtx->rip; + } +} + +/** + * Update the "interrupt shadow" flag, extended version. + * + * @returns fInhibited. + * @param pCtx Current guest CPU context. + * @param fInhibited The new state. + * @param rip The RIP for which it is inhibited. + */ +DECLINLINE(bool) CPUMUpdateInterruptShadowEx(PCPUMCTX pCtx, bool fInhibited, uint64_t rip) +{ + if (!fInhibited) + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; + else + { + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_SHADOW; + pCtx->uRipInhibitInt = rip; + } + return fInhibited; +} + +/** + * Update the two "interrupt shadow" flags separately, extended version. + * + * @param pCtx Current guest CPU context. + * @param fInhibitedBySs The new state for the MOV SS & POP SS aspect. + * @param fInhibitedBySti The new state for the STI aspect. + * @param rip The RIP for which it is inhibited. + */ +DECLINLINE(void) CPUMUpdateInterruptShadowSsStiEx(PCPUMCTX pCtx, bool fInhibitedBySs, bool fInhibitedBySti, uint64_t rip) +{ + if (!(fInhibitedBySs | fInhibitedBySti)) + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_SHADOW; + else + { + pCtx->eflags.uBoth |= (fInhibitedBySs ? CPUMCTX_INHIBIT_SHADOW_SS : UINT32_C(0)) + | (fInhibitedBySti ? CPUMCTX_INHIBIT_SHADOW_STI : UINT32_C(0)); + pCtx->uRipInhibitInt = rip; + } +} + +/* VMX forward declarations used by extended function versions: */ +DECLINLINE(bool) CPUMIsGuestInVmxNonRootMode(PCCPUMCTX pCtx); +DECLINLINE(bool) CPUMIsGuestVmxPinCtlsSet(PCCPUMCTX pCtx, uint32_t uPinCtls); +DECLINLINE(bool) CPUMIsGuestVmxVirtNmiBlocking(PCCPUMCTX pCtx); +DECLINLINE(void) CPUMSetGuestVmxVirtNmiBlocking(PCPUMCTX pCtx, bool fBlocking); + +/** + * Checks whether interrupts, include NMIs, are inhibited by pending NMI + * delivery. + * + * This only checks the inhibit mask. + * + * @retval true if interrupts are inhibited by NMI handling. + * @retval false if interrupts are not inhibited by NMI handling. + * @param pCtx Current guest CPU context. + */ +DECLINLINE(bool) CPUMAreInterruptsInhibitedByNmi(PCCPUMCTX pCtx) +{ + return (pCtx->eflags.uBoth & CPUMCTX_INHIBIT_NMI) != 0; +} + +/** + * Extended version of CPUMAreInterruptsInhibitedByNmi() that takes VMX non-root + * mode into account when check whether interrupts are inhibited by NMI. + * + * @retval true if interrupts are inhibited by NMI handling. + * @retval false if interrupts are not inhibited by NMI handling. + * @param pCtx Current guest CPU context. + */ +DECLINLINE(bool) CPUMAreInterruptsInhibitedByNmiEx(PCCPUMCTX pCtx) +{ + /* See CPUMUpdateInterruptInhibitingByNmiEx for comments. */ + if ( !CPUMIsGuestInVmxNonRootMode(pCtx) + || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)) + return CPUMAreInterruptsInhibitedByNmi(pCtx); + return CPUMIsGuestVmxVirtNmiBlocking(pCtx); +} + +/** + * Marks interrupts, include NMIs, as inhibited by pending NMI delivery. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMSetInterruptInhibitingByNmi(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_NMI; +} + +/** + * Extended version of CPUMSetInterruptInhibitingByNmi() that takes VMX non-root + * mode into account when marking interrupts as inhibited by NMI. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMSetInterruptInhibitingByNmiEx(PCPUMCTX pCtx) +{ + /* See CPUMUpdateInterruptInhibitingByNmiEx for comments. */ + if ( !CPUMIsGuestInVmxNonRootMode(pCtx) + || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)) + CPUMSetInterruptInhibitingByNmi(pCtx); + else + CPUMSetGuestVmxVirtNmiBlocking(pCtx, true); +} + +/** + * Marks interrupts, include NMIs, as no longer inhibited by pending NMI + * delivery. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMClearInterruptInhibitingByNmi(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_NMI; +} + +/** + * Extended version of CPUMClearInterruptInhibitingByNmi() that takes VMX + * non-root mode into account when doing the updating. + * + * @param pCtx Current guest CPU context. + */ +DECLINLINE(void) CPUMClearInterruptInhibitingByNmiEx(PCPUMCTX pCtx) +{ + /* See CPUMUpdateInterruptInhibitingByNmiEx for comments. */ + if ( !CPUMIsGuestInVmxNonRootMode(pCtx) + || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)) + CPUMClearInterruptInhibitingByNmi(pCtx); + else + CPUMSetGuestVmxVirtNmiBlocking(pCtx, false); +} + +/** + * Update whether interrupts, include NMIs, are inhibited by pending NMI + * delivery. + * + * @param pCtx Current guest CPU context. + * @param fInhibited The new state. + */ +DECLINLINE(void) CPUMUpdateInterruptInhibitingByNmi(PCPUMCTX pCtx, bool fInhibited) +{ + if (!fInhibited) + pCtx->eflags.uBoth &= ~CPUMCTX_INHIBIT_NMI; + else + pCtx->eflags.uBoth |= CPUMCTX_INHIBIT_NMI; +} + +/** + * Extended version of CPUMUpdateInterruptInhibitingByNmi() that takes VMX + * non-root mode into account when doing the updating. + * + * @param pCtx Current guest CPU context. + * @param fInhibited The new state. + */ +DECLINLINE(void) CPUMUpdateInterruptInhibitingByNmiEx(PCPUMCTX pCtx, bool fInhibited) +{ + /* + * Set the state of guest-NMI blocking in any of the following cases: + * - We're not executing a nested-guest. + * - We're executing an SVM nested-guest[1]. + * - We're executing a VMX nested-guest without virtual-NMIs enabled. + * + * [1] -- SVM does not support virtual-NMIs or virtual-NMI blocking. + * SVM hypervisors must track NMI blocking themselves by intercepting + * the IRET instruction after injection of an NMI. + */ + if ( !CPUMIsGuestInVmxNonRootMode(pCtx) + || !CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)) + CPUMUpdateInterruptInhibitingByNmi(pCtx, fInhibited); + /* + * Set the state of virtual-NMI blocking, if we are executing a + * VMX nested-guest with virtual-NMIs enabled. + */ + else + CPUMSetGuestVmxVirtNmiBlocking(pCtx, fInhibited); +} + + +/** + * Checks if we are executing inside an SVM nested hardware-virtualized guest. + * + * @returns @c true if in SVM nested-guest mode, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInSvmNestedHwVirtMode(PCCPUMCTX pCtx) +{ + /* + * With AMD-V, the VMRUN intercept is a pre-requisite to entering SVM guest-mode. + * See AMD spec. 15.5 "VMRUN instruction" subsection "Canonicalization and Consistency Checks". + */ +#ifndef IN_RC + if ( pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM + || !(pCtx->hwvirt.svm.Vmcb.ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMRUN)) + return false; + return true; +#else + NOREF(pCtx); + return false; +#endif +} + +/** + * Checks if the guest is in VMX non-root operation. + * + * @returns @c true if in VMX non-root operation, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInVmxNonRootMode(PCCPUMCTX pCtx) +{ +#ifndef IN_RC + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_VMX) + return false; + Assert(!pCtx->hwvirt.vmx.fInVmxNonRootMode || pCtx->hwvirt.vmx.fInVmxRootMode); + return pCtx->hwvirt.vmx.fInVmxNonRootMode; +#else + NOREF(pCtx); + return false; +#endif +} + +/** + * Checks if we are executing inside an SVM or VMX nested hardware-virtualized + * guest. + * + * @returns @c true if in nested-guest mode, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInNestedHwvirtMode(PCCPUMCTX pCtx) +{ +#if 0 + return CPUMIsGuestInVmxNonRootMode(pCtx) || CPUMIsGuestInSvmNestedHwVirtMode(pCtx); +#else + if (pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_NONE) + return false; + if (pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_VMX) + { + Assert(!pCtx->hwvirt.vmx.fInVmxNonRootMode || pCtx->hwvirt.vmx.fInVmxRootMode); + return pCtx->hwvirt.vmx.fInVmxNonRootMode; + } + Assert(pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_SVM); + return RT_BOOL(pCtx->hwvirt.svm.Vmcb.ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMRUN); +#endif +} + +/** + * Checks if we are executing inside an SVM or VMX nested hardware-virtualized + * guest. + * + * @retval CPUMHWVIRT_NONE if not in SVM or VMX non-root mode. + * @retval CPUMHWVIRT_VMX if in VMX non-root mode. + * @retval CPUMHWVIRT_SVM if in SVM non-root mode. + * @param pCtx Current CPU context. + */ +DECLINLINE(CPUMHWVIRT) CPUMGetGuestInNestedHwvirtMode(PCCPUMCTX pCtx) +{ + if (pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_NONE) + return CPUMHWVIRT_NONE; + if (pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_VMX) + { + Assert(!pCtx->hwvirt.vmx.fInVmxNonRootMode || pCtx->hwvirt.vmx.fInVmxRootMode); + return pCtx->hwvirt.vmx.fInVmxNonRootMode ? CPUMHWVIRT_VMX : CPUMHWVIRT_NONE; + } + Assert(pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_SVM); + return pCtx->hwvirt.svm.Vmcb.ctrl.u64InterceptCtrl & SVM_CTRL_INTERCEPT_VMRUN ? CPUMHWVIRT_SVM : CPUMHWVIRT_NONE; +} + +/** + * Checks if the guest is in VMX root operation. + * + * @returns @c true if in VMX root operation, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestInVmxRootMode(PCCPUMCTX pCtx) +{ +#ifndef IN_RC + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_VMX) + return false; + return pCtx->hwvirt.vmx.fInVmxRootMode; +#else + NOREF(pCtx); + return false; +#endif +} + +# ifndef IN_RC + +/** + * Checks if the nested-guest VMCB has the specified ctrl/instruction intercept + * active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param fIntercept The SVM control/instruction intercept, see + * SVM_CTRL_INTERCEPT_*. + */ +DECLINLINE(bool) CPUMIsGuestSvmCtrlInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint64_t fIntercept) +{ + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint64_t u64Intercepts; + if (!HMGetGuestSvmCtrlIntercepts(pVCpu, &u64Intercepts)) + u64Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u64InterceptCtrl; + return RT_BOOL(u64Intercepts & fIntercept); +} + +/** + * Checks if the nested-guest VMCB has the specified CR read intercept active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uCr The CR register number (0 to 15). + */ +DECLINLINE(bool) CPUMIsGuestSvmReadCRxInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uCr) +{ + Assert(uCr < 16); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16Intercepts; + if (!HMGetGuestSvmReadCRxIntercepts(pVCpu, &u16Intercepts)) + u16Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u16InterceptRdCRx; + return RT_BOOL(u16Intercepts & (UINT16_C(1) << uCr)); +} + +/** + * Checks if the nested-guest VMCB has the specified CR write intercept active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uCr The CR register number (0 to 15). + */ +DECLINLINE(bool) CPUMIsGuestSvmWriteCRxInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uCr) +{ + Assert(uCr < 16); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16Intercepts; + if (!HMGetGuestSvmWriteCRxIntercepts(pVCpu, &u16Intercepts)) + u16Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u16InterceptWrCRx; + return RT_BOOL(u16Intercepts & (UINT16_C(1) << uCr)); +} + +/** + * Checks if the nested-guest VMCB has the specified DR read intercept active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uDr The DR register number (0 to 15). + */ +DECLINLINE(bool) CPUMIsGuestSvmReadDRxInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uDr) +{ + Assert(uDr < 16); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16Intercepts; + if (!HMGetGuestSvmReadDRxIntercepts(pVCpu, &u16Intercepts)) + u16Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u16InterceptRdDRx; + return RT_BOOL(u16Intercepts & (UINT16_C(1) << uDr)); +} + +/** + * Checks if the nested-guest VMCB has the specified DR write intercept active. + * + * @returns @c true if in intercept is set, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uDr The DR register number (0 to 15). + */ +DECLINLINE(bool) CPUMIsGuestSvmWriteDRxInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uDr) +{ + Assert(uDr < 16); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16Intercepts; + if (!HMGetGuestSvmWriteDRxIntercepts(pVCpu, &u16Intercepts)) + u16Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u16InterceptWrDRx; + return RT_BOOL(u16Intercepts & (UINT16_C(1) << uDr)); +} + +/** + * Checks if the nested-guest VMCB has the specified exception intercept active. + * + * @returns @c true if in intercept is active, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param uVector The exception / interrupt vector. + */ +DECLINLINE(bool) CPUMIsGuestSvmXcptInterceptSet(PCVMCPU pVCpu, PCCPUMCTX pCtx, uint8_t uVector) +{ + Assert(uVector <= X86_XCPT_LAST); + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint32_t u32Intercepts; + if (!HMGetGuestSvmXcptIntercepts(pVCpu, &u32Intercepts)) + u32Intercepts = pCtx->hwvirt.svm.Vmcb.ctrl.u32InterceptXcpt; + return RT_BOOL(u32Intercepts & RT_BIT(uVector)); +} + +/** + * Checks if the nested-guest VMCB has virtual-interrupt masking enabled. + * + * @returns @c true if virtual-interrupts are masked, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * + * @remarks Should only be called when SVM feature is exposed to the guest. + */ +DECLINLINE(bool) CPUMIsGuestSvmVirtIntrMasking(PCVMCPU pVCpu, PCCPUMCTX pCtx) +{ + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + bool fVIntrMasking; + if (!HMGetGuestSvmVirtIntrMasking(pVCpu, &fVIntrMasking)) + fVIntrMasking = pCtx->hwvirt.svm.Vmcb.ctrl.IntCtrl.n.u1VIntrMasking; + return fVIntrMasking; +} + +/** + * Checks if the nested-guest VMCB has nested-paging enabled. + * + * @returns @c true if nested-paging is enabled, @c false otherwise. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * + * @remarks Should only be called when SVM feature is exposed to the guest. + */ +DECLINLINE(bool) CPUMIsGuestSvmNestedPagingEnabled(PCVMCPU pVCpu, PCCPUMCTX pCtx) +{ + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + bool fNestedPaging; + if (!HMGetGuestSvmNestedPaging(pVCpu, &fNestedPaging)) + fNestedPaging = pCtx->hwvirt.svm.Vmcb.ctrl.NestedPagingCtrl.n.u1NestedPaging; + return fNestedPaging; +} + +/** + * Gets the nested-guest VMCB pause-filter count. + * + * @returns The pause-filter count. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * + * @remarks Should only be called when SVM feature is exposed to the guest. + */ +DECLINLINE(uint16_t) CPUMGetGuestSvmPauseFilterCount(PCVMCPU pVCpu, PCCPUMCTX pCtx) +{ + if (pCtx->hwvirt.enmHwvirt != CPUMHWVIRT_SVM) + return false; + uint16_t u16PauseFilterCount; + if (!HMGetGuestSvmPauseFilterCount(pVCpu, &u16PauseFilterCount)) + u16PauseFilterCount = pCtx->hwvirt.svm.Vmcb.ctrl.u16PauseFilterCount; + return u16PauseFilterCount; +} + +/** + * Updates the NextRIP (NRIP) field in the nested-guest VMCB. + * + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pCtx Current CPU context. + * @param cbInstr The length of the current instruction in bytes. + * + * @remarks Should only be called when SVM feature is exposed to the guest. + */ +DECLINLINE(void) CPUMGuestSvmUpdateNRip(PVMCPU pVCpu, PCPUMCTX pCtx, uint8_t cbInstr) +{ + RT_NOREF(pVCpu); + Assert(pCtx->hwvirt.enmHwvirt == CPUMHWVIRT_SVM); + pCtx->hwvirt.svm.Vmcb.ctrl.u64NextRIP = pCtx->rip + cbInstr; +} + +/** + * Checks whether one of the given Pin-based VM-execution controls are set when + * executing a nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uPinCtls The Pin-based VM-execution controls to check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uPinCtl. + */ +DECLINLINE(bool) CPUMIsGuestVmxPinCtlsSet(PCCPUMCTX pCtx, uint32_t uPinCtls) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32PinCtls & uPinCtls); +} + +/** + * Checks whether one of the given Processor-based VM-execution controls are set + * when executing a nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uProcCtls The Processor-based VM-execution controls to check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uProcCtls. + */ +DECLINLINE(bool) CPUMIsGuestVmxProcCtlsSet(PCCPUMCTX pCtx, uint32_t uProcCtls) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32ProcCtls & uProcCtls); +} + +/** + * Checks whether one of the given Secondary Processor-based VM-execution controls + * are set when executing a nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uProcCtls2 The Secondary Processor-based VM-execution controls to + * check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uProcCtls2. + */ +DECLINLINE(bool) CPUMIsGuestVmxProcCtls2Set(PCCPUMCTX pCtx, uint32_t uProcCtls2) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32ProcCtls2 & uProcCtls2); +} + +/** + * Checks whether one of the given Tertiary Processor-based VM-execution controls + * are set when executing a nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uProcCtls3 The Tertiary Processor-based VM-execution controls to + * check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uProcCtls3. + */ +DECLINLINE(bool) CPUMIsGuestVmxProcCtls3Set(PCCPUMCTX pCtx, uint64_t uProcCtls3) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u64ProcCtls3.u & uProcCtls3); +} + +/** + * Checks whether one of the given VM-exit controls are set when executing a + * nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uExitCtls The VM-exit controls to check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uExitCtls. + */ +DECLINLINE(bool) CPUMIsGuestVmxExitCtlsSet(PCCPUMCTX pCtx, uint32_t uExitCtls) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32ExitCtls & uExitCtls); +} + +/** + * Checks whether one of the given VM-entry controls are set when executing a + * nested-guest. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + * @param uEntryCtls The VM-entry controls to check. + * + * @remarks This does not check if all given controls are set if more than one + * control is passed in @a uEntryCtls. + */ +DECLINLINE(bool) CPUMIsGuestVmxEntryCtlsSet(PCCPUMCTX pCtx, uint32_t uEntryCtls) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32EntryCtls & uEntryCtls); +} + +/** + * Checks whether events injected in the nested-guest are subject to VM-exit checks. + * + * @returns @c true if set, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxInterceptEvents(PCCPUMCTX pCtx) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return pCtx->hwvirt.vmx.fInterceptEvents; +} + +/** + * Sets whether events injected in the nested-guest are subject to VM-exit checks. + * + * @param pCtx Current CPU context. + * @param fIntercept Whether to subject injected events to VM-exits or not. + */ +DECLINLINE(void) CPUMSetGuestVmxInterceptEvents(PCPUMCTX pCtx, bool fInterceptEvents) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + pCtx->hwvirt.vmx.fInterceptEvents = fInterceptEvents; +} + +/** + * Checks whether the given exception causes a VM-exit. + * + * The exception type include hardware exceptions, software exceptions (#BP, #OF) + * and privileged software exceptions (#DB generated by INT1/ICEBP). + * + * Software interrupts do -not- cause VM-exits and hence must not be used with this + * function. + * + * @returns @c true if the exception causes a VM-exit, @c false otherwise. + * @param pCtx Current CPU context. + * @param uVector The exception vector. + * @param uErrCode The error code associated with the exception. Pass 0 if not + * applicable. + */ +DECLINLINE(bool) CPUMIsGuestVmxXcptInterceptSet(PCCPUMCTX pCtx, uint8_t uVector, uint32_t uErrCode) +{ + Assert(uVector <= X86_XCPT_LAST); + + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + + /* NMIs have a dedicated VM-execution control for causing VM-exits. */ + if (uVector == X86_XCPT_NMI) + return RT_BOOL(pCtx->hwvirt.vmx.Vmcs.u32PinCtls & VMX_PIN_CTLS_NMI_EXIT); + + /* Page-faults are subject to masking using its error code. */ + uint32_t fXcptBitmap = pCtx->hwvirt.vmx.Vmcs.u32XcptBitmap; + if (uVector == X86_XCPT_PF) + { + uint32_t const fXcptPFMask = pCtx->hwvirt.vmx.Vmcs.u32XcptPFMask; + uint32_t const fXcptPFMatch = pCtx->hwvirt.vmx.Vmcs.u32XcptPFMatch; + if ((uErrCode & fXcptPFMask) != fXcptPFMatch) + fXcptBitmap ^= RT_BIT(X86_XCPT_PF); + } + + /* Consult the exception bitmap for all other exceptions. */ + if (fXcptBitmap & RT_BIT(uVector)) + return true; + return false; +} + + +/** + * Checks whether the guest is in VMX non-root mode and using EPT paging. + * + * @returns @c true if in VMX non-root operation with EPT, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxEptPagingEnabledEx(PCCPUMCTX pCtx) +{ + return CPUMIsGuestInVmxNonRootMode(pCtx) + && CPUMIsGuestVmxProcCtls2Set(pCtx, VMX_PROC_CTLS2_EPT); +} + + +/** + * Implements VMSucceed for VMX instruction success. + * + * @param pCtx Current CPU context. + */ +DECLINLINE(void) CPUMSetGuestVmxVmSucceed(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth &= ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF); +} + +/** + * Implements VMFailInvalid for VMX instruction failure. + * + * @param pCtx Current CPU context. + */ +DECLINLINE(void) CPUMSetGuestVmxVmFailInvalid(PCPUMCTX pCtx) +{ + pCtx->eflags.uBoth &= ~(X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF); + pCtx->eflags.uBoth |= X86_EFL_CF; +} + +/** + * Implements VMFailValid for VMX instruction failure. + * + * @param pCtx Current CPU context. + * @param enmInsErr The VM instruction error. + */ +DECLINLINE(void) CPUMSetGuestVmxVmFailValid(PCPUMCTX pCtx, VMXINSTRERR enmInsErr) +{ + pCtx->eflags.uBoth &= ~(X86_EFL_CF | X86_EFL_PF | X86_EFL_AF | X86_EFL_ZF | X86_EFL_SF | X86_EFL_OF); + pCtx->eflags.uBoth |= X86_EFL_ZF; + pCtx->hwvirt.vmx.Vmcs.u32RoVmInstrError = enmInsErr; +} + +/** + * Implements VMFail for VMX instruction failure. + * + * @param pCtx Current CPU context. + * @param enmInsErr The VM instruction error. + */ +DECLINLINE(void) CPUMSetGuestVmxVmFail(PCPUMCTX pCtx, VMXINSTRERR enmInsErr) +{ + if (pCtx->hwvirt.vmx.GCPhysVmcs != NIL_RTGCPHYS) + CPUMSetGuestVmxVmFailValid(pCtx, enmInsErr); + else + CPUMSetGuestVmxVmFailInvalid(pCtx); +} + +/** + * Returns the guest-physical address of the APIC-access page when executing a + * nested-guest. + * + * @returns The APIC-access page guest-physical address. + * @param pCtx Current CPU context. + */ +DECLINLINE(uint64_t) CPUMGetGuestVmxApicAccessPageAddrEx(PCCPUMCTX pCtx) +{ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return pCtx->hwvirt.vmx.Vmcs.u64AddrApicAccess.u; +} + +/** + * Gets the nested-guest CR0 subject to the guest/host mask and the read-shadow. + * + * @returns The nested-guest CR0. + * @param pCtx Current CPU context. + * @param fGstHostMask The CR0 guest/host mask to use. + */ +DECLINLINE(uint64_t) CPUMGetGuestVmxMaskedCr0(PCCPUMCTX pCtx, uint64_t fGstHostMask) +{ + /* + * For each CR0 bit owned by the host, the corresponding bit from the + * CR0 read shadow is loaded. For each CR0 bit that is not owned by the host, + * the corresponding bit from the guest CR0 is loaded. + * + * See Intel Spec. 25.3 "Changes To Instruction Behavior In VMX Non-root Operation". + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + uint64_t const uGstCr0 = pCtx->cr0; + uint64_t const fReadShadow = pCtx->hwvirt.vmx.Vmcs.u64Cr0ReadShadow.u; + return (fReadShadow & fGstHostMask) | (uGstCr0 & ~fGstHostMask); +} + +/** + * Gets the nested-guest CR4 subject to the guest/host mask and the read-shadow. + * + * @returns The nested-guest CR4. + * @param pCtx Current CPU context. + * @param fGstHostMask The CR4 guest/host mask to use. + */ +DECLINLINE(uint64_t) CPUMGetGuestVmxMaskedCr4(PCCPUMCTX pCtx, uint64_t fGstHostMask) +{ + /* + * For each CR4 bit owned by the host, the corresponding bit from the + * CR4 read shadow is loaded. For each CR4 bit that is not owned by the host, + * the corresponding bit from the guest CR4 is loaded. + * + * See Intel Spec. 25.3 "Changes To Instruction Behavior In VMX Non-root Operation". + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + uint64_t const uGstCr4 = pCtx->cr4; + uint64_t const fReadShadow = pCtx->hwvirt.vmx.Vmcs.u64Cr4ReadShadow.u; + return (fReadShadow & fGstHostMask) | (uGstCr4 & ~fGstHostMask); +} + +/** + * Checks whether the LMSW access causes a VM-exit or not. + * + * @returns @c true if the LMSW access causes a VM-exit, @c false otherwise. + * @param pCtx Current CPU context. + * @param uNewMsw The LMSW source operand (the Machine Status Word). + */ +DECLINLINE(bool) CPUMIsGuestVmxLmswInterceptSet(PCCPUMCTX pCtx, uint16_t uNewMsw) +{ + /* + * LMSW VM-exits are subject to the CR0 guest/host mask and the CR0 read shadow. + * + * See Intel spec. 24.6.6 "Guest/Host Masks and Read Shadows for CR0 and CR4". + * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally". + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + + uint32_t const fGstHostMask = (uint32_t)pCtx->hwvirt.vmx.Vmcs.u64Cr0Mask.u; + uint32_t const fReadShadow = (uint32_t)pCtx->hwvirt.vmx.Vmcs.u64Cr0ReadShadow.u; + + /* + * LMSW can never clear CR0.PE but it may set it. Hence, we handle the + * CR0.PE case first, before the rest of the bits in the MSW. + * + * If CR0.PE is owned by the host and CR0.PE differs between the + * MSW (source operand) and the read-shadow, we must cause a VM-exit. + */ + if ( (fGstHostMask & X86_CR0_PE) + && (uNewMsw & X86_CR0_PE) + && !(fReadShadow & X86_CR0_PE)) + return true; + + /* + * If CR0.MP, CR0.EM or CR0.TS is owned by the host, and the corresponding + * bits differ between the MSW (source operand) and the read-shadow, we must + * cause a VM-exit. + */ + uint32_t const fGstHostLmswMask = fGstHostMask & (X86_CR0_MP | X86_CR0_EM | X86_CR0_TS); + if ((fReadShadow & fGstHostLmswMask) != (uNewMsw & fGstHostLmswMask)) + return true; + + return false; +} + +/** + * Checks whether the Mov-to-CR0/CR4 access causes a VM-exit or not. + * + * @returns @c true if the Mov CRX access causes a VM-exit, @c false otherwise. + * @param pCtx Current CPU context. + * @param iCrReg The control register number (must be 0 or 4). + * @param uNewCrX The CR0/CR4 value being written. + */ +DECLINLINE(bool) CPUMIsGuestVmxMovToCr0Cr4InterceptSet(PCCPUMCTX pCtx, uint8_t iCrReg, uint64_t uNewCrX) +{ + /* + * For any CR0/CR4 bit owned by the host (in the CR0/CR4 guest/host mask), if the + * corresponding bits differ between the source operand and the read-shadow, + * we must cause a VM-exit. + * + * See Intel spec. 25.1.3 "Instructions That Cause VM Exits Conditionally". + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + Assert(iCrReg == 0 || iCrReg == 4); + + uint64_t fGstHostMask; + uint64_t fReadShadow; + if (iCrReg == 0) + { + fGstHostMask = pCtx->hwvirt.vmx.Vmcs.u64Cr0Mask.u; + fReadShadow = pCtx->hwvirt.vmx.Vmcs.u64Cr0ReadShadow.u; + } + else + { + fGstHostMask = pCtx->hwvirt.vmx.Vmcs.u64Cr4Mask.u; + fReadShadow = pCtx->hwvirt.vmx.Vmcs.u64Cr4ReadShadow.u; + } + + if ((fReadShadow & fGstHostMask) != (uNewCrX & fGstHostMask)) + { + Assert(fGstHostMask != 0); + return true; + } + + return false; +} + +/** + * Returns whether the guest has an active, current VMCS. + * + * @returns @c true if the guest has an active, current VMCS, @c false otherwise. + * @param pCtx Current CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxCurrentVmcsValid(PCCPUMCTX pCtx) +{ + return pCtx->hwvirt.vmx.GCPhysVmcs != NIL_RTGCPHYS; +} + +# endif /* !IN_RC */ + +/** + * Checks whether the VMX nested-guest is in a state to receive physical (APIC) + * interrupts. + * + * @returns @c true if it's ready, @c false otherwise. + * @param pCtx The guest-CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxPhysIntrEnabled(PCCPUMCTX pCtx) +{ +#ifdef IN_RC + AssertReleaseFailedReturn(false); +#else + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + if (CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_EXT_INT_EXIT)) + return true; + return RT_BOOL(pCtx->eflags.u & X86_EFL_IF); +#endif +} + +/** + * Checks whether the VMX nested-guest is blocking virtual-NMIs. + * + * @returns @c true if it's blocked, @c false otherwise. + * @param pCtx The guest-CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxVirtNmiBlocking(PCCPUMCTX pCtx) +{ +#ifdef IN_RC + RT_NOREF(pCtx); + AssertReleaseFailedReturn(false); +#else + /* + * Return the state of virtual-NMI blocking, if we are executing a + * VMX nested-guest with virtual-NMIs enabled. + */ + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + Assert(CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)); + return pCtx->hwvirt.vmx.fVirtNmiBlocking; +#endif +} + +/** + * Sets or clears VMX nested-guest virtual-NMI blocking. + * + * @param pCtx The guest-CPU context. + * @param fBlocking Whether virtual-NMI blocking is in effect or not. + */ +DECLINLINE(void) CPUMSetGuestVmxVirtNmiBlocking(PCPUMCTX pCtx, bool fBlocking) +{ +#ifdef IN_RC + RT_NOREF2(pCtx, fBlocking); + AssertReleaseFailedReturnVoid(); +#else + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + Assert(CPUMIsGuestVmxPinCtlsSet(pCtx, VMX_PIN_CTLS_VIRT_NMI)); + pCtx->hwvirt.vmx.fVirtNmiBlocking = fBlocking; +#endif +} + +/** + * Checks whether the VMX nested-guest is in a state to receive virtual interrupts + * (those injected with the "virtual-interrupt delivery" feature). + * + * @returns @c true if it's ready, @c false otherwise. + * @param pCtx The guest-CPU context. + */ +DECLINLINE(bool) CPUMIsGuestVmxVirtIntrEnabled(PCCPUMCTX pCtx) +{ +#ifdef IN_RC + RT_NOREF2(pCtx); + AssertReleaseFailedReturn(false); +#else + Assert(CPUMIsGuestInVmxNonRootMode(pCtx)); + return RT_BOOL(pCtx->eflags.u & X86_EFL_IF); +#endif +} + +/** @} */ +#endif /* !IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS || DOXYGEN_RUNNING */ + + + +/** @name Hypervisor Register Getters. + * @{ */ +VMMDECL(RTGCUINTREG) CPUMGetHyperDR0(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR1(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR2(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR3(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR6(PVMCPU pVCpu); +VMMDECL(RTGCUINTREG) CPUMGetHyperDR7(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetHyperCR3(PVMCPU pVCpu); +/** @} */ + +/** @name Hypervisor Register Setters. + * @{ */ +VMMDECL(void) CPUMSetHyperCR3(PVMCPU pVCpu, uint32_t cr3); +VMMDECL(void) CPUMSetHyperDR0(PVMCPU pVCpu, RTGCUINTREG uDr0); +VMMDECL(void) CPUMSetHyperDR1(PVMCPU pVCpu, RTGCUINTREG uDr1); +VMMDECL(void) CPUMSetHyperDR2(PVMCPU pVCpu, RTGCUINTREG uDr2); +VMMDECL(void) CPUMSetHyperDR3(PVMCPU pVCpu, RTGCUINTREG uDr3); +VMMDECL(void) CPUMSetHyperDR6(PVMCPU pVCpu, RTGCUINTREG uDr6); +VMMDECL(void) CPUMSetHyperDR7(PVMCPU pVCpu, RTGCUINTREG uDr7); +VMMDECL(int) CPUMRecalcHyperDRx(PVMCPUCC pVCpu, uint8_t iGstReg); +/** @} */ + +VMMDECL(PCPUMCTX) CPUMQueryGuestCtxPtr(PVMCPU pVCpu); +#ifdef VBOX_INCLUDED_vmm_cpumctx_h +VMM_INT_DECL(PCPUMCTXMSRS) CPUMQueryGuestCtxMsrsPtr(PVMCPU pVCpu); +#endif + +/** @name Changed flags. + * These flags are used to keep track of which important register that + * have been changed since last they were reset. The only one allowed + * to clear them is REM! + * + * @todo This is obsolete, but remains as it will be refactored for coordinating + * IEM and NEM/HM later. Probably. + * @{ + */ +#define CPUM_CHANGED_FPU_REM RT_BIT(0) +#define CPUM_CHANGED_CR0 RT_BIT(1) +#define CPUM_CHANGED_CR4 RT_BIT(2) +#define CPUM_CHANGED_GLOBAL_TLB_FLUSH RT_BIT(3) +#define CPUM_CHANGED_CR3 RT_BIT(4) +#define CPUM_CHANGED_GDTR RT_BIT(5) +#define CPUM_CHANGED_IDTR RT_BIT(6) +#define CPUM_CHANGED_LDTR RT_BIT(7) +#define CPUM_CHANGED_TR RT_BIT(8) /**@< Currently unused. */ +#define CPUM_CHANGED_SYSENTER_MSR RT_BIT(9) +#define CPUM_CHANGED_HIDDEN_SEL_REGS RT_BIT(10) /**@< Currently unused. */ +#define CPUM_CHANGED_CPUID RT_BIT(11) +#define CPUM_CHANGED_ALL ( CPUM_CHANGED_FPU_REM \ + | CPUM_CHANGED_CR0 \ + | CPUM_CHANGED_CR4 \ + | CPUM_CHANGED_GLOBAL_TLB_FLUSH \ + | CPUM_CHANGED_CR3 \ + | CPUM_CHANGED_GDTR \ + | CPUM_CHANGED_IDTR \ + | CPUM_CHANGED_LDTR \ + | CPUM_CHANGED_TR \ + | CPUM_CHANGED_SYSENTER_MSR \ + | CPUM_CHANGED_HIDDEN_SEL_REGS \ + | CPUM_CHANGED_CPUID ) +/** @} */ + +VMMDECL(void) CPUMSetChangedFlags(PVMCPU pVCpu, uint32_t fChangedAdd); +VMMDECL(bool) CPUMSupportsXSave(PVM pVM); +VMMDECL(bool) CPUMIsHostUsingSysEnter(PVM pVM); +VMMDECL(bool) CPUMIsHostUsingSysCall(PVM pVM); +VMMDECL(bool) CPUMIsGuestFPUStateActive(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestFPUStateLoaded(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsHostFPUStateSaved(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsGuestDebugStateActive(PVMCPU pVCpu); +VMMDECL(void) CPUMDeactivateGuestDebugState(PVMCPU pVCpu); +VMMDECL(bool) CPUMIsHyperDebugStateActive(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestCPL(PVMCPU pVCpu); +VMMDECL(CPUMMODE) CPUMGetGuestMode(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestCodeBits(PVMCPU pVCpu); +VMMDECL(DISCPUMODE) CPUMGetGuestDisMode(PVMCPU pVCpu); +VMMDECL(uint32_t) CPUMGetGuestMxCsrMask(PVM pVM); +VMMDECL(uint64_t) CPUMGetGuestScalableBusFrequency(PVM pVM); +VMMDECL(uint64_t) CPUMGetGuestEferMsrValidMask(PVM pVM); +VMMDECL(int) CPUMIsGuestEferMsrWriteValid(PVM pVM, uint64_t uCr0, uint64_t uOldEfer, uint64_t uNewEfer, + uint64_t *puValidEfer); +VMMDECL(void) CPUMSetGuestEferMsrNoChecks(PVMCPUCC pVCpu, uint64_t uOldEfer, uint64_t uValidEfer); +VMMDECL(bool) CPUMIsPatMsrValid(uint64_t uValue); + + +/** Guest CPU interruptibility level, see CPUMGetGuestInterruptibility(). */ +typedef enum CPUMINTERRUPTIBILITY +{ + CPUMINTERRUPTIBILITY_INVALID = 0, + CPUMINTERRUPTIBILITY_UNRESTRAINED, + CPUMINTERRUPTIBILITY_VIRT_INT_DISABLED, + CPUMINTERRUPTIBILITY_INT_DISABLED, + CPUMINTERRUPTIBILITY_INT_INHIBITED, /**< @todo rename as it inhibits NMIs too. */ + CPUMINTERRUPTIBILITY_NMI_INHIBIT, + CPUMINTERRUPTIBILITY_GLOBAL_INHIBIT, + CPUMINTERRUPTIBILITY_END, + CPUMINTERRUPTIBILITY_32BIT_HACK = 0x7fffffff +} CPUMINTERRUPTIBILITY; + +VMM_INT_DECL(CPUMINTERRUPTIBILITY) CPUMGetGuestInterruptibility(PVMCPU pVCpu); + +/** @name Typical scalable bus frequency values. + * @{ */ +/** Special internal value indicating that we don't know the frequency. + * @internal */ +#define CPUM_SBUSFREQ_UNKNOWN UINT64_C(1) +#define CPUM_SBUSFREQ_100MHZ UINT64_C(100000000) +#define CPUM_SBUSFREQ_133MHZ UINT64_C(133333333) +#define CPUM_SBUSFREQ_167MHZ UINT64_C(166666666) +#define CPUM_SBUSFREQ_200MHZ UINT64_C(200000000) +#define CPUM_SBUSFREQ_267MHZ UINT64_C(266666666) +#define CPUM_SBUSFREQ_333MHZ UINT64_C(333333333) +#define CPUM_SBUSFREQ_400MHZ UINT64_C(400000000) +/** @} */ + + +#ifdef IN_RING3 +/** @defgroup grp_cpum_r3 The CPUM ring-3 API + * @{ + */ + +VMMR3DECL(int) CPUMR3Init(PVM pVM); +VMMR3DECL(int) CPUMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3DECL(void) CPUMR3LogCpuIdAndMsrFeatures(PVM pVM); +VMMR3DECL(void) CPUMR3Relocate(PVM pVM); +VMMR3DECL(int) CPUMR3Term(PVM pVM); +VMMR3DECL(void) CPUMR3Reset(PVM pVM); +VMMR3DECL(void) CPUMR3ResetCpu(PVM pVM, PVMCPU pVCpu); +VMMDECL(bool) CPUMR3IsStateRestorePending(PVM pVM); +VMMR3DECL(int) CPUMR3SetCR4Feature(PVM pVM, RTHCUINTREG fOr, RTHCUINTREG fAnd); + +VMMR3DECL(int) CPUMR3CpuIdInsert(PVM pVM, PCPUMCPUIDLEAF pNewLeaf); +VMMR3DECL(int) CPUMR3CpuIdGetLeaf(PVM pVM, PCPUMCPUIDLEAF pLeaf, uint32_t uLeaf, uint32_t uSubLeaf); +VMMR3_INT_DECL(PCCPUMCPUIDLEAF) CPUMR3CpuIdGetPtr(PVM pVM, uint32_t *pcLeaves); +VMMDECL(CPUMMICROARCH) CPUMCpuIdDetermineX86MicroarchEx(CPUMCPUVENDOR enmVendor, uint8_t bFamily, + uint8_t bModel, uint8_t bStepping); +VMMDECL(const char *) CPUMMicroarchName(CPUMMICROARCH enmMicroarch); +VMMR3DECL(int) CPUMR3CpuIdDetectUnknownLeafMethod(PCPUMUNKNOWNCPUID penmUnknownMethod, PCPUMCPUID pDefUnknown); +VMMR3DECL(const char *) CPUMR3CpuIdUnknownLeafMethodName(CPUMUNKNOWNCPUID enmUnknownMethod); +VMMR3DECL(const char *) CPUMCpuVendorName(CPUMCPUVENDOR enmVendor); +#if defined(RT_ARCH_X86) || defined(RT_ARCH_AMD64) +VMMR3DECL(uint32_t) CPUMR3DeterminHostMxCsrMask(void); +#endif + +VMMR3DECL(int) CPUMR3MsrRangesInsert(PVM pVM, PCCPUMMSRRANGE pNewRange); + +VMMR3DECL(uint32_t) CPUMR3DbGetEntries(void); +/** Pointer to CPUMR3DbGetEntries. */ +typedef DECLCALLBACKPTR(uint32_t, PFNCPUMDBGETENTRIES, (void)); +VMMR3DECL(PCCPUMDBENTRY) CPUMR3DbGetEntryByIndex(uint32_t idxCpuDb); +/** Pointer to CPUMR3DbGetEntryByIndex. */ +typedef DECLCALLBACKPTR(PCCPUMDBENTRY, PFNCPUMDBGETENTRYBYINDEX, (uint32_t idxCpuDb)); +VMMR3DECL(PCCPUMDBENTRY) CPUMR3DbGetEntryByName(const char *pszName); +/** Pointer to CPUMR3DbGetEntryByName. */ +typedef DECLCALLBACKPTR(PCCPUMDBENTRY, PFNCPUMDBGETENTRYBYNAME, (const char *pszName)); + +VMMR3_INT_DECL(void) CPUMR3NemActivateGuestDebugState(PVMCPUCC pVCpu); +VMMR3_INT_DECL(void) CPUMR3NemActivateHyperDebugState(PVMCPUCC pVCpu); +/** @} */ +#endif /* IN_RING3 */ + +#ifdef IN_RING0 +/** @defgroup grp_cpum_r0 The CPUM ring-0 API + * @{ + */ +VMMR0_INT_DECL(int) CPUMR0ModuleInit(void); +VMMR0_INT_DECL(int) CPUMR0ModuleTerm(void); +VMMR0_INT_DECL(void) CPUMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(int) CPUMR0InitVM(PVMCC pVM); +DECLASM(void) CPUMR0RegisterVCpuThread(PVMCPUCC pVCpu); +DECLASM(void) CPUMR0TouchHostFpu(void); +VMMR0_INT_DECL(int) CPUMR0Trap07Handler(PVMCC pVM, PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) CPUMR0LoadGuestFPU(PVMCC pVM, PVMCPUCC pVCpu); +VMMR0_INT_DECL(bool) CPUMR0FpuStateMaybeSaveGuestAndRestoreHost(PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) CPUMR0SaveHostDebugState(PVMCC pVM, PVMCPUCC pVCpu); +VMMR0_INT_DECL(bool) CPUMR0DebugStateMaybeSaveGuestAndRestoreHost(PVMCPUCC pVCpu, bool fDr6); +VMMR0_INT_DECL(bool) CPUMR0DebugStateMaybeSaveGuest(PVMCPUCC pVCpu, bool fDr6); + +VMMR0_INT_DECL(void) CPUMR0LoadGuestDebugState(PVMCPUCC pVCpu, bool fDr6); +VMMR0_INT_DECL(void) CPUMR0LoadHyperDebugState(PVMCPUCC pVCpu, bool fDr6); +/** @} */ +#endif /* IN_RING0 */ + +/** @defgroup grp_cpum_rz The CPUM raw-mode and ring-0 context API + * @{ + */ +VMMRZ_INT_DECL(void) CPUMRZFpuStatePrepareHostCpuForUse(PVMCPUCC pVCpu); +VMMRZ_INT_DECL(void) CPUMRZFpuStateActualizeForRead(PVMCPUCC pVCpu); +VMMRZ_INT_DECL(void) CPUMRZFpuStateActualizeForChange(PVMCPUCC pVCpu); +VMMRZ_INT_DECL(void) CPUMRZFpuStateActualizeSseForRead(PVMCPUCC pVCpu); +VMMRZ_INT_DECL(void) CPUMRZFpuStateActualizeAvxForRead(PVMCPUCC pVCpu); +/** @} */ + + +#endif /* !VBOX_FOR_DTRACE_LIB */ +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_cpum_h */ + diff --git a/include/VBox/vmm/cpum.mac b/include/VBox/vmm/cpum.mac new file mode 100644 index 00000000..dac92f61 --- /dev/null +++ b/include/VBox/vmm/cpum.mac @@ -0,0 +1,275 @@ +;; @file +; CPUM - CPU Monitor, Assembly header file. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_vmm_cpum_mac__ +%define ___VBox_vmm_cpum_mac__ + +%include "iprt/asmdefs.mac" + + +;; +; The volatile XSAVE components when VBOX_WITH_KERNEL_USING_XMM is active. +; @note ASSUMED to be at the most 32-bit in width at the moment. +%ifdef VBOX_WITH_KERNEL_USING_XMM + %define CPUM_VOLATILE_XSAVE_GUEST_COMPONENTS (XSAVE_C_SSE | XSAVE_C_YMM | XSAVE_C_ZMM_HI256 | XSAVE_C_ZMM_16HI) +%endif + +;; +; CPUID leaf. +; @remarks This structure is used by the patch manager and can only be extended +; by adding to the end of it. +struc CPUMCPUIDLEAF + .uLeaf resd 1 + .uSubLeaf resd 1 + .fSubLeafMask resd 1 + .uEax resd 1 + .uEbx resd 1 + .uEcx resd 1 + .uEdx resd 1 + .fFlags resd 1 +endstruc +%define CPUMCPUIDLEAF_F_INTEL_TOPOLOGY_SUBLEAVES RT_BIT_32(0) +%define CPUMCPUIDLEAF_F_CONTAINS_APIC_ID RT_BIT_32(1) +%define CPUMCPUIDLEAF_F_CONTAINS_OSXSAVE RT_BIT_32(2) +%define CPUMCPUIDLEAF_F_CONTAINS_APIC RT_BIT_32(3) + + +;; +; For the default CPUID leaf value. +; @remarks This is used by the patch manager and cannot be modified in any way. +struc CPUMCPUID + .uEax resd 1 + .uEbx resd 1 + .uEcx resd 1 + .uEdx resd 1 +endstruc + + +;; @name Method used to deal with unknown CPUID leaves. +;; @{ +%define CPUMUNKNOWNCPUID_DEFAULTS 1 +%define CPUMUNKNOWNCPUID_LAST_STD_LEAF 2 +%define CPUMUNKNOWNCPUID_LAST_STD_LEAF_WITH_ECX 3 +%define CPUMUNKNOWNCPUID_PASSTHRU 4 +;; @} + + +%define XSTATE_SIZE 8192 + +;; Note! Updates here must be reflected in CPUMInternal.mac too! +struc CPUMCTX + .eax resq 1 + .ecx resq 1 + .edx resq 1 + .ebx resq 1 + .esp resq 1 + .ebp resq 1 + .esi resq 1 + .edi resq 1 + .r8 resq 1 + .r9 resq 1 + .r10 resq 1 + .r11 resq 1 + .r12 resq 1 + .r13 resq 1 + .r14 resq 1 + .r15 resq 1 + .es.Sel resw 1 + .es.PaddingSel resw 1 + .es.ValidSel resw 1 + .es.fFlags resw 1 + .es.u64Base resq 1 + .es.u32Limit resd 1 + .es.Attr resd 1 + .cs.Sel resw 1 + .cs.PaddingSel resw 1 + .cs.ValidSel resw 1 + .cs.fFlags resw 1 + .cs.u64Base resq 1 + .cs.u32Limit resd 1 + .cs.Attr resd 1 + .ss.Sel resw 1 + .ss.PaddingSel resw 1 + .ss.ValidSel resw 1 + .ss.fFlags resw 1 + .ss.u64Base resq 1 + .ss.u32Limit resd 1 + .ss.Attr resd 1 + .ds.Sel resw 1 + .ds.PaddingSel resw 1 + .ds.ValidSel resw 1 + .ds.fFlags resw 1 + .ds.u64Base resq 1 + .ds.u32Limit resd 1 + .ds.Attr resd 1 + .fs.Sel resw 1 + .fs.PaddingSel resw 1 + .fs.ValidSel resw 1 + .fs.fFlags resw 1 + .fs.u64Base resq 1 + .fs.u32Limit resd 1 + .fs.Attr resd 1 + .gs.Sel resw 1 + .gs.PaddingSel resw 1 + .gs.ValidSel resw 1 + .gs.fFlags resw 1 + .gs.u64Base resq 1 + .gs.u32Limit resd 1 + .gs.Attr resd 1 + .ldtr.Sel resw 1 + .ldtr.PaddingSel resw 1 + .ldtr.ValidSel resw 1 + .ldtr.fFlags resw 1 + .ldtr.u64Base resq 1 + .ldtr.u32Limit resd 1 + .ldtr.Attr resd 1 + .tr.Sel resw 1 + .tr.PaddingSel resw 1 + .tr.ValidSel resw 1 + .tr.fFlags resw 1 + .tr.u64Base resq 1 + .tr.u32Limit resd 1 + .tr.Attr resd 1 + alignb 8 + .eip resq 1 + .eflags resq 1 + .fExtrn resq 1 + .uRipInhibitInt resq 1 + .cr0 resq 1 + .cr2 resq 1 + .cr3 resq 1 + .cr4 resq 1 + .dr resq 8 + .gdtrPadding resw 3 + .gdtr resw 0 + .gdtr.cbGdt resw 1 + .gdtr.pGdt resq 1 + .idtrPadding resw 3 + .idtr resw 0 + .idtr.cbIdt resw 1 + .idtr.pIdt resq 1 + .SysEnter.cs resb 8 + .SysEnter.eip resb 8 + .SysEnter.esp resb 8 + .msrEFER resb 8 + .msrSTAR resb 8 + .msrPAT resb 8 + .msrLSTAR resb 8 + .msrCSTAR resb 8 + .msrSFMASK resb 8 + .msrKERNELGSBASE resb 8 + + alignb 32 + .aPaePdpes resq 4 + + alignb 8 + .aXcr resq 2 + .fXStateMask resq 1 + .fUsedFpuGuest resb 1 + alignb 8 + .aoffXState resw 64 + alignb 256 + .abXState resb 0x4000-0x300 + .XState EQU .abXState + + alignb 4096 + .hwvirt resb 0 + .hwvirt.svm resb 0 + .hwvirt.vmx resb 0 + + .hwvirt.svm.Vmcb EQU .hwvirt.svm + .hwvirt.svm.abMsrBitmap EQU (.hwvirt.svm.Vmcb + 0x1000) + .hwvirt.svm.abIoBitmap EQU (.hwvirt.svm.abMsrBitmap + 0x2000) + .hwvirt.svm.uMsrHSavePa EQU (.hwvirt.svm.abIoBitmap + 0x3000) ; resq 1 + .hwvirt.svm.GCPhysVmcb EQU (.hwvirt.svm.uMsrHSavePa + 8) ; resq 1 + alignb 8 + .hwvirt.svm.HostState EQU (.hwvirt.svm.GCPhysVmcb + 8) ; resb 184 + .hwvirt.svm.uPrevPauseTick EQU (.hwvirt.svm.HostState + 184) ; resq 1 + .hwvirt.svm.cPauseFilter EQU (.hwvirt.svm.uPrevPauseTick + 8) ; resw 1 + .hwvirt.svm.cPauseFilterThreshold EQU (.hwvirt.svm.cPauseFilter + 2) ; resw 1 + .hwvirt.svm.fInterceptEvents EQU (.hwvirt.svm.cPauseFilterThreshold + 2) ; resb 1 + + .hwvirt.vmx.Vmcs resb 0x1000 + .hwvirt.vmx.ShadowVmcs resb 0x1000 + .hwvirt.vmx.abVmreadBitmap resb 0x1000 + .hwvirt.vmx.abVmwriteBitmap resb 0x1000 + .hwvirt.vmx.aEntryMsrLoadArea resb 0x2000 + .hwvirt.vmx.aExitMsrStoreArea resb 0x2000 + .hwvirt.vmx.aExitMsrLoadArea resb 0x2000 + .hwvirt.vmx.abMsrBitmap resb 0x1000 + .hwvirt.vmx.abIoBitmap resb 0x1000+0x1000 + alignb 8 + .hwvirt.vmx.GCPhysVmxon resq 1 + .hwvirt.vmx.GCPhysVmcs resq 1 + .hwvirt.vmx.GCPhysShadowVmcs resq 1 + .hwvirt.vmx.enmDiag resd 1 + .hwvirt.vmx.enmAbort resd 1 + .hwvirt.vmx.uDiagAux resq 1 + .hwvirt.vmx.uAbortAux resd 1 + .hwvirt.vmx.fInVmxRootMode resb 1 + .hwvirt.vmx.fInVmxNonRootMode resb 1 + .hwvirt.vmx.fInterceptEvents resb 1 + .hwvirt.vmx.fNmiUnblockingIret resb 1 + .hwvirt.vmx.uFirstPauseLoopTick resq 1 + .hwvirt.vmx.uPrevPauseTick resq 1 + .hwvirt.vmx.uEntryTick resq 1 + .hwvirt.vmx.offVirtApicWrite resw 1 + .hwvirt.vmx.fVirtNmiBlocking resb 1 + alignb 8 + .hwvirt.vmx.Msrs resb 224 + + alignb 8 + .hwvirt.enmHwvirt resd 1 + .hwvirt.fGif resb 1 + alignb 4 + .hwvirt.fSavedInhibit resd 1 + alignb 64 +endstruc + + +%define CPUMSELREG_FLAGS_VALID 0x0001 +%define CPUMSELREG_FLAGS_STALE 0x0002 +%define CPUMSELREG_FLAGS_VALID_MASK 0x0003 + + +;; +; Guest MSR state. +struc CPUMCTXMSRS + .au64 resq 64 +endstruc + + +%endif + diff --git a/include/VBox/vmm/cpumctx-v1_6.h b/include/VBox/vmm/cpumctx-v1_6.h new file mode 100644 index 00000000..fe6d30db --- /dev/null +++ b/include/VBox/vmm/cpumctx-v1_6.h @@ -0,0 +1,263 @@ +/** @file + * CPUM - CPU Monitor(/ Manager), Context Structures from v1.6 (saved state). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpumctx_v1_6_h +#define VBOX_INCLUDED_vmm_cpumctx_v1_6_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_cpum_ctx_v1_6 The CPUM Context Structures from v1.6 + * @ingroup grp_cpum + * @{ + */ + +#pragma pack(1) +/** IDTR from version 1.6 */ +typedef struct VBOXIDTR_VER1_6 +{ + /** Size of the IDT. */ + uint16_t cbIdt; + /** Address of the IDT. */ + uint32_t pIdt; +} VBOXIDTR_VER1_6; +#pragma pack() + +#pragma pack(1) +/** GDTR from version 1.6 */ +typedef struct VBOXGDTR_VER1_6 +{ + /** Size of the GDT. */ + uint16_t cbGdt; + /** Address of the GDT. */ + uint32_t pGdt; +} VBOXGDTR_VER1_6; +#pragma pack() + + +/** + * Selector hidden registers, for version 1.6 saved state. + */ +typedef struct CPUMSELREGHID_VER1_6 +{ + /** Base register. */ + uint32_t u32Base; + /** Limit (expanded). */ + uint32_t u32Limit; + /** Flags. + * This is the high 32-bit word of the descriptor entry. + * Only the flags, dpl and type are used. */ + X86DESCATTR Attr; +} CPUMSELREGHID_VER1_6; + +/** + * CPU context, for version 1.6 saved state. + * @remarks PATM uses this, which is why it has to be here. + */ +# pragma pack(1) +typedef struct CPUMCTX_VER1_6 +{ + /** FPU state. (16-byte alignment) + * @todo This doesn't have to be in X86FXSTATE on CPUs without fxsr - we need a type for the + * actual format or convert it (waste of time). */ + X86FXSTATE fpu; + + /** CPUMCTXCORE Part. + * @{ */ + union + { + uint32_t edi; + uint64_t rdi; + } CPUM_UNION_NM(rdi); + union + { + uint32_t esi; + uint64_t rsi; + } CPUM_UNION_NM(rsi); + union + { + uint32_t ebp; + uint64_t rbp; + } CPUM_UNION_NM(rbp); + union + { + uint32_t eax; + uint64_t rax; + } CPUM_UNION_NM(rax); + union + { + uint32_t ebx; + uint64_t rbx; + } CPUM_UNION_NM(rbx); + union + { + uint32_t edx; + uint64_t rdx; + } CPUM_UNION_NM(rdx); + union + { + uint32_t ecx; + uint64_t rcx; + } CPUM_UNION_NM(rcx); + /** @note We rely on the exact layout, because we use lss esp, [] in the + * switcher. */ + uint32_t esp; + RTSEL ss; + RTSEL ssPadding; + /* Note: no overlap with esp here. */ + uint64_t rsp_notused; + + RTSEL gs; + RTSEL gsPadding; + RTSEL fs; + RTSEL fsPadding; + RTSEL es; + RTSEL esPadding; + RTSEL ds; + RTSEL dsPadding; + RTSEL cs; + RTSEL csPadding[3]; /**< 3 words to force 8 byte alignment for the remainder. */ + + union + { + X86EFLAGS eflags; + X86RFLAGS rflags; + } CPUM_UNION_NM(rflags); + union + { + uint32_t eip; + uint64_t rip; + } CPUM_UNION_NM(rip); + + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + + /** Hidden selector registers. + * @{ */ + CPUMSELREGHID_VER1_6 esHid; + CPUMSELREGHID_VER1_6 csHid; + CPUMSELREGHID_VER1_6 ssHid; + CPUMSELREGHID_VER1_6 dsHid; + CPUMSELREGHID_VER1_6 fsHid; + CPUMSELREGHID_VER1_6 gsHid; + /** @} */ + + /** @} */ + + /** Control registers. + * @{ */ + uint64_t cr0; + uint64_t cr2; + uint64_t cr3; + uint64_t cr4; + uint64_t cr8; + /** @} */ + + /** Debug registers. + * @{ */ + uint64_t dr0; + uint64_t dr1; + uint64_t dr2; + uint64_t dr3; + uint64_t dr4; /**< @todo remove dr4 and dr5. */ + uint64_t dr5; + uint64_t dr6; + uint64_t dr7; + /* DR8-15 are currently not supported */ + /** @} */ + + /** Global Descriptor Table register. */ + VBOXGDTR_VER1_6 gdtr; + uint16_t gdtrPadding; + uint32_t gdtrPadding64;/** @todo fix this hack */ + /** Interrupt Descriptor Table register. */ + VBOXIDTR_VER1_6 idtr; + uint16_t idtrPadding; + uint32_t idtrPadding64;/** @todo fix this hack */ + /** The task register. + * Only the guest context uses all the members. */ + RTSEL ldtr; + RTSEL ldtrPadding; + /** The task register. + * Only the guest context uses all the members. */ + RTSEL tr; + RTSEL trPadding; + + /** The sysenter msr registers. + * This member is not used by the hypervisor context. */ + CPUMSYSENTER SysEnter; + + /** System MSRs. + * @{ */ + uint64_t msrEFER; + uint64_t msrSTAR; + uint64_t msrPAT; + uint64_t msrLSTAR; + uint64_t msrCSTAR; + uint64_t msrSFMASK; + uint64_t msrFSBASE; + uint64_t msrGSBASE; + uint64_t msrKERNELGSBASE; + /** @} */ + + /** Hidden selector registers. + * @{ */ + CPUMSELREGHID_VER1_6 ldtrHid; + CPUMSELREGHID_VER1_6 trHid; + /** @} */ + + /** padding to get 32byte aligned size. */ + uint32_t padding[2]; +} CPUMCTX_VER1_6; +# pragma pack() + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_cpumctx_v1_6_h */ + diff --git a/include/VBox/vmm/cpumctx.h b/include/VBox/vmm/cpumctx.h new file mode 100644 index 00000000..fd8a4fec --- /dev/null +++ b/include/VBox/vmm/cpumctx.h @@ -0,0 +1,1116 @@ +/** @file + * CPUM - CPU Monitor(/ Manager), Context Structures. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpumctx_h +#define VBOX_INCLUDED_vmm_cpumctx_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef VBOX_FOR_DTRACE_LIB +# include +# include +# include +# include +#else +# pragma D depends_on library x86.d +#endif + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_cpum_ctx The CPUM Context Structures + * @ingroup grp_cpum + * @{ + */ + +/** + * Selector hidden registers. + */ +typedef struct CPUMSELREG +{ + /** The selector register. */ + RTSEL Sel; + /** Padding, don't use. */ + RTSEL PaddingSel; + /** The selector which info resides in u64Base, u32Limit and Attr, provided + * that CPUMSELREG_FLAGS_VALID is set. */ + RTSEL ValidSel; + /** Flags, see CPUMSELREG_FLAGS_XXX. */ + uint16_t fFlags; + + /** Base register. + * + * Long mode remarks: + * - Unused in long mode for CS, DS, ES, SS + * - 32 bits for FS & GS; FS(GS)_BASE msr used for the base address + * - 64 bits for TR & LDTR + */ + uint64_t u64Base; + /** Limit (expanded). */ + uint32_t u32Limit; + /** Flags. + * This is the high 32-bit word of the descriptor entry. + * Only the flags, dpl and type are used. */ + X86DESCATTR Attr; +} CPUMSELREG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMSELREG, 24); +#endif + +/** @name CPUMSELREG_FLAGS_XXX - CPUMSELREG::fFlags values. + * @{ */ +#define CPUMSELREG_FLAGS_VALID UINT16_C(0x0001) +#define CPUMSELREG_FLAGS_STALE UINT16_C(0x0002) +#define CPUMSELREG_FLAGS_VALID_MASK UINT16_C(0x0003) +/** @} */ + +/** Checks if the hidden parts of the selector register are valid. */ +#define CPUMSELREG_ARE_HIDDEN_PARTS_VALID(a_pVCpu, a_pSelReg) \ + ( ((a_pSelReg)->fFlags & CPUMSELREG_FLAGS_VALID) \ + && (a_pSelReg)->ValidSel == (a_pSelReg)->Sel ) + +/** Old type used for the hidden register part. + * @deprecated */ +typedef CPUMSELREG CPUMSELREGHID; + +/** + * The sysenter register set. + */ +typedef struct CPUMSYSENTER +{ + /** Ring 0 cs. + * This value + 8 is the Ring 0 ss. + * This value + 16 is the Ring 3 cs. + * This value + 24 is the Ring 3 ss. + */ + uint64_t cs; + /** Ring 0 eip. */ + uint64_t eip; + /** Ring 0 esp. */ + uint64_t esp; +} CPUMSYSENTER; + +/** @def CPUM_UNION_NM + * For compilers (like DTrace) that does not grok nameless unions, we have a + * little hack to make them palatable. + */ +/** @def CPUM_STRUCT_NM + * For compilers (like DTrace) that does not grok nameless structs (it is + * non-standard C++), we have a little hack to make them palatable. + */ +#ifdef VBOX_FOR_DTRACE_LIB +# define CPUM_UNION_NM(a_Nm) a_Nm +# define CPUM_STRUCT_NM(a_Nm) a_Nm +#elif defined(IPRT_WITHOUT_NAMED_UNIONS_AND_STRUCTS) +# define CPUM_UNION_NM(a_Nm) a_Nm +# define CPUM_STRUCT_NM(a_Nm) a_Nm +#else +# define CPUM_UNION_NM(a_Nm) +# define CPUM_STRUCT_NM(a_Nm) +#endif +/** @def CPUM_UNION_STRUCT_NM + * Combines CPUM_UNION_NM and CPUM_STRUCT_NM to avoid hitting the right side of + * the screen in the compile time assertions. + */ +#define CPUM_UNION_STRUCT_NM(a_UnionNm, a_StructNm) CPUM_UNION_NM(a_UnionNm .) CPUM_STRUCT_NM(a_StructNm) + +/** A general register (union). */ +typedef union CPUMCTXGREG +{ + /** Natural unsigned integer view. */ + uint64_t u; + /** 64-bit view. */ + uint64_t u64; + /** 32-bit view. */ + uint32_t u32; + /** 16-bit view. */ + uint16_t u16; + /** 8-bit view. */ + uint8_t u8; + /** 8-bit low/high view. */ + RT_GCC_EXTENSION struct + { + /** Low byte (al, cl, dl, bl, ++). */ + uint8_t bLo; + /** High byte in the first word - ah, ch, dh, bh. */ + uint8_t bHi; + } CPUM_STRUCT_NM(s); +} CPUMCTXGREG; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMCTXGREG, 8); +AssertCompileMemberOffset(CPUMCTXGREG, CPUM_STRUCT_NM(s.) bLo, 0); +AssertCompileMemberOffset(CPUMCTXGREG, CPUM_STRUCT_NM(s.) bHi, 1); +#endif + + + +/** + * SVM Host-state area (Nested Hw.virt - VirtualBox's layout). + * + * @warning Exercise caution while modifying the layout of this struct. It's + * part of VM saved states. + */ +#pragma pack(1) +typedef struct SVMHOSTSTATE +{ + uint64_t uEferMsr; + uint64_t uCr0; + uint64_t uCr4; + uint64_t uCr3; + uint64_t uRip; + uint64_t uRsp; + uint64_t uRax; + X86RFLAGS rflags; + CPUMSELREG es; + CPUMSELREG cs; + CPUMSELREG ss; + CPUMSELREG ds; + VBOXGDTR gdtr; + VBOXIDTR idtr; + uint8_t abPadding[4]; +} SVMHOSTSTATE; +#pragma pack() +/** Pointer to the SVMHOSTSTATE structure. */ +typedef SVMHOSTSTATE *PSVMHOSTSTATE; +/** Pointer to a const SVMHOSTSTATE structure. */ +typedef const SVMHOSTSTATE *PCSVMHOSTSTATE; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSizeAlignment(SVMHOSTSTATE, 8); +AssertCompileSize(SVMHOSTSTATE, 184); +#endif + + +/** + * CPU hardware virtualization types. + */ +typedef enum +{ + CPUMHWVIRT_NONE = 0, + CPUMHWVIRT_VMX, + CPUMHWVIRT_SVM, + CPUMHWVIRT_32BIT_HACK = 0x7fffffff +} CPUMHWVIRT; +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSize(CPUMHWVIRT, 4); +#endif + +/** Number of EFLAGS bits we put aside for the hardware EFLAGS, with the bits + * above this we use for storing internal state not visible to the guest. + * + * Using a value less than 32 here means some code bloat when loading and + * fetching the hardware EFLAGS value. Comparing VMMR0.r0 text size when + * compiling release build using gcc 11.3.1 on linux: + * - 32 bits: 2475709 bytes + * - 24 bits: 2482069 bytes; +6360 bytes. + * - 22 bits: 2482261 bytes; +6552 bytes. + * Same for windows (virtual size of .text): + * - 32 bits: 1498502 bytes + * - 24 bits: 1502278 bytes; +3776 bytes. + * - 22 bits: 1502198 bytes; +3696 bytes. + * + * In addition we pass pointer the 32-bit EFLAGS to a number of IEM assembly + * functions, so it would be safer to not store anything in the lower 32 bits. + * OTOH, we'd sooner discover buggy assembly code by doing so, as we've had one + * example of accidental EFLAGS trashing by these functions already. + * + * It would be more efficient for IEM to store the interrupt shadow bit (and + * anything else that needs to be cleared at the same time) in the 30:22 bit + * range, because that would allow using a simple AND imm32 instruction on x86 + * and a MOVN imm16,16 instruction to load the constant on ARM64 (assuming the + * other flag needing clearing is RF (bit 16)). Putting it in the 63:32 range + * means we that on x86 we'll either use a memory variant of AND or require a + * separate load instruction for the immediate, whereas on ARM we'll need more + * instructions to construct the immediate value. + * + * Comparing the instruction exit thruput via the bs2-test-1 testcase, there + * seems to be little difference between 32 and 24 here (best results out of 9 + * runs on Linux/VT-x). So, unless the results are really wrong and there is + * clear drop in thruput, it would on the whole make the most sense to use 24 + * here. + * + * Update: We need more than 8 bits because of DBGF, so using 22 now. + */ +#define CPUMX86EFLAGS_HW_BITS 22 +/** Mask for the hardware EFLAGS bits, 64-bit version. */ +#define CPUMX86EFLAGS_HW_MASK_64 (RT_BIT_64(CPUMX86EFLAGS_HW_BITS) - UINT64_C(1)) +/** Mask for the hardware EFLAGS bits, 32-bit version. */ +#if CPUMX86EFLAGS_HW_BITS == 32 +# define CPUMX86EFLAGS_HW_MASK_32 UINT32_MAX +#elif CPUMX86EFLAGS_HW_BITS < 32 && CPUMX86EFLAGS_HW_BITS >= 22 +# define CPUMX86EFLAGS_HW_MASK_32 (RT_BIT_32(CPUMX86EFLAGS_HW_BITS) - UINT32_C(1)) +#else +# error "Misconfigured CPUMX86EFLAGS_HW_BITS value!" +#endif + +/** Mask of internal flags kept with EFLAGS, 64-bit version. + * Bits 22-24 are taken by CPUMCTX_INHIBIT_SHADOW_SS, CPUMCTX_INHIBIT_SHADOW_STI + * and CPUMCTX_INHIBIT_NMI, bits 25-28 are for CPUMCTX_DBG_HIT_DRX_MASK, and + * bits 29-30 are for DBGF events and breakpoints. + * + * @todo The two DBGF bits could be merged. The NMI inhibiting could move to + * bit 32 or higher as it isn't automatically cleared on instruction + * completion (except for iret). + */ +#define CPUMX86EFLAGS_INT_MASK_64 UINT64_C(0x00000000ffc00000) +/** Mask of internal flags kept with EFLAGS, 32-bit version. */ +#define CPUMX86EFLAGS_INT_MASK_32 UINT32_C(0xffc00000) + + +/** + * CPUM EFLAGS. + * + * This differs from X86EFLAGS in that we could use bits 31:22 for internal + * purposes, see CPUMX86EFLAGS_HW_BITS. + */ +typedef union CPUMX86EFLAGS +{ + /** The full unsigned view, both hardware and VBox bits. */ + uint32_t uBoth; + /** The plain unsigned view of the hardware bits. */ +#if CPUMX86EFLAGS_HW_BITS == 32 + uint32_t u; +#else + uint32_t u : CPUMX86EFLAGS_HW_BITS; +#endif +#ifndef VBOX_FOR_DTRACE_LIB + /** The bitfield view. */ + X86EFLAGSBITS Bits; +#endif +} CPUMX86EFLAGS; +/** Pointer to CPUM EFLAGS. */ +typedef CPUMX86EFLAGS *PCPUMX86EFLAGS; +/** Pointer to const CPUM EFLAGS. */ +typedef const CPUMX86EFLAGS *PCCPUMX86EFLAGS; + +/** + * CPUM RFLAGS. + * + * This differs from X86EFLAGS in that we use could be using bits 63:22 for + * internal purposes, see CPUMX86EFLAGS_HW_BITS. + */ +typedef union CPUMX86RFLAGS +{ + /** The full unsigned view, both hardware and VBox bits. */ + uint64_t uBoth; + /** The plain unsigned view of the hardware bits. */ +#if CPUMX86EFLAGS_HW_BITS == 32 + uint32_t u; +#else + uint32_t u : CPUMX86EFLAGS_HW_BITS; +#endif +#ifndef VBOX_FOR_DTRACE_LIB + /** The bitfield view. */ + X86EFLAGSBITS Bits; +#endif +} CPUMX86RFLAGS; +/** Pointer to CPUM RFLAGS. */ +typedef CPUMX86RFLAGS *PCPUMX86RFLAGS; +/** Pointer to const CPUM RFLAGS. */ +typedef const CPUMX86RFLAGS *PCCPUMX86RFLAGS; + + +/** + * CPU context. + */ +#pragma pack(1) /* for VBOXIDTR / VBOXGDTR. */ +typedef struct CPUMCTX +{ + /** General purpose registers. */ + union /* no tag! */ + { + /** The general purpose register array view, indexed by X86_GREG_XXX. */ + CPUMCTXGREG aGRegs[16]; + + /** 64-bit general purpose register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + uint64_t rax, rcx, rdx, rbx, rsp, rbp, rsi, rdi, r8, r9, r10, r11, r12, r13, r14, r15; + } CPUM_STRUCT_NM(qw); + /** 64-bit general purpose register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + uint64_t r0, r1, r2, r3, r4, r5, r6, r7; + } CPUM_STRUCT_NM(qw2); + /** 32-bit general purpose register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + uint32_t eax, u32Pad00, ecx, u32Pad01, edx, u32Pad02, ebx, u32Pad03, + esp, u32Pad04, ebp, u32Pad05, esi, u32Pad06, edi, u32Pad07, + r8d, u32Pad08, r9d, u32Pad09, r10d, u32Pad10, r11d, u32Pad11, + r12d, u32Pad12, r13d, u32Pad13, r14d, u32Pad14, r15d, u32Pad15; + } CPUM_STRUCT_NM(dw); + /** 16-bit general purpose register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + uint16_t ax, au16Pad00[3], cx, au16Pad01[3], dx, au16Pad02[3], bx, au16Pad03[3], + sp, au16Pad04[3], bp, au16Pad05[3], si, au16Pad06[3], di, au16Pad07[3], + r8w, au16Pad08[3], r9w, au16Pad09[3], r10w, au16Pad10[3], r11w, au16Pad11[3], + r12w, au16Pad12[3], r13w, au16Pad13[3], r14w, au16Pad14[3], r15w, au16Pad15[3]; + } CPUM_STRUCT_NM(w); + RT_GCC_EXTENSION struct /* no tag! */ + { + uint8_t al, ah, abPad00[6], cl, ch, abPad01[6], dl, dh, abPad02[6], bl, bh, abPad03[6], + spl, abPad04[7], bpl, abPad05[7], sil, abPad06[7], dil, abPad07[7], + r8l, abPad08[7], r9l, abPad09[7], r10l, abPad10[7], r11l, abPad11[7], + r12l, abPad12[7], r13l, abPad13[7], r14l, abPad14[7], r15l, abPad15[7]; + } CPUM_STRUCT_NM(b); + } CPUM_UNION_NM(g); + + /** Segment registers. */ + union /* no tag! */ + { + /** The segment register array view, indexed by X86_SREG_XXX. */ + CPUMSELREG aSRegs[6]; + /** The named segment register view. */ + RT_GCC_EXTENSION struct /* no tag! */ + { + CPUMSELREG es, cs, ss, ds, fs, gs; + } CPUM_STRUCT_NM(n); + } CPUM_UNION_NM(s); + + /** The task register. + * Only the guest context uses all the members. */ + CPUMSELREG ldtr; + /** The task register. + * Only the guest context uses all the members. */ + CPUMSELREG tr; + + /** The program counter. */ + union + { + uint16_t ip; + uint32_t eip; + uint64_t rip; + } CPUM_UNION_NM(rip); + + /** The flags register. */ + union + { + CPUMX86EFLAGS eflags; + CPUMX86RFLAGS rflags; + } CPUM_UNION_NM(rflags); + + /** 0x150 - Externalized state tracker, CPUMCTX_EXTRN_XXX. */ + uint64_t fExtrn; + + /** The RIP value an interrupt shadow is/was valid for. */ + uint64_t uRipInhibitInt; + + /** @name Control registers. + * @{ */ + uint64_t cr0; + uint64_t cr2; + uint64_t cr3; + uint64_t cr4; + /** @} */ + + /** Debug registers. + * @remarks DR4 and DR5 should not be used since they are aliases for + * DR6 and DR7 respectively on both AMD and Intel CPUs. + * @remarks DR8-15 are currently not supported by AMD or Intel, so + * neither do we. + */ + uint64_t dr[8]; + + /** Padding before the structure so the 64-bit member is correctly aligned. + * @todo fix this structure! */ + uint16_t gdtrPadding[3]; + /** Global Descriptor Table register. */ + VBOXGDTR gdtr; + + /** Padding before the structure so the 64-bit member is correctly aligned. + * @todo fix this structure! */ + uint16_t idtrPadding[3]; + /** Interrupt Descriptor Table register. */ + VBOXIDTR idtr; + + /** The sysenter msr registers. + * This member is not used by the hypervisor context. */ + CPUMSYSENTER SysEnter; + + /** @name System MSRs. + * @{ */ + uint64_t msrEFER; /**< @todo move EFER up to the crX registers for better cacheline mojo */ + uint64_t msrSTAR; /**< Legacy syscall eip, cs & ss. */ + uint64_t msrPAT; /**< Page attribute table. */ + uint64_t msrLSTAR; /**< 64 bits mode syscall rip. */ + uint64_t msrCSTAR; /**< Compatibility mode syscall rip. */ + uint64_t msrSFMASK; /**< syscall flag mask. */ + uint64_t msrKERNELGSBASE; /**< swapgs exchange value. */ + /** @} */ + + uint64_t au64Unused[2]; + + /** 0x240 - PAE PDPTEs. */ + X86PDPE aPaePdpes[4]; + + /** 0x260 - The XCR0..XCR1 registers. */ + uint64_t aXcr[2]; + /** 0x270 - The mask to pass to XSAVE/XRSTOR in EDX:EAX. If zero we use + * FXSAVE/FXRSTOR (since bit 0 will always be set, we only need to test it). */ + uint64_t fXStateMask; + /** 0x278 - Mirror of CPUMCPU::fUseFlags[CPUM_USED_FPU_GUEST]. */ + bool fUsedFpuGuest; + uint8_t afUnused[7]; + + /* ---- Start of members not zeroed at reset. ---- */ + + /** 0x280 - State component offsets into pXState, UINT16_MAX if not present. + * @note Everything before this member will be memset to zero during reset. */ + uint16_t aoffXState[64]; + /** 0x300 - The extended state (FPU/SSE/AVX/AVX-2/XXXX). + * Aligned on 256 byte boundrary (min req is currently 64 bytes). */ + union /* no tag */ + { + X86XSAVEAREA XState; + /** Byte view for simple indexing and space allocation. */ + uint8_t abXState[0x4000 - 0x300]; + } CPUM_UNION_NM(u); + + /** 0x4000 - Hardware virtualization state. + * @note This is page aligned, so an full page member comes first in the + * substructures. */ + struct + { + union /* no tag! */ + { + struct + { + /** 0x4000 - Cache of the nested-guest VMCB. */ + SVMVMCB Vmcb; + /** 0x5000 - The MSRPM (MSR Permission bitmap). + * + * This need not be physically contiguous pages because we use the one from + * HMPHYSCPU while executing the nested-guest using hardware-assisted SVM. + * This one is just used for caching the bitmap from guest physical memory. + * + * @todo r=bird: This is not used directly by AMD-V hardware, so it doesn't + * really need to even be page aligned. + * + * Also, couldn't we just access the guest page directly when we need to, + * or do we have to use a cached copy of it? */ + uint8_t abMsrBitmap[SVM_MSRPM_PAGES * X86_PAGE_SIZE]; + /** 0x7000 - The IOPM (IO Permission bitmap). + * + * This need not be physically contiguous pages because we re-use the ring-0 + * allocated IOPM while executing the nested-guest using hardware-assisted SVM + * because it's identical (we trap all IO accesses). + * + * This one is just used for caching the IOPM from guest physical memory in + * case the guest hypervisor allows direct access to some IO ports. + * + * @todo r=bird: This is not used directly by AMD-V hardware, so it doesn't + * really need to even be page aligned. + * + * Also, couldn't we just access the guest page directly when we need to, + * or do we have to use a cached copy of it? */ + uint8_t abIoBitmap[SVM_IOPM_PAGES * X86_PAGE_SIZE]; + + /** 0xa000 - MSR holding physical address of the Guest's Host-state. */ + uint64_t uMsrHSavePa; + /** 0xa008 - Guest physical address of the nested-guest VMCB. */ + RTGCPHYS GCPhysVmcb; + /** 0xa010 - Guest's host-state save area. */ + SVMHOSTSTATE HostState; + /** 0xa0c8 - Guest TSC time-stamp of when the previous PAUSE instr. was + * executed. */ + uint64_t uPrevPauseTick; + /** 0xa0d0 - Pause filter count. */ + uint16_t cPauseFilter; + /** 0xa0d2 - Pause filter threshold. */ + uint16_t cPauseFilterThreshold; + /** 0xa0d4 - Whether the injected event is subject to event intercepts. */ + bool fInterceptEvents; + /** 0xa0d5 - Padding. */ + bool afPadding[3]; + } svm; + + struct + { + /** 0x4000 - The current VMCS. */ + VMXVVMCS Vmcs; + /** 0X5000 - The shadow VMCS. */ + VMXVVMCS ShadowVmcs; + /** 0x6000 - The VMREAD bitmap. + * @todo r=bird: Do we really need to keep copies for these? Couldn't we just + * access the guest memory directly as needed? */ + uint8_t abVmreadBitmap[VMX_V_VMREAD_VMWRITE_BITMAP_SIZE]; + /** 0x7000 - The VMWRITE bitmap. + * @todo r=bird: Do we really need to keep copies for these? Couldn't we just + * access the guest memory directly as needed? */ + uint8_t abVmwriteBitmap[VMX_V_VMREAD_VMWRITE_BITMAP_SIZE]; + /** 0x8000 - The VM-entry MSR-load area. */ + VMXAUTOMSR aEntryMsrLoadArea[VMX_V_AUTOMSR_AREA_SIZE / sizeof(VMXAUTOMSR)]; + /** 0xa000 - The VM-exit MSR-store area. */ + VMXAUTOMSR aExitMsrStoreArea[VMX_V_AUTOMSR_AREA_SIZE / sizeof(VMXAUTOMSR)]; + /** 0xc000 - The VM-exit MSR-load area. */ + VMXAUTOMSR aExitMsrLoadArea[VMX_V_AUTOMSR_AREA_SIZE / sizeof(VMXAUTOMSR)]; + /** 0xe000 - The MSR permission bitmap. + * @todo r=bird: Do we really need to keep copies for these? Couldn't we just + * access the guest memory directly as needed? */ + uint8_t abMsrBitmap[VMX_V_MSR_BITMAP_SIZE]; + /** 0xf000 - The I/O permission bitmap. + * @todo r=bird: Do we really need to keep copies for these? Couldn't we just + * access the guest memory directly as needed? */ + uint8_t abIoBitmap[VMX_V_IO_BITMAP_A_SIZE + VMX_V_IO_BITMAP_B_SIZE]; + + /** 0x11000 - Guest physical address of the VMXON region. */ + RTGCPHYS GCPhysVmxon; + /** 0x11008 - Guest physical address of the current VMCS pointer. */ + RTGCPHYS GCPhysVmcs; + /** 0x11010 - Guest physical address of the shadow VMCS pointer. */ + RTGCPHYS GCPhysShadowVmcs; + /** 0x11018 - Last emulated VMX instruction/VM-exit diagnostic. */ + VMXVDIAG enmDiag; + /** 0x1101c - VMX abort reason. */ + VMXABORT enmAbort; + /** 0x11020 - Last emulated VMX instruction/VM-exit diagnostic auxiliary info. + * (mainly used for info. that's not part of the VMCS). */ + uint64_t uDiagAux; + /** 0x11028 - VMX abort auxiliary info. */ + uint32_t uAbortAux; + /** 0x1102c - Whether the guest is in VMX root mode. */ + bool fInVmxRootMode; + /** 0x1102d - Whether the guest is in VMX non-root mode. */ + bool fInVmxNonRootMode; + /** 0x1102e - Whether the injected events are subjected to event intercepts. */ + bool fInterceptEvents; + /** 0x1102f - Whether blocking of NMI (or virtual-NMIs) was in effect in VMX + * non-root mode before execution of IRET. */ + bool fNmiUnblockingIret; + /** 0x11030 - Guest TSC timestamp of the first PAUSE instruction that is + * considered to be the first in a loop. */ + uint64_t uFirstPauseLoopTick; + /** 0x11038 - Guest TSC timestamp of the previous PAUSE instruction. */ + uint64_t uPrevPauseTick; + /** 0x11040 - Guest TSC timestamp of VM-entry (used for VMX-preemption + * timer). */ + uint64_t uEntryTick; + /** 0x11048 - Virtual-APIC write offset (until trap-like VM-exit). */ + uint16_t offVirtApicWrite; + /** 0x1104a - Whether virtual-NMI blocking is in effect. */ + bool fVirtNmiBlocking; + /** 0x1104b - Padding. */ + uint8_t abPadding0[5]; + /** 0x11050 - Guest VMX MSRs. */ + VMXMSRS Msrs; + } vmx; + } CPUM_UNION_NM(s); + + /** 0x11130 - Hardware virtualization type currently in use. */ + CPUMHWVIRT enmHwvirt; + /** 0x11134 - Global interrupt flag - AMD only (always true on Intel). */ + bool fGif; + /** 0x11135 - Padding. */ + bool afPadding0[3]; + /** 0x11138 - A subset of guest inhibit flags (CPUMCTX_INHIBIT_XXX) that are + * saved while running the nested-guest. */ + uint32_t fSavedInhibit; + /** 0x1113c - Pad to 64 byte boundary. */ + uint8_t abPadding1[4]; + } hwvirt; +} CPUMCTX; +#pragma pack() + +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompileSizeAlignment(CPUMCTX, 64); +AssertCompileSizeAlignment(CPUMCTX, 32); +AssertCompileSizeAlignment(CPUMCTX, 16); +AssertCompileSizeAlignment(CPUMCTX, 8); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rax, 0x0000); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rcx, 0x0008); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rdx, 0x0010); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rbx, 0x0018); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rsp, 0x0020); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rbp, 0x0028); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rsi, 0x0030); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) rdi, 0x0038); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r8, 0x0040); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r9, 0x0048); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r10, 0x0050); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r11, 0x0058); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r12, 0x0060); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r13, 0x0068); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r14, 0x0070); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(g.) CPUM_STRUCT_NM(qw.) r15, 0x0078); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) es, 0x0080); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) cs, 0x0098); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) ss, 0x00b0); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) ds, 0x00c8); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) fs, 0x00e0); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) gs, 0x00f8); +AssertCompileMemberOffset(CPUMCTX, ldtr, 0x0110); +AssertCompileMemberOffset(CPUMCTX, tr, 0x0128); +AssertCompileMemberOffset(CPUMCTX, rip, 0x0140); +AssertCompileMemberOffset(CPUMCTX, rflags, 0x0148); +AssertCompileMemberOffset(CPUMCTX, fExtrn, 0x0150); +AssertCompileMemberOffset(CPUMCTX, uRipInhibitInt, 0x0158); +AssertCompileMemberOffset(CPUMCTX, cr0, 0x0160); +AssertCompileMemberOffset(CPUMCTX, cr2, 0x0168); +AssertCompileMemberOffset(CPUMCTX, cr3, 0x0170); +AssertCompileMemberOffset(CPUMCTX, cr4, 0x0178); +AssertCompileMemberOffset(CPUMCTX, dr, 0x0180); +AssertCompileMemberOffset(CPUMCTX, gdtr, 0x01c0+6); +AssertCompileMemberOffset(CPUMCTX, idtr, 0x01d0+6); +AssertCompileMemberOffset(CPUMCTX, SysEnter, 0x01e0); +AssertCompileMemberOffset(CPUMCTX, msrEFER, 0x01f8); +AssertCompileMemberOffset(CPUMCTX, msrSTAR, 0x0200); +AssertCompileMemberOffset(CPUMCTX, msrPAT, 0x0208); +AssertCompileMemberOffset(CPUMCTX, msrLSTAR, 0x0210); +AssertCompileMemberOffset(CPUMCTX, msrCSTAR, 0x0218); +AssertCompileMemberOffset(CPUMCTX, msrSFMASK, 0x0220); +AssertCompileMemberOffset(CPUMCTX, msrKERNELGSBASE, 0x0228); +AssertCompileMemberOffset(CPUMCTX, aPaePdpes, 0x0240); +AssertCompileMemberOffset(CPUMCTX, aXcr, 0x0260); +AssertCompileMemberOffset(CPUMCTX, fXStateMask, 0x0270); +AssertCompileMemberOffset(CPUMCTX, fUsedFpuGuest, 0x0278); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(u.) XState, 0x0300); +AssertCompileMemberOffset(CPUMCTX, CPUM_UNION_NM(u.) abXState, 0x0300); +AssertCompileMemberAlignment(CPUMCTX, CPUM_UNION_NM(u.) XState, 0x0100); +/* Only do spot checks for hwvirt */ +AssertCompileMemberAlignment(CPUMCTX, hwvirt, 0x1000); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.Vmcb, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.abMsrBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.abIoBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.Vmcs, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.ShadowVmcs, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abVmreadBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abVmwriteBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.aEntryMsrLoadArea, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.aExitMsrStoreArea, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.aExitMsrLoadArea, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abMsrBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abIoBitmap, X86_PAGE_SIZE); +AssertCompileMemberAlignment(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.Msrs, 8); +AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.abIoBitmap, 0x7000); +AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) svm.fInterceptEvents, 0xa0d4); +AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.abIoBitmap, 0xf000); +AssertCompileMemberOffset(CPUMCTX, hwvirt.CPUM_UNION_NM(s.) vmx.fVirtNmiBlocking, 0x1104a); +AssertCompileMemberOffset(CPUMCTX, hwvirt.enmHwvirt, 0x11130); +AssertCompileMemberOffset(CPUMCTX, hwvirt.fGif, 0x11134); +AssertCompileMemberOffset(CPUMCTX, hwvirt.fSavedInhibit, 0x11138); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_NM(g.) aGRegs); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r0); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r1); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r2); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r3); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r4); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r5); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r6); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw2.) r7); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) eax); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) ecx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) edx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) ebx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) esp); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) ebp); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) esi); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) edi); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r8, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r8d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r9, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r9d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r10, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r10d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r11, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r11d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r12, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r12d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r13, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r13d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r14, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r14d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r15, CPUMCTX, CPUM_UNION_STRUCT_NM(g,dw.) r15d); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) ax); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) cx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) dx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) bx); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) sp); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) bp); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) si); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) di); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r8, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r8w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r9, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r9w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r10, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r10w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r11, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r11w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r12, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r12w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r13, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r13w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r14, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r14w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r15, CPUMCTX, CPUM_UNION_STRUCT_NM(g,w.) r15w); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) al); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) cl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) dl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) bl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) spl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) bpl); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) sil); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) dil); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r8, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r8l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r9, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r9l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r10, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r10l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r11, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r11l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r12, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r12l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r13, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r13l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r14, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r14l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r15, CPUMCTX, CPUM_UNION_STRUCT_NM(g,b.) r15l); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_NM(s.) CPUM_STRUCT_NM(n.) es, CPUMCTX, CPUM_UNION_NM(s.) aSRegs); +# ifndef _MSC_VER +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rax, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xAX]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rcx, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xCX]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdx, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xDX]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbx, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xBX]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsp, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xSP]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rbp, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xBP]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rsi, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xSI]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) rdi, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_xDI]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r8, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x8]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r9, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x9]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r10, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x10]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r11, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x11]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r12, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x12]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r13, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x13]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r14, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x14]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(g,qw.) r15, CPUMCTX, CPUM_UNION_NM(g.) aGRegs[X86_GREG_x15]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) es, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_ES]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) cs, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_CS]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) ss, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_SS]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) ds, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_DS]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) fs, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_FS]); +AssertCompileMembersAtSameOffset(CPUMCTX, CPUM_UNION_STRUCT_NM(s,n.) gs, CPUMCTX, CPUM_UNION_NM(s.) aSRegs[X86_SREG_GS]); +# endif + + +/** + * Calculates the pointer to the given extended state component. + * + * @returns Pointer of type @a a_PtrType + * @param a_pCtx Pointer to the context. + * @param a_iCompBit The extended state component bit number. This bit + * must be set in CPUMCTX::fXStateMask. + * @param a_PtrType The pointer type of the extended state component. + * + */ +#if defined(VBOX_STRICT) && defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define CPUMCTX_XSAVE_C_PTR(a_pCtx, a_iCompBit, a_PtrType) \ + ([](PCCPUMCTX a_pLambdaCtx) -> a_PtrType \ + { \ + AssertCompile((a_iCompBit) < 64U); \ + AssertMsg(a_pLambdaCtx->fXStateMask & RT_BIT_64(a_iCompBit), (#a_iCompBit "\n")); \ + AssertMsg(a_pLambdaCtx->aoffXState[(a_iCompBit)] != UINT16_MAX, (#a_iCompBit "\n")); \ + return (a_PtrType)(&a_pLambdaCtx->abXState[a_pLambdaCtx->aoffXState[(a_iCompBit)]]); \ + }(a_pCtx)) +#elif defined(VBOX_STRICT) && defined(__GNUC__) +# define CPUMCTX_XSAVE_C_PTR(a_pCtx, a_iCompBit, a_PtrType) \ + __extension__ (\ + { \ + AssertCompile((a_iCompBit) < 64U); \ + AssertMsg((a_pCtx)->fXStateMask & RT_BIT_64(a_iCompBit), (#a_iCompBit "\n")); \ + AssertMsg((a_pCtx)->aoffXState[(a_iCompBit)] != UINT16_MAX, (#a_iCompBit "\n")); \ + (a_PtrType)(&(a_pCtx)->abXState[(a_pCtx)->aoffXState[(a_iCompBit)]]); \ + }) +#else +# define CPUMCTX_XSAVE_C_PTR(a_pCtx, a_iCompBit, a_PtrType) \ + ((a_PtrType)(&(a_pCtx)->abXState[(a_pCtx)->aoffXState[(a_iCompBit)]])) +#endif + +/** + * Gets the first selector register of a CPUMCTX. + * + * Use this with X86_SREG_COUNT to loop thru the selector registers. + */ +# define CPUMCTX_FIRST_SREG(a_pCtx) (&(a_pCtx)->es) + +#endif /* !VBOX_FOR_DTRACE_LIB */ + + +/** @name CPUMCTX_EXTRN_XXX + * Used for parts of the CPUM state that is externalized and needs fetching + * before use. + * + * @{ */ +/** External state keeper: Invalid. */ +#define CPUMCTX_EXTRN_KEEPER_INVALID UINT64_C(0x0000000000000000) +/** External state keeper: HM. */ +#define CPUMCTX_EXTRN_KEEPER_HM UINT64_C(0x0000000000000001) +/** External state keeper: NEM. */ +#define CPUMCTX_EXTRN_KEEPER_NEM UINT64_C(0x0000000000000002) +/** External state keeper: REM. */ +#define CPUMCTX_EXTRN_KEEPER_REM UINT64_C(0x0000000000000003) +/** External state keeper mask. */ +#define CPUMCTX_EXTRN_KEEPER_MASK UINT64_C(0x0000000000000003) + +/** The RIP register value is kept externally. */ +#define CPUMCTX_EXTRN_RIP UINT64_C(0x0000000000000004) +/** The RFLAGS register values are kept externally. */ +#define CPUMCTX_EXTRN_RFLAGS UINT64_C(0x0000000000000008) + +/** The RAX register value is kept externally. */ +#define CPUMCTX_EXTRN_RAX UINT64_C(0x0000000000000010) +/** The RCX register value is kept externally. */ +#define CPUMCTX_EXTRN_RCX UINT64_C(0x0000000000000020) +/** The RDX register value is kept externally. */ +#define CPUMCTX_EXTRN_RDX UINT64_C(0x0000000000000040) +/** The RBX register value is kept externally. */ +#define CPUMCTX_EXTRN_RBX UINT64_C(0x0000000000000080) +/** The RSP register value is kept externally. */ +#define CPUMCTX_EXTRN_RSP UINT64_C(0x0000000000000100) +/** The RBP register value is kept externally. */ +#define CPUMCTX_EXTRN_RBP UINT64_C(0x0000000000000200) +/** The RSI register value is kept externally. */ +#define CPUMCTX_EXTRN_RSI UINT64_C(0x0000000000000400) +/** The RDI register value is kept externally. */ +#define CPUMCTX_EXTRN_RDI UINT64_C(0x0000000000000800) +/** The R8 thru R15 register values are kept externally. */ +#define CPUMCTX_EXTRN_R8_R15 UINT64_C(0x0000000000001000) +/** General purpose registers mask. */ +#define CPUMCTX_EXTRN_GPRS_MASK UINT64_C(0x0000000000001ff0) + +/** The ES register values are kept externally. */ +#define CPUMCTX_EXTRN_ES UINT64_C(0x0000000000002000) +/** The CS register values are kept externally. */ +#define CPUMCTX_EXTRN_CS UINT64_C(0x0000000000004000) +/** The SS register values are kept externally. */ +#define CPUMCTX_EXTRN_SS UINT64_C(0x0000000000008000) +/** The DS register values are kept externally. */ +#define CPUMCTX_EXTRN_DS UINT64_C(0x0000000000010000) +/** The FS register values are kept externally. */ +#define CPUMCTX_EXTRN_FS UINT64_C(0x0000000000020000) +/** The GS register values are kept externally. */ +#define CPUMCTX_EXTRN_GS UINT64_C(0x0000000000040000) +/** Segment registers (includes CS). */ +#define CPUMCTX_EXTRN_SREG_MASK UINT64_C(0x000000000007e000) +/** Converts a X86_XREG_XXX index to a CPUMCTX_EXTRN_xS mask. */ +#define CPUMCTX_EXTRN_SREG_FROM_IDX(a_SRegIdx) RT_BIT_64((a_SRegIdx) + 13) +#ifndef VBOX_FOR_DTRACE_LIB +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_ES) == CPUMCTX_EXTRN_ES); +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_CS) == CPUMCTX_EXTRN_CS); +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_DS) == CPUMCTX_EXTRN_DS); +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_FS) == CPUMCTX_EXTRN_FS); +AssertCompile(CPUMCTX_EXTRN_SREG_FROM_IDX(X86_SREG_GS) == CPUMCTX_EXTRN_GS); +#endif + +/** The GDTR register values are kept externally. */ +#define CPUMCTX_EXTRN_GDTR UINT64_C(0x0000000000080000) +/** The IDTR register values are kept externally. */ +#define CPUMCTX_EXTRN_IDTR UINT64_C(0x0000000000100000) +/** The LDTR register values are kept externally. */ +#define CPUMCTX_EXTRN_LDTR UINT64_C(0x0000000000200000) +/** The TR register values are kept externally. */ +#define CPUMCTX_EXTRN_TR UINT64_C(0x0000000000400000) +/** Table register mask. */ +#define CPUMCTX_EXTRN_TABLE_MASK UINT64_C(0x0000000000780000) + +/** The CR0 register value is kept externally. */ +#define CPUMCTX_EXTRN_CR0 UINT64_C(0x0000000000800000) +/** The CR2 register value is kept externally. */ +#define CPUMCTX_EXTRN_CR2 UINT64_C(0x0000000001000000) +/** The CR3 register value is kept externally. */ +#define CPUMCTX_EXTRN_CR3 UINT64_C(0x0000000002000000) +/** The CR4 register value is kept externally. */ +#define CPUMCTX_EXTRN_CR4 UINT64_C(0x0000000004000000) +/** Control register mask. */ +#define CPUMCTX_EXTRN_CR_MASK UINT64_C(0x0000000007800000) +/** The TPR/CR8 register value is kept externally. */ +#define CPUMCTX_EXTRN_APIC_TPR UINT64_C(0x0000000008000000) +/** The EFER register value is kept externally. */ +#define CPUMCTX_EXTRN_EFER UINT64_C(0x0000000010000000) + +/** The DR0, DR1, DR2 and DR3 register values are kept externally. */ +#define CPUMCTX_EXTRN_DR0_DR3 UINT64_C(0x0000000020000000) +/** The DR6 register value is kept externally. */ +#define CPUMCTX_EXTRN_DR6 UINT64_C(0x0000000040000000) +/** The DR7 register value is kept externally. */ +#define CPUMCTX_EXTRN_DR7 UINT64_C(0x0000000080000000) +/** Debug register mask. */ +#define CPUMCTX_EXTRN_DR_MASK UINT64_C(0x00000000e0000000) + +/** The XSAVE_C_X87 state is kept externally. */ +#define CPUMCTX_EXTRN_X87 UINT64_C(0x0000000100000000) +/** The XSAVE_C_SSE, XSAVE_C_YMM, XSAVE_C_ZMM_HI256, XSAVE_C_ZMM_16HI and + * XSAVE_C_OPMASK state is kept externally. */ +#define CPUMCTX_EXTRN_SSE_AVX UINT64_C(0x0000000200000000) +/** The state of XSAVE components not covered by CPUMCTX_EXTRN_X87 and + * CPUMCTX_EXTRN_SEE_AVX is kept externally. */ +#define CPUMCTX_EXTRN_OTHER_XSAVE UINT64_C(0x0000000400000000) +/** The state of XCR0 and XCR1 register values are kept externally. */ +#define CPUMCTX_EXTRN_XCRx UINT64_C(0x0000000800000000) + + +/** The KERNEL GS BASE MSR value is kept externally. */ +#define CPUMCTX_EXTRN_KERNEL_GS_BASE UINT64_C(0x0000001000000000) +/** The STAR, LSTAR, CSTAR and SFMASK MSR values are kept externally. */ +#define CPUMCTX_EXTRN_SYSCALL_MSRS UINT64_C(0x0000002000000000) +/** The SYSENTER_CS, SYSENTER_EIP and SYSENTER_ESP MSR values are kept externally. */ +#define CPUMCTX_EXTRN_SYSENTER_MSRS UINT64_C(0x0000004000000000) +/** The TSC_AUX MSR is kept externally. */ +#define CPUMCTX_EXTRN_TSC_AUX UINT64_C(0x0000008000000000) +/** All other stateful MSRs not covered by CPUMCTX_EXTRN_EFER, + * CPUMCTX_EXTRN_KERNEL_GS_BASE, CPUMCTX_EXTRN_SYSCALL_MSRS, + * CPUMCTX_EXTRN_SYSENTER_MSRS, and CPUMCTX_EXTRN_TSC_AUX. */ +#define CPUMCTX_EXTRN_OTHER_MSRS UINT64_C(0x0000010000000000) + +/** Mask of all the MSRs. */ +#define CPUMCTX_EXTRN_ALL_MSRS ( CPUMCTX_EXTRN_EFER | CPUMCTX_EXTRN_KERNEL_GS_BASE | CPUMCTX_EXTRN_SYSCALL_MSRS \ + | CPUMCTX_EXTRN_SYSENTER_MSRS | CPUMCTX_EXTRN_TSC_AUX | CPUMCTX_EXTRN_OTHER_MSRS) + +/** Hardware-virtualization (SVM or VMX) state is kept externally. */ +#define CPUMCTX_EXTRN_HWVIRT UINT64_C(0x0000020000000000) + +/** Inhibit maskable interrupts (VMCPU_FF_INHIBIT_INTERRUPTS) */ +#define CPUMCTX_EXTRN_INHIBIT_INT UINT64_C(0x0000040000000000) +/** Inhibit non-maskable interrupts (VMCPU_FF_BLOCK_NMIS). */ +#define CPUMCTX_EXTRN_INHIBIT_NMI UINT64_C(0x0000080000000000) + +/** Mask of bits the keepers can use for state tracking. */ +#define CPUMCTX_EXTRN_KEEPER_STATE_MASK UINT64_C(0xffff000000000000) + +/** NEM/Win: Event injection (known was interruption) pending state. */ +#define CPUMCTX_EXTRN_NEM_WIN_EVENT_INJECT UINT64_C(0x0001000000000000) +/** NEM/Win: Mask. */ +#define CPUMCTX_EXTRN_NEM_WIN_MASK UINT64_C(0x0001000000000000) + +/** HM/SVM: Nested-guest interrupt pending (VMCPU_FF_INTERRUPT_NESTED_GUEST). */ +#define CPUMCTX_EXTRN_HM_SVM_HWVIRT_VIRQ UINT64_C(0x0001000000000000) +/** HM/SVM: Mask. */ +#define CPUMCTX_EXTRN_HM_SVM_MASK UINT64_C(0x0001000000000000) + +/** All CPUM state bits, not including keeper specific ones. */ +#define CPUMCTX_EXTRN_ALL UINT64_C(0x00000ffffffffffc) +/** All CPUM state bits, including keeper specific ones. */ +#define CPUMCTX_EXTRN_ABSOLUTELY_ALL UINT64_C(0xfffffffffffffffc) +/** @} */ + + +/** @name CPUMCTX_INHIBIT_XXX - Interrupt inhibiting flags. + * @{ */ +/** Interrupt shadow following MOV SS or POP SS. + * + * When this in effect, both maskable and non-maskable interrupts are blocked + * from delivery for one instruction. Same for certain debug exceptions too, + * unlike the STI variant. + * + * It is implementation specific whether a sequence of two or more of these + * instructions will have any effect on the instruction following the last one + * of them. */ +#define CPUMCTX_INHIBIT_SHADOW_SS RT_BIT_32(0 + CPUMX86EFLAGS_HW_BITS) +/** Interrupt shadow following STI. + * Same as CPUMCTX_INHIBIT_SHADOW_SS but without blocking any debug exceptions. */ +#define CPUMCTX_INHIBIT_SHADOW_STI RT_BIT_32(1 + CPUMX86EFLAGS_HW_BITS) +/** Mask combining STI and SS shadowing. */ +#define CPUMCTX_INHIBIT_SHADOW (CPUMCTX_INHIBIT_SHADOW_SS | CPUMCTX_INHIBIT_SHADOW_STI) + +/** Interrupts blocked by NMI delivery. This condition is cleared by IRET. + * + * Section "6.7 NONMASKABLE INTERRUPT (NMI)" in Intel SDM Vol 3A states that + * "The processor also invokes certain hardware conditions to ensure that no + * other interrupts, including NMI interrupts, are received until the NMI + * handler has completed executing." This flag indicates that these + * conditions are currently active. + * + * @todo this does not really need to be in the lower 32-bits of EFLAGS. + */ +#define CPUMCTX_INHIBIT_NMI RT_BIT_32(2 + CPUMX86EFLAGS_HW_BITS) + +/** Mask containing all the interrupt inhibit bits. */ +#define CPUMCTX_INHIBIT_ALL_MASK (CPUMCTX_INHIBIT_SHADOW_SS | CPUMCTX_INHIBIT_SHADOW_STI | CPUMCTX_INHIBIT_NMI) +AssertCompile(CPUMCTX_INHIBIT_ALL_MASK < UINT32_MAX); +/** @} */ + +/** @name CPUMCTX_DBG_XXX - Pending debug events. + * @{ */ +/** Hit guest DR0 breakpoint. */ +#define CPUMCTX_DBG_HIT_DR0 RT_BIT_32(CPUMCTX_DBG_HIT_DR0_BIT) +#define CPUMCTX_DBG_HIT_DR0_BIT (3 + CPUMX86EFLAGS_HW_BITS) +/** Hit guest DR1 breakpoint. */ +#define CPUMCTX_DBG_HIT_DR1 RT_BIT_32(CPUMCTX_DBG_HIT_DR1_BIT) +#define CPUMCTX_DBG_HIT_DR1_BIT (4 + CPUMX86EFLAGS_HW_BITS) +/** Hit guest DR2 breakpoint. */ +#define CPUMCTX_DBG_HIT_DR2 RT_BIT_32(CPUMCTX_DBG_HIT_DR2_BIT) +#define CPUMCTX_DBG_HIT_DR2_BIT (5 + CPUMX86EFLAGS_HW_BITS) +/** Hit guest DR3 breakpoint. */ +#define CPUMCTX_DBG_HIT_DR3 RT_BIT_32(CPUMCTX_DBG_HIT_DR3_BIT) +#define CPUMCTX_DBG_HIT_DR3_BIT (6 + CPUMX86EFLAGS_HW_BITS) +/** Shift for the CPUMCTX_DBG_HIT_DRx bits. */ +#define CPUMCTX_DBG_HIT_DRX_SHIFT CPUMCTX_DBG_HIT_DR0_BIT +/** Mask of all guest pending DR0-DR3 breakpoint indicators. */ +#define CPUMCTX_DBG_HIT_DRX_MASK (CPUMCTX_DBG_HIT_DR0 | CPUMCTX_DBG_HIT_DR1 | CPUMCTX_DBG_HIT_DR2 | CPUMCTX_DBG_HIT_DR3) +/** DBGF event/breakpoint pending. */ +#define CPUMCTX_DBG_DBGF_EVENT RT_BIT_32(CPUMCTX_DBG_DBGF_EVENT_BIT) +#define CPUMCTX_DBG_DBGF_EVENT_BIT (7 + CPUMX86EFLAGS_HW_BITS) +/** DBGF event/breakpoint pending. */ +#define CPUMCTX_DBG_DBGF_BP RT_BIT_32(CPUMCTX_DBG_DBGF_BP_BIT) +#define CPUMCTX_DBG_DBGF_BP_BIT (8 + CPUMX86EFLAGS_HW_BITS) +/** Mask of all DBGF indicators. */ +#define CPUMCTX_DBG_DBGF_MASK (CPUMCTX_DBG_DBGF_EVENT | CPUMCTX_DBG_DBGF_BP) +AssertCompile((CPUMCTX_DBG_HIT_DRX_MASK | CPUMCTX_DBG_DBGF_MASK) < UINT32_MAX); +/** @} */ + + + +/** + * Additional guest MSRs (i.e. not part of the CPU context structure). + * + * @remarks Never change the order here because of the saved stated! The size + * can in theory be changed, but keep older VBox versions in mind. + */ +typedef union CPUMCTXMSRS +{ + struct + { + uint64_t TscAux; /**< MSR_K8_TSC_AUX */ + uint64_t MiscEnable; /**< MSR_IA32_MISC_ENABLE */ + uint64_t MtrrDefType; /**< IA32_MTRR_DEF_TYPE */ + uint64_t MtrrFix64K_00000; /**< IA32_MTRR_FIX16K_80000 */ + uint64_t MtrrFix16K_80000; /**< IA32_MTRR_FIX16K_80000 */ + uint64_t MtrrFix16K_A0000; /**< IA32_MTRR_FIX16K_A0000 */ + uint64_t MtrrFix4K_C0000; /**< IA32_MTRR_FIX4K_C0000 */ + uint64_t MtrrFix4K_C8000; /**< IA32_MTRR_FIX4K_C8000 */ + uint64_t MtrrFix4K_D0000; /**< IA32_MTRR_FIX4K_D0000 */ + uint64_t MtrrFix4K_D8000; /**< IA32_MTRR_FIX4K_D8000 */ + uint64_t MtrrFix4K_E0000; /**< IA32_MTRR_FIX4K_E0000 */ + uint64_t MtrrFix4K_E8000; /**< IA32_MTRR_FIX4K_E8000 */ + uint64_t MtrrFix4K_F0000; /**< IA32_MTRR_FIX4K_F0000 */ + uint64_t MtrrFix4K_F8000; /**< IA32_MTRR_FIX4K_F8000 */ + uint64_t PkgCStateCfgCtrl; /**< MSR_PKG_CST_CONFIG_CONTROL */ + uint64_t SpecCtrl; /**< IA32_SPEC_CTRL */ + uint64_t ArchCaps; /**< IA32_ARCH_CAPABILITIES */ + } msr; + uint64_t au64[64]; +} CPUMCTXMSRS; +/** Pointer to the guest MSR state. */ +typedef CPUMCTXMSRS *PCPUMCTXMSRS; +/** Pointer to the const guest MSR state. */ +typedef const CPUMCTXMSRS *PCCPUMCTXMSRS; + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_cpumctx_h */ + diff --git a/include/VBox/vmm/cpumdis.h b/include/VBox/vmm/cpumdis.h new file mode 100644 index 00000000..ee09e7b5 --- /dev/null +++ b/include/VBox/vmm/cpumdis.h @@ -0,0 +1,61 @@ +/** @file + * CPUM - Disassembler. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_cpumdis_h +#define VBOX_INCLUDED_vmm_cpumdis_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +RT_C_DECLS_BEGIN +/** @addtogroup grp_cpum + * @{ + */ + +#ifdef IN_RING3 +VMMR3DECL(int) CPUMR3DisasmInstrCPU(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTGCPTR GCPtrPC, PDISCPUSTATE pCpu, const char *pszPrefix); +#endif + +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_cpumdis_h */ + diff --git a/include/VBox/vmm/dbgf.h b/include/VBox/vmm/dbgf.h new file mode 100644 index 00000000..a961a3a5 --- /dev/null +++ b/include/VBox/vmm/dbgf.h @@ -0,0 +1,3192 @@ +/** @file + * DBGF - Debugger Facility. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgf_h +#define VBOX_INCLUDED_vmm_dbgf_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include /* LOG_ENABLED */ +#include +#include + +#include +#include + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_dbgf The Debugger Facility API + * @ingroup grp_vmm + * @{ + */ + +/** @defgroup grp_dbgf_r0 The R0 DBGF API + * @{ + */ +VMMR0_INT_DECL(void) DBGFR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(void) DBGFR0CleanupVM(PGVM pGVM); + +/** + * Request buffer for DBGFR0TracerCreateReqHandler / VMMR0_DO_DBGF_TRACER_CREATE. + * @see DBGFR0TracerCreateReqHandler. + */ +typedef struct DBGFTRACERCREATEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Where to return the address of the ring-3 tracer instance. */ + PDBGFTRACERINSR3 pTracerInsR3; + + /** Number of bytes for the shared event ring buffer. */ + uint32_t cbRingBuf; + + /** Set if the raw-mode component is desired. */ + bool fRCEnabled; + /** Explicit padding. */ + bool afReserved[3]; + +} DBGFTRACERCREATEREQ; +/** Pointer to a DBGFR0TracerCreate / VMMR0_DO_DBGF_TRACER_CREATE request buffer. */ +typedef DBGFTRACERCREATEREQ *PDBGFTRACERCREATEREQ; + +VMMR0_INT_DECL(int) DBGFR0TracerCreateReqHandler(PGVM pGVM, PDBGFTRACERCREATEREQ pReq); + +/** + * Request buffer for DBGFR0BpInitReqHandler / VMMR0_DO_DBGF_BP_INIT and + * DBGFR0BpPortIoInitReqHandler / VMMR0_DO_DBGF_BP_PORTIO_INIT. + * @see DBGFR0BpInitReqHandler, DBGFR0BpPortIoInitReqHandler. + */ +typedef struct DBGFBPINITREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Ring-3 pointer of the L1 lookup table on success. */ + R3PTRTYPE(volatile uint32_t *) paBpLocL1R3; +} DBGFBPINITREQ; +/** Pointer to a DBGFR0BpInitReqHandler / VMMR0_DO_DBGF_BP_INIT request buffer. */ +typedef DBGFBPINITREQ *PDBGFBPINITREQ; + +VMMR0_INT_DECL(int) DBGFR0BpInitReqHandler(PGVM pGVM, PDBGFBPINITREQ pReq); +VMMR0_INT_DECL(int) DBGFR0BpPortIoInitReqHandler(PGVM pGVM, PDBGFBPINITREQ pReq); + +/** + * Request buffer for DBGFR0BpOwnerInitReqHandler / VMMR0_DO_DBGF_BP_OWNER_INIT. + * @see DBGFR0BpOwnerInitReqHandler. + */ +typedef struct DBGFBPOWNERINITREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Ring-3 pointer of the breakpoint owner table on success. */ + R3PTRTYPE(void *) paBpOwnerR3; +} DBGFBPOWNERINITREQ; +/** Pointer to a DBGFR0BpOwnerInitReqHandler / VMMR0_DO_DBGF_BP_INIT request buffer. */ +typedef DBGFBPOWNERINITREQ *PDBGFBPOWNERINITREQ; + +VMMR0_INT_DECL(int) DBGFR0BpOwnerInitReqHandler(PGVM pGVM, PDBGFBPOWNERINITREQ pReq); + +/** + * Request buffer for DBGFR0BpChunkAllocReqHandler / VMMR0_DO_DBGF_CHUNK_ALLOC. + * @see DBGFR0BpChunkAllocReqHandler. + */ +typedef struct DBGFBPCHUNKALLOCREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Ring-3 pointer of the chunk base on success. */ + R3PTRTYPE(void *) pChunkBaseR3; + + /** The chunk ID to allocate. */ + uint32_t idChunk; +} DBGFBPCHUNKALLOCREQ; +/** Pointer to a DBGFR0BpChunkAllocReqHandler / VMMR0_DO_DBGF_CHUNK_ALLOC request buffer. */ +typedef DBGFBPCHUNKALLOCREQ *PDBGFBPCHUNKALLOCREQ; + +VMMR0_INT_DECL(int) DBGFR0BpChunkAllocReqHandler(PGVM pGVM, PDBGFBPCHUNKALLOCREQ pReq); + +/** + * Request buffer for DBGFR0BpL2TblChunkAllocReqHandler / VMMR0_DO_DBGF_L2_TBL_CHUNK_ALLOC. + * @see DBGFR0BpL2TblChunkAllocReqHandler. + */ +typedef struct DBGFBPL2TBLCHUNKALLOCREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Ring-3 pointer of the chunk base on success. */ + R3PTRTYPE(void *) pChunkBaseR3; + + /** The chunk ID to allocate. */ + uint32_t idChunk; +} DBGFBPL2TBLCHUNKALLOCREQ; +/** Pointer to a DBGFR0BpChunkAllocReqHandler / VMMR0_DO_DBGF_L2_TBL_CHUNK_ALLOC request buffer. */ +typedef DBGFBPL2TBLCHUNKALLOCREQ *PDBGFBPL2TBLCHUNKALLOCREQ; + +VMMR0_INT_DECL(int) DBGFR0BpL2TblChunkAllocReqHandler(PGVM pGVM, PDBGFBPL2TBLCHUNKALLOCREQ pReq); +/** @} */ + + +#ifdef IN_RING3 + +/** + * Mixed address. + */ +typedef struct DBGFADDRESS +{ + /** The flat address. */ + RTGCUINTPTR FlatPtr; + /** The selector offset address. */ + RTGCUINTPTR off; + /** The selector. DBGF_SEL_FLAT is a legal value. */ + RTSEL Sel; + /** Flags describing further details about the address. */ + uint16_t fFlags; +} DBGFADDRESS; +/** Pointer to a mixed address. */ +typedef DBGFADDRESS *PDBGFADDRESS; +/** Pointer to a const mixed address. */ +typedef const DBGFADDRESS *PCDBGFADDRESS; + +/** @name DBGFADDRESS Flags. + * @{ */ +/** A 16:16 far address. */ +#define DBGFADDRESS_FLAGS_FAR16 0 +/** A 16:32 far address. */ +#define DBGFADDRESS_FLAGS_FAR32 1 +/** A 16:64 far address. */ +#define DBGFADDRESS_FLAGS_FAR64 2 +/** A flat address. */ +#define DBGFADDRESS_FLAGS_FLAT 3 +/** A physical address. */ +#define DBGFADDRESS_FLAGS_PHYS 4 +/** A ring-0 host address (internal use only). */ +#define DBGFADDRESS_FLAGS_RING0 5 +/** The address type mask. */ +#define DBGFADDRESS_FLAGS_TYPE_MASK 7 + +/** Set if the address is valid. */ +#define DBGFADDRESS_FLAGS_VALID RT_BIT(3) + +/** Checks if the mixed address is flat or not. */ +#define DBGFADDRESS_IS_FLAT(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_FLAT ) +/** Checks if the mixed address is flat or not. */ +#define DBGFADDRESS_IS_PHYS(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_PHYS ) +/** Checks if the mixed address is far 16:16 or not. */ +#define DBGFADDRESS_IS_FAR16(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_FAR16 ) +/** Checks if the mixed address is far 16:32 or not. */ +#define DBGFADDRESS_IS_FAR32(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_FAR32 ) +/** Checks if the mixed address is far 16:64 or not. */ +#define DBGFADDRESS_IS_FAR64(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_FAR64 ) +/** Checks if the mixed address is any kind of far address. */ +#define DBGFADDRESS_IS_FAR(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) <= DBGFADDRESS_FLAGS_FAR64 ) +/** Checks if the mixed address host context ring-0 (special). */ +#define DBGFADDRESS_IS_R0_HC(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) == DBGFADDRESS_FLAGS_RING0 ) +/** Checks if the mixed address a virtual guest context address (incl HMA). */ +#define DBGFADDRESS_IS_VIRT_GC(pAddress) ( ((pAddress)->fFlags & DBGFADDRESS_FLAGS_TYPE_MASK) <= DBGFADDRESS_FLAGS_FLAT ) +/** Checks if the mixed address is valid. */ +#define DBGFADDRESS_IS_VALID(pAddress) RT_BOOL((pAddress)->fFlags & DBGFADDRESS_FLAGS_VALID) +/** @} */ + +VMMR3DECL(int) DBGFR3AddrFromSelOff(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, RTSEL Sel, RTUINTPTR off); +VMMR3DECL(int) DBGFR3AddrFromSelInfoOff(PUVM pUVM, PDBGFADDRESS pAddress, PCDBGFSELINFO pSelInfo, RTUINTPTR off); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrFromFlat(PUVM pUVM, PDBGFADDRESS pAddress, RTGCUINTPTR FlatPtr); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrFromPhys(PUVM pUVM, PDBGFADDRESS pAddress, RTGCPHYS PhysAddr); +VMMR3_INT_DECL(PDBGFADDRESS) DBGFR3AddrFromHostR0(PDBGFADDRESS pAddress, RTR0UINTPTR R0Ptr); +VMMR3DECL(bool) DBGFR3AddrIsValid(PUVM pUVM, PCDBGFADDRESS pAddress); +VMMR3DECL(int) DBGFR3AddrToPhys(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, PRTGCPHYS pGCPhys); +VMMR3DECL(int) DBGFR3AddrToHostPhys(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, PRTHCPHYS pHCPhys); +VMMR3DECL(int) DBGFR3AddrToVolatileR3Ptr(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddress, bool fReadOnly, void **ppvR3Ptr); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrAdd(PDBGFADDRESS pAddress, RTGCUINTPTR uAddend); +VMMR3DECL(PDBGFADDRESS) DBGFR3AddrSub(PDBGFADDRESS pAddress, RTGCUINTPTR uSubtrahend); + +#endif /* IN_RING3 */ + + + +/** + * VMM Debug Event Type. + */ +typedef enum DBGFEVENTTYPE +{ + /** Halt completed. + * This notifies that a halt command have been successfully completed. + */ + DBGFEVENT_HALT_DONE = 0, + /** Detach completed. + * This notifies that the detach command have been successfully completed. + */ + DBGFEVENT_DETACH_DONE, + /** The command from the debugger is not recognized. + * This means internal error or half implemented features. + */ + DBGFEVENT_INVALID_COMMAND, + + /** Fatal error. + * This notifies a fatal error in the VMM and that the debugger get's a + * chance to first hand information about the the problem. + */ + DBGFEVENT_FATAL_ERROR, + /** Breakpoint Hit. + * This notifies that a breakpoint installed by the debugger was hit. The + * identifier of the breakpoint can be found in the DBGFEVENT::u::Bp::iBp member. + */ + DBGFEVENT_BREAKPOINT, + /** I/O port breakpoint. + * @todo not yet implemented. */ + DBGFEVENT_BREAKPOINT_IO, + /** MMIO breakpoint. + * @todo not yet implemented. */ + DBGFEVENT_BREAKPOINT_MMIO, + /** Breakpoint Hit in the Hypervisor. + * This notifies that a breakpoint installed by the debugger was hit. The + * identifier of the breakpoint can be found in the DBGFEVENT::u::Bp::iBp member. + * @todo raw-mode: remove this + */ + DBGFEVENT_BREAKPOINT_HYPER, + /** Assertion in the Hypervisor (breakpoint instruction). + * This notifies that a breakpoint instruction was hit in the hypervisor context. + */ + DBGFEVENT_ASSERTION_HYPER, + /** Single Stepped. + * This notifies that a single step operation was completed. + */ + DBGFEVENT_STEPPED, + /** Single Stepped. + * This notifies that a hypervisor single step operation was completed. + */ + DBGFEVENT_STEPPED_HYPER, + /** The developer have used the DBGFSTOP macro or the PDMDeviceDBGFSTOP function + * to bring up the debugger at a specific place. + */ + DBGFEVENT_DEV_STOP, + /** The VM is powering off. + * When this notification is received, the debugger thread should detach ASAP. + */ + DBGFEVENT_POWERING_OFF, + + /** Hardware Interrupt break. + * @todo not yet implemented. */ + DBGFEVENT_INTERRUPT_HARDWARE, + /** Software Interrupt break. + * @todo not yet implemented. */ + DBGFEVENT_INTERRUPT_SOFTWARE, + + /** The first selectable event. + * Whether the debugger wants or doesn't want these events can be configured + * via DBGFR3xxx and queried via DBGFR3yyy. */ + DBGFEVENT_FIRST_SELECTABLE, + /** Tripple fault. */ + DBGFEVENT_TRIPLE_FAULT = DBGFEVENT_FIRST_SELECTABLE, + + /** @name Exception events + * The exception events normally represents guest exceptions, but depending on + * the execution mode some virtualization exceptions may occure (no nested + * paging, raw-mode, ++). When necessary, we will request additional VM exits. + * @{ */ + DBGFEVENT_XCPT_FIRST, /**< The first exception event. */ + DBGFEVENT_XCPT_DE /**< 0x00 - \#DE - Fault - NoErr - Integer divide error (zero/overflow). */ + = DBGFEVENT_XCPT_FIRST, + DBGFEVENT_XCPT_DB, /**< 0x01 - \#DB - trap/fault - NoErr - debug event. */ + DBGFEVENT_XCPT_02, /**< 0x02 - Reserved for NMI, see interrupt events. */ + DBGFEVENT_XCPT_BP, /**< 0x03 - \#BP - Trap - NoErr - Breakpoint, INT 3 instruction. */ + DBGFEVENT_XCPT_OF, /**< 0x04 - \#OF - Trap - NoErr - Overflow, INTO instruction. */ + DBGFEVENT_XCPT_BR, /**< 0x05 - \#BR - Fault - NoErr - BOUND Range Exceeded, BOUND instruction. */ + DBGFEVENT_XCPT_UD, /**< 0x06 - \#UD - Fault - NoErr - Undefined(/Invalid) Opcode. */ + DBGFEVENT_XCPT_NM, /**< 0x07 - \#NM - Fault - NoErr - Device not available, FP or (F)WAIT instruction. */ + DBGFEVENT_XCPT_DF, /**< 0x08 - \#DF - Abort - Err=0 - Double fault. */ + DBGFEVENT_XCPT_09, /**< 0x09 - Int9 - Fault - NoErr - Coprocessor Segment Overrun (obsolete). */ + DBGFEVENT_XCPT_TS, /**< 0x0a - \#TS - Fault - ErrCd - Invalid TSS, Taskswitch or TSS access. */ + DBGFEVENT_XCPT_NP, /**< 0x0b - \#NP - Fault - ErrCd - Segment not present. */ + DBGFEVENT_XCPT_SS, /**< 0x0c - \#SS - Fault - ErrCd - Stack-Segment fault. */ + DBGFEVENT_XCPT_GP, /**< 0x0d - \#GP - Fault - ErrCd - General protection fault. */ + DBGFEVENT_XCPT_PF, /**< 0x0e - \#PF - Fault - ErrCd - Page fault. - interrupt gate!!! */ + DBGFEVENT_XCPT_0f, /**< 0x0f - Rsvd - Resvd - Resvd - Intel Reserved. */ + DBGFEVENT_XCPT_MF, /**< 0x10 - \#MF - Fault - NoErr - x86 FPU Floating-Point Error (Math fault), FP or (F)WAIT instruction. */ + DBGFEVENT_XCPT_AC, /**< 0x11 - \#AC - Fault - Err=0 - Alignment Check. */ + DBGFEVENT_XCPT_MC, /**< 0x12 - \#MC - Abort - NoErr - Machine Check. */ + DBGFEVENT_XCPT_XF, /**< 0x13 - \#XF - Fault - NoErr - SIMD Floating-Point Exception. */ + DBGFEVENT_XCPT_VE, /**< 0x14 - \#VE - Fault - Noerr - Virtualization exception. */ + DBGFEVENT_XCPT_15, /**< 0x15 - Intel Reserved. */ + DBGFEVENT_XCPT_16, /**< 0x16 - Intel Reserved. */ + DBGFEVENT_XCPT_17, /**< 0x17 - Intel Reserved. */ + DBGFEVENT_XCPT_18, /**< 0x18 - Intel Reserved. */ + DBGFEVENT_XCPT_19, /**< 0x19 - Intel Reserved. */ + DBGFEVENT_XCPT_1a, /**< 0x1a - Intel Reserved. */ + DBGFEVENT_XCPT_1b, /**< 0x1b - Intel Reserved. */ + DBGFEVENT_XCPT_1c, /**< 0x1c - Intel Reserved. */ + DBGFEVENT_XCPT_1d, /**< 0x1d - Intel Reserved. */ + DBGFEVENT_XCPT_SX, /**< 0x1e - \#SX - Fault - ErrCd - Security Exception. */ + DBGFEVENT_XCPT_1f, /**< 0x1f - Intel Reserved. */ + DBGFEVENT_XCPT_LAST /**< The last exception event. */ + = DBGFEVENT_XCPT_1f, + /** @} */ + + /** @name Instruction events + * The instruction events exerts all possible effort to intercept the + * relevant instructions. However, in some execution modes we won't be able + * to catch them. So it goes. + * @{ */ + DBGFEVENT_INSTR_FIRST, /**< The first VM instruction event. */ + DBGFEVENT_INSTR_HALT /**< Instruction: HALT */ + = DBGFEVENT_INSTR_FIRST, + DBGFEVENT_INSTR_MWAIT, /**< Instruction: MWAIT */ + DBGFEVENT_INSTR_MONITOR, /**< Instruction: MONITOR */ + DBGFEVENT_INSTR_CPUID, /**< Instruction: CPUID (missing stuff in raw-mode). */ + DBGFEVENT_INSTR_INVD, /**< Instruction: INVD */ + DBGFEVENT_INSTR_WBINVD, /**< Instruction: WBINVD */ + DBGFEVENT_INSTR_INVLPG, /**< Instruction: INVLPG */ + DBGFEVENT_INSTR_RDTSC, /**< Instruction: RDTSC */ + DBGFEVENT_INSTR_RDTSCP, /**< Instruction: RDTSCP */ + DBGFEVENT_INSTR_RDPMC, /**< Instruction: RDPMC */ + DBGFEVENT_INSTR_RDMSR, /**< Instruction: RDMSR */ + DBGFEVENT_INSTR_WRMSR, /**< Instruction: WRMSR */ + DBGFEVENT_INSTR_CRX_READ, /**< Instruction: CRx read instruction (missing smsw in raw-mode, and reads in general in VT-x). */ + DBGFEVENT_INSTR_CRX_WRITE, /**< Instruction: CRx write */ + DBGFEVENT_INSTR_DRX_READ, /**< Instruction: DRx read */ + DBGFEVENT_INSTR_DRX_WRITE, /**< Instruction: DRx write */ + DBGFEVENT_INSTR_PAUSE, /**< Instruction: PAUSE instruction (not in raw-mode). */ + DBGFEVENT_INSTR_XSETBV, /**< Instruction: XSETBV */ + DBGFEVENT_INSTR_SIDT, /**< Instruction: SIDT */ + DBGFEVENT_INSTR_LIDT, /**< Instruction: LIDT */ + DBGFEVENT_INSTR_SGDT, /**< Instruction: SGDT */ + DBGFEVENT_INSTR_LGDT, /**< Instruction: LGDT */ + DBGFEVENT_INSTR_SLDT, /**< Instruction: SLDT */ + DBGFEVENT_INSTR_LLDT, /**< Instruction: LLDT */ + DBGFEVENT_INSTR_STR, /**< Instruction: STR */ + DBGFEVENT_INSTR_LTR, /**< Instruction: LTR */ + DBGFEVENT_INSTR_GETSEC, /**< Instruction: GETSEC */ + DBGFEVENT_INSTR_RSM, /**< Instruction: RSM */ + DBGFEVENT_INSTR_RDRAND, /**< Instruction: RDRAND */ + DBGFEVENT_INSTR_RDSEED, /**< Instruction: RDSEED */ + DBGFEVENT_INSTR_XSAVES, /**< Instruction: XSAVES */ + DBGFEVENT_INSTR_XRSTORS, /**< Instruction: XRSTORS */ + DBGFEVENT_INSTR_VMM_CALL, /**< Instruction: VMCALL (intel) or VMMCALL (AMD) */ + DBGFEVENT_INSTR_LAST_COMMON /**< Instruction: the last common event. */ + = DBGFEVENT_INSTR_VMM_CALL, + DBGFEVENT_INSTR_VMX_FIRST, /**< Instruction: VT-x - First. */ + DBGFEVENT_INSTR_VMX_VMCLEAR /**< Instruction: VT-x VMCLEAR */ + = DBGFEVENT_INSTR_VMX_FIRST, + DBGFEVENT_INSTR_VMX_VMLAUNCH, /**< Instruction: VT-x VMLAUNCH */ + DBGFEVENT_INSTR_VMX_VMPTRLD, /**< Instruction: VT-x VMPTRLD */ + DBGFEVENT_INSTR_VMX_VMPTRST, /**< Instruction: VT-x VMPTRST */ + DBGFEVENT_INSTR_VMX_VMREAD, /**< Instruction: VT-x VMREAD */ + DBGFEVENT_INSTR_VMX_VMRESUME, /**< Instruction: VT-x VMRESUME */ + DBGFEVENT_INSTR_VMX_VMWRITE, /**< Instruction: VT-x VMWRITE */ + DBGFEVENT_INSTR_VMX_VMXOFF, /**< Instruction: VT-x VMXOFF */ + DBGFEVENT_INSTR_VMX_VMXON, /**< Instruction: VT-x VMXON */ + DBGFEVENT_INSTR_VMX_VMFUNC, /**< Instruction: VT-x VMFUNC */ + DBGFEVENT_INSTR_VMX_INVEPT, /**< Instruction: VT-x INVEPT */ + DBGFEVENT_INSTR_VMX_INVVPID, /**< Instruction: VT-x INVVPID */ + DBGFEVENT_INSTR_VMX_INVPCID, /**< Instruction: VT-x INVPCID */ + DBGFEVENT_INSTR_VMX_LAST /**< Instruction: VT-x - Last. */ + = DBGFEVENT_INSTR_VMX_INVPCID, + DBGFEVENT_INSTR_SVM_FIRST, /**< Instruction: AMD-V - first */ + DBGFEVENT_INSTR_SVM_VMRUN /**< Instruction: AMD-V VMRUN */ + = DBGFEVENT_INSTR_SVM_FIRST, + DBGFEVENT_INSTR_SVM_VMLOAD, /**< Instruction: AMD-V VMLOAD */ + DBGFEVENT_INSTR_SVM_VMSAVE, /**< Instruction: AMD-V VMSAVE */ + DBGFEVENT_INSTR_SVM_STGI, /**< Instruction: AMD-V STGI */ + DBGFEVENT_INSTR_SVM_CLGI, /**< Instruction: AMD-V CLGI */ + DBGFEVENT_INSTR_SVM_LAST /**< Instruction: The last ADM-V VM exit event. */ + = DBGFEVENT_INSTR_SVM_CLGI, + DBGFEVENT_INSTR_LAST /**< Instruction: The last instruction event. */ + = DBGFEVENT_INSTR_SVM_LAST, + /** @} */ + + + /** @name VM exit events. + * VM exits events for VT-x and AMD-V execution mode. Many of the VM exits + * behind these events are also directly translated into instruction events, but + * the difference here is that the exit events will not try provoke the exits. + * @{ */ + DBGFEVENT_EXIT_FIRST, /**< The first VM exit event. */ + DBGFEVENT_EXIT_TASK_SWITCH /**< Exit: Task switch. */ + = DBGFEVENT_EXIT_FIRST, + DBGFEVENT_EXIT_HALT, /**< Exit: HALT instruction. */ + DBGFEVENT_EXIT_MWAIT, /**< Exit: MWAIT instruction. */ + DBGFEVENT_EXIT_MONITOR, /**< Exit: MONITOR instruction. */ + DBGFEVENT_EXIT_CPUID, /**< Exit: CPUID instruction (missing stuff in raw-mode). */ + DBGFEVENT_EXIT_INVD, /**< Exit: INVD instruction. */ + DBGFEVENT_EXIT_WBINVD, /**< Exit: WBINVD instruction. */ + DBGFEVENT_EXIT_INVLPG, /**< Exit: INVLPG instruction. */ + DBGFEVENT_EXIT_RDTSC, /**< Exit: RDTSC instruction. */ + DBGFEVENT_EXIT_RDTSCP, /**< Exit: RDTSCP instruction. */ + DBGFEVENT_EXIT_RDPMC, /**< Exit: RDPMC instruction. */ + DBGFEVENT_EXIT_RDMSR, /**< Exit: RDMSR instruction. */ + DBGFEVENT_EXIT_WRMSR, /**< Exit: WRMSR instruction. */ + DBGFEVENT_EXIT_CRX_READ, /**< Exit: CRx read instruction (missing smsw in raw-mode, and reads in general in VT-x). */ + DBGFEVENT_EXIT_CRX_WRITE, /**< Exit: CRx write instruction. */ + DBGFEVENT_EXIT_DRX_READ, /**< Exit: DRx read instruction. */ + DBGFEVENT_EXIT_DRX_WRITE, /**< Exit: DRx write instruction. */ + DBGFEVENT_EXIT_PAUSE, /**< Exit: PAUSE instruction (not in raw-mode). */ + DBGFEVENT_EXIT_XSETBV, /**< Exit: XSETBV instruction. */ + DBGFEVENT_EXIT_SIDT, /**< Exit: SIDT instruction. */ + DBGFEVENT_EXIT_LIDT, /**< Exit: LIDT instruction. */ + DBGFEVENT_EXIT_SGDT, /**< Exit: SGDT instruction. */ + DBGFEVENT_EXIT_LGDT, /**< Exit: LGDT instruction. */ + DBGFEVENT_EXIT_SLDT, /**< Exit: SLDT instruction. */ + DBGFEVENT_EXIT_LLDT, /**< Exit: LLDT instruction. */ + DBGFEVENT_EXIT_STR, /**< Exit: STR instruction. */ + DBGFEVENT_EXIT_LTR, /**< Exit: LTR instruction. */ + DBGFEVENT_EXIT_GETSEC, /**< Exit: GETSEC instruction. */ + DBGFEVENT_EXIT_RSM, /**< Exit: RSM instruction. */ + DBGFEVENT_EXIT_RDRAND, /**< Exit: RDRAND instruction. */ + DBGFEVENT_EXIT_RDSEED, /**< Exit: RDSEED instruction. */ + DBGFEVENT_EXIT_XSAVES, /**< Exit: XSAVES instruction. */ + DBGFEVENT_EXIT_XRSTORS, /**< Exit: XRSTORS instruction. */ + DBGFEVENT_EXIT_VMM_CALL, /**< Exit: VMCALL (intel) or VMMCALL (AMD) instruction. */ + DBGFEVENT_EXIT_LAST_COMMON /**< Exit: the last common event. */ + = DBGFEVENT_EXIT_VMM_CALL, + DBGFEVENT_EXIT_VMX_FIRST, /**< Exit: VT-x - First. */ + DBGFEVENT_EXIT_VMX_VMCLEAR /**< Exit: VT-x VMCLEAR instruction. */ + = DBGFEVENT_EXIT_VMX_FIRST, + DBGFEVENT_EXIT_VMX_VMLAUNCH, /**< Exit: VT-x VMLAUNCH instruction. */ + DBGFEVENT_EXIT_VMX_VMPTRLD, /**< Exit: VT-x VMPTRLD instruction. */ + DBGFEVENT_EXIT_VMX_VMPTRST, /**< Exit: VT-x VMPTRST instruction. */ + DBGFEVENT_EXIT_VMX_VMREAD, /**< Exit: VT-x VMREAD instruction. */ + DBGFEVENT_EXIT_VMX_VMRESUME, /**< Exit: VT-x VMRESUME instruction. */ + DBGFEVENT_EXIT_VMX_VMWRITE, /**< Exit: VT-x VMWRITE instruction. */ + DBGFEVENT_EXIT_VMX_VMXOFF, /**< Exit: VT-x VMXOFF instruction. */ + DBGFEVENT_EXIT_VMX_VMXON, /**< Exit: VT-x VMXON instruction. */ + DBGFEVENT_EXIT_VMX_VMFUNC, /**< Exit: VT-x VMFUNC instruction. */ + DBGFEVENT_EXIT_VMX_INVEPT, /**< Exit: VT-x INVEPT instruction. */ + DBGFEVENT_EXIT_VMX_INVVPID, /**< Exit: VT-x INVVPID instruction. */ + DBGFEVENT_EXIT_VMX_INVPCID, /**< Exit: VT-x INVPCID instruction. */ + DBGFEVENT_EXIT_VMX_EPT_VIOLATION, /**< Exit: VT-x EPT violation. */ + DBGFEVENT_EXIT_VMX_EPT_MISCONFIG, /**< Exit: VT-x EPT misconfiguration. */ + DBGFEVENT_EXIT_VMX_VAPIC_ACCESS, /**< Exit: VT-x Virtual APIC page access. */ + DBGFEVENT_EXIT_VMX_VAPIC_WRITE, /**< Exit: VT-x Virtual APIC write. */ + DBGFEVENT_EXIT_VMX_LAST /**< Exit: VT-x - Last. */ + = DBGFEVENT_EXIT_VMX_VAPIC_WRITE, + DBGFEVENT_EXIT_SVM_FIRST, /**< Exit: AMD-V - first */ + DBGFEVENT_EXIT_SVM_VMRUN /**< Exit: AMD-V VMRUN instruction. */ + = DBGFEVENT_EXIT_SVM_FIRST, + DBGFEVENT_EXIT_SVM_VMLOAD, /**< Exit: AMD-V VMLOAD instruction. */ + DBGFEVENT_EXIT_SVM_VMSAVE, /**< Exit: AMD-V VMSAVE instruction. */ + DBGFEVENT_EXIT_SVM_STGI, /**< Exit: AMD-V STGI instruction. */ + DBGFEVENT_EXIT_SVM_CLGI, /**< Exit: AMD-V CLGI instruction. */ + DBGFEVENT_EXIT_SVM_LAST /**< Exit: The last ADM-V VM exit event. */ + = DBGFEVENT_EXIT_SVM_CLGI, + DBGFEVENT_EXIT_LAST /**< Exit: The last VM exit event. */ + = DBGFEVENT_EXIT_SVM_LAST, + /** @} */ + + + /** @name Misc VT-x and AMD-V execution events. + * @{ */ + DBGFEVENT_VMX_SPLIT_LOCK, /**< VT-x: Split-lock \#AC triggered by host having detection enabled. */ + /** @} */ + + + /** Access to an unassigned I/O port. + * @todo not yet implemented. */ + DBGFEVENT_IOPORT_UNASSIGNED, + /** Access to an unused I/O port on a device. + * @todo not yet implemented. */ + DBGFEVENT_IOPORT_UNUSED, + /** Unassigned memory event. + * @todo not yet implemented. */ + DBGFEVENT_MEMORY_UNASSIGNED, + /** Attempt to write to unshadowed ROM. + * @todo not yet implemented. */ + DBGFEVENT_MEMORY_ROM_WRITE, + + /** Windows guest reported BSOD via hyperv MSRs. */ + DBGFEVENT_BSOD_MSR, + /** Windows guest reported BSOD via EFI variables. */ + DBGFEVENT_BSOD_EFI, + /** Windows guest reported BSOD via VMMDev. */ + DBGFEVENT_BSOD_VMMDEV, + + /** End of valid event values. */ + DBGFEVENT_END, + /** The usual 32-bit hack. */ + DBGFEVENT_32BIT_HACK = 0x7fffffff +} DBGFEVENTTYPE; +AssertCompile(DBGFEVENT_XCPT_LAST - DBGFEVENT_XCPT_FIRST == 0x1f); + +/** + * The context of an event. + */ +typedef enum DBGFEVENTCTX +{ + /** The usual invalid entry. */ + DBGFEVENTCTX_INVALID = 0, + /** Raw mode. */ + DBGFEVENTCTX_RAW, + /** Recompiled mode. */ + DBGFEVENTCTX_REM, + /** VMX / AVT mode. */ + DBGFEVENTCTX_HM, + /** Hypervisor context. */ + DBGFEVENTCTX_HYPER, + /** Other mode */ + DBGFEVENTCTX_OTHER, + + /** The usual 32-bit hack */ + DBGFEVENTCTX_32BIT_HACK = 0x7fffffff +} DBGFEVENTCTX; + +/** + * VMM Debug Event. + */ +typedef struct DBGFEVENT +{ + /** Type. */ + DBGFEVENTTYPE enmType; + /** Context */ + DBGFEVENTCTX enmCtx; + /** The vCPU/EMT which generated the event. */ + VMCPUID idCpu; + /** Reserved. */ + uint32_t uReserved; + /** Type specific data. */ + union + { + /** Fatal error details. */ + struct + { + /** The GC return code. */ + int rc; + } FatalError; + + /** Source location. */ + struct + { + /** File name. */ + R3PTRTYPE(const char *) pszFile; + /** Function name. */ + R3PTRTYPE(const char *) pszFunction; + /** Message. */ + R3PTRTYPE(const char *) pszMessage; + /** Line number. */ + unsigned uLine; + } Src; + + /** Assertion messages. */ + struct + { + /** The first message. */ + R3PTRTYPE(const char *) pszMsg1; + /** The second message. */ + R3PTRTYPE(const char *) pszMsg2; + } Assert; + + /** Breakpoint. */ + struct DBGFEVENTBP + { + /** The handle of the breakpoint which was hit. */ + DBGFBP hBp; + } Bp; + + /** Generic debug event. */ + struct DBGFEVENTGENERIC + { + /** Number of arguments. */ + uint8_t cArgs; + /** Alignment padding. */ + uint8_t uPadding[7]; + /** Arguments. */ + uint64_t auArgs[5]; + } Generic; + + /** Padding for ensuring that the structure is 8 byte aligned. */ + uint64_t au64Padding[6]; + } u; +} DBGFEVENT; +AssertCompileSizeAlignment(DBGFEVENT, 8); +AssertCompileSize(DBGFEVENT, 64); +/** Pointer to VMM Debug Event. */ +typedef DBGFEVENT *PDBGFEVENT; +/** Pointer to const VMM Debug Event. */ +typedef const DBGFEVENT *PCDBGFEVENT; + +#ifdef IN_RING3 /* The event API only works in ring-3. */ + +/** @def DBGFSTOP + * Stops the debugger raising a DBGFEVENT_DEVELOPER_STOP event. + * + * @returns VBox status code which must be propagated up to EM if not VINF_SUCCESS. + * @param pVM The cross context VM structure. + */ +# ifdef VBOX_STRICT +# define DBGFSTOP(pVM) DBGFR3EventSrc(pVM, DBGFEVENT_DEV_STOP, __FILE__, __LINE__, __PRETTY_FUNCTION__, NULL) +# else +# define DBGFSTOP(pVM) VINF_SUCCESS +# endif + +VMMR3_INT_DECL(int) DBGFR3Init(PVM pVM); +VMMR3_INT_DECL(int) DBGFR3Term(PVM pVM); +VMMR3DECL(void) DBGFR3TermUVM(PUVM pUVM); +VMMR3_INT_DECL(void) DBGFR3PowerOff(PVM pVM); +VMMR3_INT_DECL(void) DBGFR3Relocate(PVM pVM, RTGCINTPTR offDelta); + +VMMR3_INT_DECL(int) DBGFR3VMMForcedAction(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(VBOXSTRICTRC) DBGFR3EventHandlePending(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) DBGFR3Event(PVM pVM, DBGFEVENTTYPE enmEvent); +VMMR3DECL(int) DBGFR3EventSrc(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, + const char *pszFunction, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 7); +VMMR3DECL(int) DBGFR3EventSrcV(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszFile, unsigned uLine, + const char *pszFunction, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR_MAYBE_NULL(6, 0); +VMMR3_INT_DECL(int) DBGFR3EventAssertion(PVM pVM, DBGFEVENTTYPE enmEvent, const char *pszMsg1, const char *pszMsg2); +VMMR3_INT_DECL(int) DBGFR3EventBreakpoint(PVM pVM, DBGFEVENTTYPE enmEvent); + +VMMR3_INT_DECL(int) DBGFR3PrgStep(PVMCPU pVCpu); + +VMMR3DECL(int) DBGFR3Attach(PUVM pUVM); +VMMR3DECL(int) DBGFR3Detach(PUVM pUVM); +VMMR3DECL(int) DBGFR3EventWait(PUVM pUVM, RTMSINTERVAL cMillies, PDBGFEVENT pEvent); +VMMR3DECL(int) DBGFR3Halt(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(bool) DBGFR3IsHalted(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) DBGFR3QueryWaitable(PUVM pUVM); +VMMR3DECL(int) DBGFR3Resume(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) DBGFR3InjectNMI(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) DBGFR3Step(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) DBGFR3StepEx(PUVM pUVM, VMCPUID idCpu, uint32_t fFlags, PCDBGFADDRESS pStopPcAddr, + PCDBGFADDRESS pStopPopAddr, RTGCUINTPTR cbStopPop, uint32_t cMaxSteps); + +/** @name DBGF_STEP_F_XXX - Flags for DBGFR3StepEx. + * + * @note The stop filters are not applied to the starting instruction. + * + * @{ */ +/** Step into CALL, INT, SYSCALL and SYSENTER instructions. */ +#define DBGF_STEP_F_INTO RT_BIT_32(0) +/** Step over CALL, INT, SYSCALL and SYSENTER instruction when considering + * what's "next". */ +#define DBGF_STEP_F_OVER RT_BIT_32(1) + +/** Stop on the next CALL, INT, SYSCALL, SYSENTER instruction. */ +#define DBGF_STEP_F_STOP_ON_CALL RT_BIT_32(8) +/** Stop on the next RET, IRET, SYSRET, SYSEXIT instruction. */ +#define DBGF_STEP_F_STOP_ON_RET RT_BIT_32(9) +/** Stop after the next RET, IRET, SYSRET, SYSEXIT instruction. */ +#define DBGF_STEP_F_STOP_AFTER_RET RT_BIT_32(10) +/** Stop on the given address. + * The comparison will be made using effective (flat) addresses. */ +#define DBGF_STEP_F_STOP_ON_ADDRESS RT_BIT_32(11) +/** Stop when the stack pointer pops to or past the given address. + * The comparison will be made using effective (flat) addresses. */ +#define DBGF_STEP_F_STOP_ON_STACK_POP RT_BIT_32(12) +/** Mask of stop filter flags. */ +#define DBGF_STEP_F_STOP_FILTER_MASK UINT32_C(0x00001f00) + +/** Mask of valid flags. */ +#define DBGF_STEP_F_VALID_MASK UINT32_C(0x00001f03) +/** @} */ + +/** + * Event configuration array element, see DBGFR3EventConfigEx. + */ +typedef struct DBGFEVENTCONFIG +{ + /** The event to configure */ + DBGFEVENTTYPE enmType; + /** The new state. */ + bool fEnabled; + /** Unused. */ + uint8_t abUnused[3]; +} DBGFEVENTCONFIG; +/** Pointer to an event config. */ +typedef DBGFEVENTCONFIG *PDBGFEVENTCONFIG; +/** Pointer to a const event config. */ +typedef const DBGFEVENTCONFIG *PCDBGFEVENTCONFIG; + +VMMR3DECL(int) DBGFR3EventConfigEx(PUVM pUVM, PCDBGFEVENTCONFIG paConfigs, size_t cConfigs); +VMMR3DECL(int) DBGFR3EventConfig(PUVM pUVM, DBGFEVENTTYPE enmEvent, bool fEnabled); +VMMR3DECL(bool) DBGFR3EventIsEnabled(PUVM pUVM, DBGFEVENTTYPE enmEvent); +VMMR3DECL(int) DBGFR3EventQuery(PUVM pUVM, PDBGFEVENTCONFIG paConfigs, size_t cConfigs); + +/** @name DBGFINTERRUPTSTATE_XXX - interrupt break state. + * @{ */ +#define DBGFINTERRUPTSTATE_DISABLED 0 +#define DBGFINTERRUPTSTATE_ENABLED 1 +#define DBGFINTERRUPTSTATE_DONT_TOUCH 2 +/** @} */ + +/** + * Interrupt break state configuration entry. + */ +typedef struct DBGFINTERRUPTCONFIG +{ + /** The interrupt number. */ + uint8_t iInterrupt; + /** The hardware interrupt state (DBGFINTERRUPTSTATE_XXX). */ + uint8_t enmHardState; + /** The software interrupt state (DBGFINTERRUPTSTATE_XXX). */ + uint8_t enmSoftState; +} DBGFINTERRUPTCONFIG; +/** Pointer to an interrupt break state config entyr. */ +typedef DBGFINTERRUPTCONFIG *PDBGFINTERRUPTCONFIG; +/** Pointer to a const interrupt break state config entyr. */ +typedef DBGFINTERRUPTCONFIG const *PCDBGFINTERRUPTCONFIG; + +VMMR3DECL(int) DBGFR3InterruptConfigEx(PUVM pUVM, PCDBGFINTERRUPTCONFIG paConfigs, size_t cConfigs); +VMMR3DECL(int) DBGFR3InterruptHardwareConfig(PUVM pUVM, uint8_t iInterrupt, bool fEnabled); +VMMR3DECL(int) DBGFR3InterruptSoftwareConfig(PUVM pUVM, uint8_t iInterrupt, bool fEnabled); +VMMR3DECL(int) DBGFR3InterruptHardwareIsEnabled(PUVM pUVM, uint8_t iInterrupt); +VMMR3DECL(int) DBGFR3InterruptSoftwareIsEnabled(PUVM pUVM, uint8_t iInterrupt); + +#endif /* IN_RING3 */ + +/** @def DBGF_IS_EVENT_ENABLED + * Checks if a selectable debug event is enabled or not (fast). + * + * @returns true/false. + * @param a_pVM Pointer to the cross context VM structure. + * @param a_enmEvent The selectable event to check. + * @remarks Only for use internally in the VMM. Use DBGFR3EventIsEnabled elsewhere. + */ +#if defined(VBOX_STRICT) && defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define DBGF_IS_EVENT_ENABLED(a_pVM, a_enmEvent) \ + ([](PVM a_pLambdaVM, DBGFEVENTTYPE a_enmLambdaEvent) -> bool { \ + Assert( a_enmLambdaEvent >= DBGFEVENT_FIRST_SELECTABLE \ + || a_enmLambdaEvent == DBGFEVENT_INTERRUPT_HARDWARE \ + || a_enmLambdaEvent == DBGFEVENT_INTERRUPT_SOFTWARE); \ + Assert(a_enmLambdaEvent < DBGFEVENT_END); \ + return ASMBitTest(&a_pLambdaVM->dbgf.ro.bmSelectedEvents, a_enmLambdaEvent); \ + }(a_pVM, a_enmEvent)) +#elif defined(VBOX_STRICT) && defined(__GNUC__) +# define DBGF_IS_EVENT_ENABLED(a_pVM, a_enmEvent) \ + __extension__ ({ \ + Assert( (a_enmEvent) >= DBGFEVENT_FIRST_SELECTABLE \ + || (a_enmEvent) == DBGFEVENT_INTERRUPT_HARDWARE \ + || (a_enmEvent) == DBGFEVENT_INTERRUPT_SOFTWARE); \ + Assert((a_enmEvent) < DBGFEVENT_END); \ + ASMBitTest(&(a_pVM)->dbgf.ro.bmSelectedEvents, (a_enmEvent)); \ + }) +#else +# define DBGF_IS_EVENT_ENABLED(a_pVM, a_enmEvent) \ + ASMBitTest(&(a_pVM)->dbgf.ro.bmSelectedEvents, (a_enmEvent)) +#endif + + +/** @def DBGF_IS_HARDWARE_INT_ENABLED + * Checks if hardware interrupt interception is enabled or not for an interrupt. + * + * @returns true/false. + * @param a_pVM Pointer to the cross context VM structure. + * @param a_iInterrupt Interrupt to check. + * @remarks Only for use internally in the VMM. Use + * DBGFR3InterruptHardwareIsEnabled elsewhere. + */ +#define DBGF_IS_HARDWARE_INT_ENABLED(a_pVM, a_iInterrupt) \ + ASMBitTest(&(a_pVM)->dbgf.ro.bmHardIntBreakpoints, (uint8_t)(a_iInterrupt)) + +/** @def DBGF_IS_SOFTWARE_INT_ENABLED + * Checks if software interrupt interception is enabled or not for an interrupt. + * + * @returns true/false. + * @param a_pVM Pointer to the cross context VM structure. + * @param a_iInterrupt Interrupt to check. + * @remarks Only for use internally in the VMM. Use + * DBGFR3InterruptSoftwareIsEnabled elsewhere. + */ +#define DBGF_IS_SOFTWARE_INT_ENABLED(a_pVM, a_iInterrupt) \ + ASMBitTest(&(a_pVM)->dbgf.ro.bmSoftIntBreakpoints, (uint8_t)(a_iInterrupt)) + + + +/** Breakpoint type. */ +typedef enum DBGFBPTYPE +{ + /** Invalid breakpoint type. */ + DBGFBPTYPE_INVALID = 0, + /** Debug register. */ + DBGFBPTYPE_REG, + /** INT 3 instruction. */ + DBGFBPTYPE_INT3, + /** Port I/O breakpoint. */ + DBGFBPTYPE_PORT_IO, + /** Memory mapped I/O breakpoint. */ + DBGFBPTYPE_MMIO, + /** ensure 32-bit size. */ + DBGFBPTYPE_32BIT_HACK = 0x7fffffff +} DBGFBPTYPE; + + +/** @name DBGFBPIOACCESS_XXX - I/O (port + mmio) access types. + * @{ */ +/** Byte sized read accesses. */ +#define DBGFBPIOACCESS_READ_BYTE UINT32_C(0x00000001) +/** Word sized accesses. */ +#define DBGFBPIOACCESS_READ_WORD UINT32_C(0x00000002) +/** Double word sized accesses. */ +#define DBGFBPIOACCESS_READ_DWORD UINT32_C(0x00000004) +/** Quad word sized accesses - not available for I/O ports. */ +#define DBGFBPIOACCESS_READ_QWORD UINT32_C(0x00000008) +/** Other sized accesses - not available for I/O ports. */ +#define DBGFBPIOACCESS_READ_OTHER UINT32_C(0x00000010) +/** Read mask. */ +#define DBGFBPIOACCESS_READ_MASK UINT32_C(0x0000001f) + +/** Byte sized write accesses. */ +#define DBGFBPIOACCESS_WRITE_BYTE UINT32_C(0x00000100) +/** Word sized write accesses. */ +#define DBGFBPIOACCESS_WRITE_WORD UINT32_C(0x00000200) +/** Double word sized write accesses. */ +#define DBGFBPIOACCESS_WRITE_DWORD UINT32_C(0x00000400) +/** Quad word sized write accesses - not available for I/O ports. */ +#define DBGFBPIOACCESS_WRITE_QWORD UINT32_C(0x00000800) +/** Other sized write accesses - not available for I/O ports. */ +#define DBGFBPIOACCESS_WRITE_OTHER UINT32_C(0x00001000) +/** Write mask. */ +#define DBGFBPIOACCESS_WRITE_MASK UINT32_C(0x00001f00) + +/** All kind of access (read, write, all sizes). */ +#define DBGFBPIOACCESS_ALL UINT32_C(0x00001f1f) +/** All kind of access for MMIO (read, write, all sizes). */ +#define DBGFBPIOACCESS_ALL_MMIO DBGFBPIOACCESS_ALL +/** All kind of access (read, write, all sizes). */ +#define DBGFBPIOACCESS_ALL_PORT_IO UINT32_C(0x00000303) + +/** The acceptable mask for I/O ports. */ +#define DBGFBPIOACCESS_VALID_MASK_PORT_IO UINT32_C(0x00000303) +/** The acceptable mask for MMIO. */ +#define DBGFBPIOACCESS_VALID_MASK_MMIO UINT32_C(0x00001f1f) +/** @} */ + +/** + * The visible breakpoint state (read-only). + */ +typedef struct DBGFBPPUB +{ + /** The number of breakpoint hits. */ + uint64_t cHits; + /** The hit number which starts to trigger the breakpoint. */ + uint64_t iHitTrigger; + /** The hit number which stops triggering the breakpoint (disables it). + * Use ~(uint64_t)0 if it should never stop. */ + uint64_t iHitDisable; + /** The breakpoint owner handle (a nil owner defers the breakpoint to the + * debugger). */ + DBGFBPOWNER hOwner; + /** Breakpoint type stored as a 16bit integer to stay within size limits. */ + uint16_t u16Type; + /** Breakpoint flags. */ + uint16_t fFlags; + + /** Union of type specific data. */ + union + { + /** The flat GC address breakpoint address for REG and INT3 breakpoints. */ + RTGCUINTPTR GCPtr; + + /** Debug register data. */ + struct DBGFBPREG + { + /** The flat GC address of the breakpoint. */ + RTGCUINTPTR GCPtr; + /** The debug register number. */ + uint8_t iReg; + /** The access type (one of the X86_DR7_RW_* value). */ + uint8_t fType; + /** The access size. */ + uint8_t cb; + } Reg; + + /** INT3 breakpoint data. */ + struct DBGFBPINT3 + { + /** The flat GC address of the breakpoint. */ + RTGCUINTPTR GCPtr; + /** The physical address of the breakpoint. */ + RTGCPHYS PhysAddr; + /** The byte value we replaced by the INT 3 instruction. */ + uint8_t bOrg; + } Int3; + + /** I/O port breakpoint data. */ + struct DBGFBPPORTIO + { + /** The first port. */ + RTIOPORT uPort; + /** The number of ports. */ + RTIOPORT cPorts; + /** Valid DBGFBPIOACCESS_XXX selection, max DWORD size. */ + uint32_t fAccess; + } PortIo; + + /** Memory mapped I/O breakpoint data. */ + struct DBGFBPMMIO + { + /** The first MMIO address. */ + RTGCPHYS PhysAddr; + /** The size of the MMIO range in bytes. */ + uint32_t cb; + /** Valid DBGFBPIOACCESS_XXX selection, max QWORD size. */ + uint32_t fAccess; + } Mmio; + + /** Padding to the anticipated size. */ + uint64_t u64Padding[3]; + } u; +} DBGFBPPUB; +AssertCompileSize(DBGFBPPUB, 64 - 8); +AssertCompileMembersAtSameOffset(DBGFBPPUB, u.GCPtr, DBGFBPPUB, u.Reg.GCPtr); +AssertCompileMembersAtSameOffset(DBGFBPPUB, u.GCPtr, DBGFBPPUB, u.Int3.GCPtr); + +/** Pointer to the visible breakpoint state. */ +typedef DBGFBPPUB *PDBGFBPPUB; +/** Pointer to a const visible breakpoint state. */ +typedef const DBGFBPPUB *PCDBGFBPPUB; + +/** Sets the DBGFPUB::u16Type member. */ +#define DBGF_BP_PUB_MAKE_TYPE(a_enmType) ((uint16_t)(a_enmType)) +/** Returns the type of the DBGFPUB::u16Type member. */ +#define DBGF_BP_PUB_GET_TYPE(a_pBp) ((DBGFBPTYPE)((a_pBp)->u16Type)) +/** Returns the enabled status of DBGFPUB::fFlags member. */ +#define DBGF_BP_PUB_IS_ENABLED(a_pBp) RT_BOOL((a_pBp)->fFlags & DBGF_BP_F_ENABLED) +/** Returns whether DBGF_BP_F_HIT_EXEC_BEFORE is set for DBGFPUB::fFlags. */ +#define DBGF_BP_PUB_IS_EXEC_BEFORE(a_pBp) RT_BOOL((a_pBp)->fFlags & DBGF_BP_F_HIT_EXEC_BEFORE) +/** Returns whether DBGF_BP_F_HIT_EXEC_AFTER is set for DBGFPUB::fFlags. */ +#define DBGF_BP_PUB_IS_EXEC_AFTER(a_pBp) RT_BOOL((a_pBp)->fFlags & DBGF_BP_F_HIT_EXEC_AFTER) + + +/** @name Possible DBGFBPPUB::fFlags flags. + * @{ */ +/** Default flags, breakpoint is enabled and hits before the instruction is executed. */ +#define DBGF_BP_F_DEFAULT (DBGF_BP_F_ENABLED | DBGF_BP_F_HIT_EXEC_BEFORE) +/** Flag whether the breakpoint is enabled currently. */ +#define DBGF_BP_F_ENABLED RT_BIT(0) +/** Flag indicating whether the action assoicated with the breakpoint should be carried out + * before the instruction causing the breakpoint to hit was executed. */ +#define DBGF_BP_F_HIT_EXEC_BEFORE RT_BIT(1) +/** Flag indicating whether the action assoicated with the breakpoint should be carried out + * after the instruction causing the breakpoint to hit was executed. */ +#define DBGF_BP_F_HIT_EXEC_AFTER RT_BIT(2) +/** The acceptable flags mask. */ +#define DBGF_BP_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + + +/** + * Breakpoint hit handler. + * + * @returns Strict VBox status code. + * @retval VINF_SUCCESS if the breakpoint was handled and guest execution can resume. + * @retval VINF_DBGF_BP_HALT if guest execution should be stopped and the debugger should be invoked. + * @retval VINF_DBGF_R3_BP_OWNER_DEFER return to ring-3 and invoke the owner callback there again. + * + * @param pVM The cross-context VM structure pointer. + * @param idCpu ID of the vCPU triggering the breakpoint. + * @param pvUserBp User argument of the set breakpoint. + * @param hBp The breakpoint handle. + * @param pBpPub Pointer to the readonly public state of the breakpoint. + * @param fFlags Flags indicating when the handler was called (DBGF_BP_F_HIT_EXEC_BEFORE vs DBGF_BP_F_HIT_EXEC_AFTER). + * + * @remarks The handler is called on the EMT of vCPU triggering the breakpoint and no locks are held. + * @remarks Any status code returned other than the ones mentioned will send the VM straight into a + * guru meditation. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNDBGFBPHIT,(PVM pVM, VMCPUID idCpu, void *pvUserBp, DBGFBP hBp, PCDBGFBPPUB pBpPub, + uint16_t fFlags)); +/** Pointer to a FNDBGFBPHIT(). */ +typedef FNDBGFBPHIT *PFNDBGFBPHIT; + + +/** + * I/O breakpoint hit handler. + * + * @returns Strict VBox status code. + * @retval VINF_SUCCESS if the breakpoint was handled and guest execution can resume. + * @retval VINF_DBGF_BP_HALT if guest execution should be stopped and the debugger should be invoked. + * @retval VINF_DBGF_R3_BP_OWNER_DEFER return to ring-3 and invoke the owner callback there again. + * + * @param pVM The cross-context VM structure pointer. + * @param idCpu ID of the vCPU triggering the breakpoint. + * @param pvUserBp User argument of the set breakpoint. + * @param hBp The breakpoint handle. + * @param pBpPub Pointer to the readonly public state of the breakpoint. + * @param fFlags Flags indicating when the handler was called (DBGF_BP_F_HIT_EXEC_BEFORE vs DBGF_BP_F_HIT_EXEC_AFTER). + * @param fAccess Access flags, see DBGFBPIOACCESS_XXX. + * @param uAddr The address of the access, for port I/O this will hold the port number. + * @param uValue The value read or written (the value for reads is only valid when DBGF_BP_F_HIT_EXEC_AFTER is set). + * + * @remarks The handler is called on the EMT of vCPU triggering the breakpoint and no locks are held. + * @remarks Any status code returned other than the ones mentioned will send the VM straight into a + * guru meditation. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNDBGFBPIOHIT,(PVM pVM, VMCPUID idCpu, void *pvUserBp, DBGFBP hBp, PCDBGFBPPUB pBpPub, + uint16_t fFlags, uint32_t fAccess, uint64_t uAddr, uint64_t uValue)); +/** Pointer to a FNDBGFBPIOHIT(). */ +typedef FNDBGFBPIOHIT *PFNDBGFBPIOHIT; + + +#ifdef IN_RING3 +/** @defgroup grp_dbgf_bp_r3 The DBGF Breakpoint Host Context Ring-3 API + * @{ */ +VMMR3DECL(int) DBGFR3BpOwnerCreate(PUVM pUVM, PFNDBGFBPHIT pfnBpHit, PFNDBGFBPIOHIT pfnBpIoHit, PDBGFBPOWNER phBpOwner); +VMMR3DECL(int) DBGFR3BpOwnerDestroy(PUVM pUVM, DBGFBPOWNER hBpOwner); + +VMMR3DECL(int) DBGFR3BpSetInt3(PUVM pUVM, VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, + uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetInt3Ex(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, + VMCPUID idSrcCpu, PCDBGFADDRESS pAddress, uint16_t fFlags, + uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetReg(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, + uint64_t iHitDisable, uint8_t fType, uint8_t cb, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetRegEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, + PCDBGFADDRESS pAddress, uint16_t fFlags, + uint64_t iHitTrigger, uint64_t iHitDisable, + uint8_t fType, uint8_t cb, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetREM(PUVM pUVM, PCDBGFADDRESS pAddress, uint64_t iHitTrigger, + uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetPortIo(PUVM pUVM, RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess, + uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetPortIoEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, + RTIOPORT uPort, RTIOPORT cPorts, uint32_t fAccess, + uint32_t fFlags, uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetMmio(PUVM pUVM, RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess, + uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpSetMmioEx(PUVM pUVM, DBGFBPOWNER hOwner, void *pvUser, + RTGCPHYS GCPhys, uint32_t cb, uint32_t fAccess, + uint32_t fFlags, uint64_t iHitTrigger, uint64_t iHitDisable, PDBGFBP phBp); +VMMR3DECL(int) DBGFR3BpClear(PUVM pUVM, DBGFBP hBp); +VMMR3DECL(int) DBGFR3BpEnable(PUVM pUVM, DBGFBP hBp); +VMMR3DECL(int) DBGFR3BpDisable(PUVM pUVM, DBGFBP hBp); + +/** + * Breakpoint enumeration callback function. + * + * @returns VBox status code. + * The enumeration stops on failure status and VINF_CALLBACK_RETURN. + * @param pUVM The user mode VM handle. + * @param pvUser The user argument. + * @param hBp The breakpoint handle. + * @param pBpPub Pointer to the public breakpoint information. (readonly) + */ +typedef DECLCALLBACKTYPE(int, FNDBGFBPENUM,(PUVM pUVM, void *pvUser, DBGFBP hBp, PCDBGFBPPUB pBpPub)); +/** Pointer to a breakpoint enumeration callback function. */ +typedef FNDBGFBPENUM *PFNDBGFBPENUM; + +VMMR3DECL(int) DBGFR3BpEnum(PUVM pUVM, PFNDBGFBPENUM pfnCallback, void *pvUser); + +VMMR3_INT_DECL(int) DBGFR3BpHit(PVM pVM, PVMCPU pVCpu); +/** @} */ +#endif /* !IN_RING3 */ + + +#if defined(IN_RING0) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_dbgf_bp_r0 The DBGF Breakpoint Host Context Ring-0 API + * @{ */ +VMMR0_INT_DECL(int) DBGFR0BpOwnerSetUpContext(PGVM pGVM, DBGFBPOWNER hBpOwner, PFNDBGFBPHIT pfnBpHit, PFNDBGFBPIOHIT pfnBpIoHit); +VMMR0_INT_DECL(int) DBGFR0BpOwnerDestroyContext(PGVM pGVM, DBGFBPOWNER hBpOwner); + +VMMR0_INT_DECL(int) DBGFR0BpSetUpContext(PGVM pGVM, DBGFBP hBp, void *pvUser); +VMMR0_INT_DECL(int) DBGFR0BpDestroyContext(PGVM pGVM, DBGFBP hBp); +/** @} */ +#endif /* IN_RING0 || DOXYGEN_RUNNING */ + +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR7(PVM pVM); +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR0(PVM pVM); +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR1(PVM pVM); +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR2(PVM pVM); +VMM_INT_DECL(RTGCUINTREG) DBGFBpGetDR3(PVM pVM); +VMM_INT_DECL(bool) DBGFBpIsHwArmed(PVM pVM); +VMM_INT_DECL(bool) DBGFBpIsHwIoArmed(PVM pVM); +VMM_INT_DECL(bool) DBGFBpIsInt3Armed(PVM pVM); +VMM_INT_DECL(bool) DBGFIsStepping(PVMCPU pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) DBGFBpCheckInstruction(PVMCC pVM, PVMCPUCC pVCpu, RTGCPTR GCPtrPC); +VMM_INT_DECL(VBOXSTRICTRC) DBGFBpCheckIo(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTIOPORT uIoPort, uint8_t cbValue); +VMM_INT_DECL(uint32_t) DBGFBpCheckIo2(PVMCC pVM, PVMCPUCC pVCpu, RTIOPORT uIoPort, uint8_t cbValue); +VMM_INT_DECL(VBOXSTRICTRC) DBGFBpCheckPortIo(PVMCC pVM, PVMCPU pVCpu, RTIOPORT uIoPort, + uint32_t fAccess, uint32_t uValue, bool fBefore); +VMM_INT_DECL(VBOXSTRICTRC) DBGFEventGenericWithArgs(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmEvent, DBGFEVENTCTX enmCtx, + unsigned cArgs, ...); +VMM_INT_DECL(int) DBGFTrap01Handler(PVM pVM, PVMCPU pVCpu, PCPUMCTX pCtx, RTGCUINTREG uDr6, bool fAltStepping); +VMM_INT_DECL(VBOXSTRICTRC) DBGFTrap03Handler(PVMCC pVM, PVMCPUCC pVCpu, PCPUMCTX pCtx); + + +#ifdef IN_RING3 /* The CPU mode API only works in ring-3. */ +VMMR3DECL(CPUMMODE) DBGFR3CpuGetMode(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(VMCPUID) DBGFR3CpuGetCount(PUVM pUVM); +VMMR3DECL(bool) DBGFR3CpuIsIn64BitCode(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(bool) DBGFR3CpuIsInV86Code(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(const char *) DBGFR3CpuGetState(PUVM pUVM, VMCPUID idCpu); +#endif + + + +#ifdef IN_RING3 /* The info callbacks API only works in ring-3. */ + +struct RTGETOPTSTATE; +union RTGETOPTUNION; + +/** + * Info helper callback structure. + */ +typedef struct DBGFINFOHLP +{ + /** + * Print formatted string. + * + * @param pHlp Pointer to this structure. + * @param pszFormat The format string. + * @param ... Arguments. + */ + DECLCALLBACKMEMBER(void, pfnPrintf,(PCDBGFINFOHLP pHlp, const char *pszFormat, ...)) RT_IPRT_FORMAT_ATTR(2, 3); + + /** + * Print formatted string. + * + * @param pHlp Pointer to this structure. + * @param pszFormat The format string. + * @param args Argument list. + */ + DECLCALLBACKMEMBER(void, pfnPrintfV,(PCDBGFINFOHLP pHlp, const char *pszFormat, va_list args)) RT_IPRT_FORMAT_ATTR(2, 0); + + /** + * Report getopt parsing trouble + * + * @param pHlp Pointer to this structure. + * @param rc The RTGetOpt return value. + * @param pValueUnion The value union. + * @param pState The getopt state. + */ + DECLCALLBACKMEMBER(void, pfnGetOptError,(PCDBGFINFOHLP pHlp, int rc, union RTGETOPTUNION *pValueUnion, + struct RTGETOPTSTATE *pState)); +} DBGFINFOHLP; + + +/** + * Info handler, device version. + * + * @param pDevIns The device instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFHANDLERDEV,(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, const char *pszArgs)); +/** Pointer to a FNDBGFHANDLERDEV function. */ +typedef FNDBGFHANDLERDEV *PFNDBGFHANDLERDEV; + +/** + * Info handler, driver version. + * + * @param pDrvIns The driver instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFHANDLERDRV,(PPDMDRVINS pDrvIns, PCDBGFINFOHLP pHlp, const char *pszArgs)); +/** Pointer to a FNDBGFHANDLERDRV function. */ +typedef FNDBGFHANDLERDRV *PFNDBGFHANDLERDRV; + +/** + * Info handler, internal version. + * + * @param pVM The cross context VM structure. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFHANDLERINT,(PVM pVM, PCDBGFINFOHLP pHlp, const char *pszArgs)); +/** Pointer to a FNDBGFHANDLERINT function. */ +typedef FNDBGFHANDLERINT *PFNDBGFHANDLERINT; + +/** + * Info handler, external version. + * + * @param pvUser User argument. + * @param pHlp Callback functions for doing output. + * @param pszArgs Argument string. Optional and specific to the handler. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFHANDLEREXT,(void *pvUser, PCDBGFINFOHLP pHlp, const char *pszArgs)); +/** Pointer to a FNDBGFHANDLEREXT function. */ +typedef FNDBGFHANDLEREXT *PFNDBGFHANDLEREXT; + +/** + * Info handler, device version with argv. + * + * @param pDevIns The device instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVDEV,(PPDMDEVINS pDevIns, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVDEV function. */ +typedef FNDBGFINFOARGVDEV *PFNDBGFINFOARGVDEV; + +/** + * Info handler, USB device version with argv. + * + * @param pUsbIns The USB device instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVUSB,(PPDMUSBINS pUsbIns, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVUSB function. */ +typedef FNDBGFINFOARGVUSB *PFNDBGFINFOARGVUSB; + +/** + * Info handler, driver version with argv. + * + * @param pDrvIns The driver instance which registered the info. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVDRV,(PPDMDRVINS pDrvIns, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVDRV function. */ +typedef FNDBGFINFOARGVDRV *PFNDBGFINFOARGVDRV; + +/** + * Info handler, internal version with argv. + * + * @param pVM The cross context VM structure. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVINT,(PVM pVM, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVINT function. */ +typedef FNDBGFINFOARGVINT *PFNDBGFINFOARGVINT; + +/** + * Info handler, external version with argv. + * + * @param pvUser User argument. + * @param pHlp Callback functions for doing output. + * @param cArgs Number of arguments. + * @param papszArgs Argument vector. + */ +typedef DECLCALLBACKTYPE(void, FNDBGFINFOARGVEXT,(void *pvUser, PCDBGFINFOHLP pHlp, int cArgs, char **papszArgs)); +/** Pointer to a FNDBGFINFOARGVEXT function. */ +typedef FNDBGFINFOARGVEXT *PFNDBGFINFOARGVEXT; + + +/** @name Flags for the info registration functions. + * @{ */ +/** The handler must run on the EMT. */ +#define DBGFINFO_FLAGS_RUN_ON_EMT RT_BIT(0) +/** Call on all EMTs when a specific isn't specified. */ +#define DBGFINFO_FLAGS_ALL_EMTS RT_BIT(1) +/** @} */ + +VMMR3_INT_DECL(int) DBGFR3InfoRegisterDevice(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDEV pfnHandler, PPDMDEVINS pDevIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterDriver(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler, PPDMDRVINS pDrvIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterInternal(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERINT pfnHandler); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterInternalEx(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLERINT pfnHandler, uint32_t fFlags); +VMMR3DECL(int) DBGFR3InfoRegisterExternal(PUVM pUVM, const char *pszName, const char *pszDesc, PFNDBGFHANDLEREXT pfnHandler, void *pvUser); + +VMMR3_INT_DECL(int) DBGFR3InfoRegisterDeviceArgv(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDEV pfnHandler, PPDMDEVINS pDevIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterDriverArgv(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDRV pfnHandler, PPDMDRVINS pDrvIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterUsbArgv(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVUSB pfnHandler, PPDMUSBINS pUsbIns); +VMMR3_INT_DECL(int) DBGFR3InfoRegisterInternalArgv(PVM pVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVINT pfnHandler, uint32_t fFlags); +VMMR3DECL(int) DBGFR3InfoRegisterExternalArgv(PUVM pUVM, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVEXT pfnHandler, void *pvUser); + +VMMR3_INT_DECL(int) DBGFR3InfoDeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName); +VMMR3_INT_DECL(int) DBGFR3InfoDeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName); +VMMR3_INT_DECL(int) DBGFR3InfoDeregisterUsb(PVM pVM, PPDMUSBINS pDrvIns, const char *pszName); +VMMR3_INT_DECL(int) DBGFR3InfoDeregisterInternal(PVM pVM, const char *pszName); +VMMR3DECL(int) DBGFR3InfoDeregisterExternal(PUVM pUVM, const char *pszName); + +VMMR3DECL(int) DBGFR3Info(PUVM pUVM, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp); +VMMR3DECL(int) DBGFR3InfoEx(PUVM pUVM, VMCPUID idCpu, const char *pszName, const char *pszArgs, PCDBGFINFOHLP pHlp); +VMMR3DECL(int) DBGFR3InfoLogRel(PUVM pUVM, const char *pszName, const char *pszArgs); +VMMR3DECL(int) DBGFR3InfoStdErr(PUVM pUVM, const char *pszName, const char *pszArgs); +VMMR3_INT_DECL(int) DBGFR3InfoMulti(PVM pVM, const char *pszIncludePat, const char *pszExcludePat, + const char *pszSepFmt, PCDBGFINFOHLP pHlp); + +/** @def DBGFR3_INFO_LOG + * Display a piece of info writing to the log if enabled. + * + * This is for execution on EMTs and will only show the items on the calling + * EMT. This is to avoid deadlocking against other CPUs if a rendezvous is + * initiated in parallel to this call. (Besides, nobody really wants or need + * info for the other EMTs when using this macro.) + * + * @param a_pVM The shared VM handle. + * @param a_pVCpu The cross context per CPU structure of the calling EMT. + * @param a_pszName The identifier of the info to display. + * @param a_pszArgs Arguments to the info handler. + */ +#ifdef LOG_ENABLED +# define DBGFR3_INFO_LOG(a_pVM, a_pVCpu, a_pszName, a_pszArgs) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3InfoEx((a_pVM)->pUVM, (a_pVCpu)->idCpu, a_pszName, a_pszArgs, NULL); \ + } while (0) +#else +# define DBGFR3_INFO_LOG(a_pVM, a_pVCpu, a_pszName, a_pszArgs) do { } while (0) +#endif + +/** @def DBGFR3_INFO_LOG_SAFE + * Display a piece of info (rendezvous safe) writing to the log if enabled. + * + * @param a_pVM The shared VM handle. + * @param a_pszName The identifier of the info to display. + * @param a_pszArgs Arguments to the info handler. + * + * @remarks Use DBGFR3_INFO_LOG where ever possible! + */ +#ifdef LOG_ENABLED +# define DBGFR3_INFO_LOG_SAFE(a_pVM, a_pszName, a_pszArgs) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3Info((a_pVM)->pUVM, a_pszName, a_pszArgs, NULL); \ + } while (0) +#else +# define DBGFR3_INFO_LOG_SAFE(a_pVM, a_pszName, a_pszArgs) do { } while (0) +#endif + +/** + * Enumeration callback for use with DBGFR3InfoEnum. + * + * @returns VBox status code. + * A status code indicating failure will end the enumeration + * and DBGFR3InfoEnum will return with that status code. + * @param pUVM The user mode VM handle. + * @param pszName Info identifier name. + * @param pszDesc The description. + * @param pvUser User parameter. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFINFOENUM,(PUVM pUVM, const char *pszName, const char *pszDesc, void *pvUser)); +/** Pointer to a FNDBGFINFOENUM function. */ +typedef FNDBGFINFOENUM *PFNDBGFINFOENUM; + +VMMR3DECL(int) DBGFR3InfoEnum(PUVM pUVM, PFNDBGFINFOENUM pfnCallback, void *pvUser); +VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogHlp(void); +VMMR3DECL(PCDBGFINFOHLP) DBGFR3InfoLogRelHlp(void); +VMMR3DECL(void) DBGFR3InfoGenericGetOptError(PCDBGFINFOHLP pHlp, int rc, union RTGETOPTUNION *pValueUnion, + struct RTGETOPTSTATE *pState); + +#endif /* IN_RING3 */ + + +#ifdef IN_RING3 /* The log contrl API only works in ring-3. */ +VMMR3DECL(int) DBGFR3LogModifyGroups(PUVM pUVM, const char *pszGroupSettings); +VMMR3DECL(int) DBGFR3LogModifyFlags(PUVM pUVM, const char *pszFlagSettings); +VMMR3DECL(int) DBGFR3LogModifyDestinations(PUVM pUVM, const char *pszDestSettings); +#endif /* IN_RING3 */ + +#ifdef IN_RING3 /* The debug information management APIs only works in ring-3. */ + +/** Max length (including '\\0') of a symbol name. */ +#define DBGF_SYMBOL_NAME_LENGTH 512 + +/** + * Debug symbol. + */ +typedef struct DBGFSYMBOL +{ + /** Symbol value (address). */ + RTGCUINTPTR Value; + /** Symbol size. */ + uint32_t cb; + /** Symbol Flags. (reserved). */ + uint32_t fFlags; + /** Symbol name. */ + char szName[DBGF_SYMBOL_NAME_LENGTH]; +} DBGFSYMBOL; +/** Pointer to debug symbol. */ +typedef DBGFSYMBOL *PDBGFSYMBOL; +/** Pointer to const debug symbol. */ +typedef const DBGFSYMBOL *PCDBGFSYMBOL; + +/** + * Debug line number information. + */ +typedef struct DBGFLINE +{ + /** Address. */ + RTGCUINTPTR Address; + /** Line number. */ + uint32_t uLineNo; + /** Filename. */ + char szFilename[260]; +} DBGFLINE; +/** Pointer to debug line number. */ +typedef DBGFLINE *PDBGFLINE; +/** Pointer to const debug line number. */ +typedef const DBGFLINE *PCDBGFLINE; + +/** @name Address spaces aliases. + * @{ */ +/** The guest global address space. */ +#define DBGF_AS_GLOBAL ((RTDBGAS)-1) +/** The guest kernel address space. + * This is usually resolves to the same as DBGF_AS_GLOBAL. */ +#define DBGF_AS_KERNEL ((RTDBGAS)-2) +/** The physical address space. */ +#define DBGF_AS_PHYS ((RTDBGAS)-3) +/** Raw-mode context. */ +#define DBGF_AS_RC ((RTDBGAS)-4) +/** Ring-0 context. */ +#define DBGF_AS_R0 ((RTDBGAS)-5) +/** Raw-mode context and then global guest context. + * When used for looking up information, it works as if the call was first made + * with DBGF_AS_RC and then on failure with DBGF_AS_GLOBAL. When called for + * making address space changes, it works as if DBGF_AS_RC was used. */ +#define DBGF_AS_RC_AND_GC_GLOBAL ((RTDBGAS)-6) + +/** The first special one. */ +#define DBGF_AS_FIRST DBGF_AS_RC_AND_GC_GLOBAL +/** The last special one. */ +#define DBGF_AS_LAST DBGF_AS_GLOBAL +#endif +/** The number of special address space handles. */ +#define DBGF_AS_COUNT (6U) +#ifdef IN_RING3 +/** Converts an alias handle to an array index. */ +#define DBGF_AS_ALIAS_2_INDEX(hAlias) \ + ( (uintptr_t)(hAlias) - (uintptr_t)DBGF_AS_FIRST ) +/** Predicat macro that check if the specified handle is an alias. */ +#define DBGF_AS_IS_ALIAS(hAlias) \ + ( DBGF_AS_ALIAS_2_INDEX(hAlias) < DBGF_AS_COUNT ) +/** Predicat macro that check if the specified alias is a fixed one or not. */ +#define DBGF_AS_IS_FIXED_ALIAS(hAlias) \ + ( DBGF_AS_ALIAS_2_INDEX(hAlias) < (uintptr_t)DBGF_AS_PHYS - (uintptr_t)DBGF_AS_FIRST + 1U ) + +/** @} */ + +VMMR3DECL(RTDBGCFG) DBGFR3AsGetConfig(PUVM pUVM); + +VMMR3DECL(int) DBGFR3AsAdd(PUVM pUVM, RTDBGAS hDbgAs, RTPROCESS ProcId); +VMMR3DECL(int) DBGFR3AsDelete(PUVM pUVM, RTDBGAS hDbgAs); +VMMR3DECL(int) DBGFR3AsSetAlias(PUVM pUVM, RTDBGAS hAlias, RTDBGAS hAliasFor); +VMMR3DECL(RTDBGAS) DBGFR3AsResolve(PUVM pUVM, RTDBGAS hAlias); +VMMR3DECL(RTDBGAS) DBGFR3AsResolveAndRetain(PUVM pUVM, RTDBGAS hAlias); +VMMR3DECL(RTDBGAS) DBGFR3AsQueryByName(PUVM pUVM, const char *pszName); +VMMR3DECL(RTDBGAS) DBGFR3AsQueryByPid(PUVM pUVM, RTPROCESS ProcId); + +VMMR3DECL(int) DBGFR3AsLoadImage(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, + RTLDRARCH enmArch, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags); +VMMR3DECL(int) DBGFR3AsLoadMap(PUVM pUVM, RTDBGAS hDbgAs, const char *pszFilename, const char *pszModName, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, RTGCUINTPTR uSubtrahend, uint32_t fFlags); +VMMR3DECL(int) DBGFR3AsLinkModule(PUVM pUVM, RTDBGAS hDbgAs, RTDBGMOD hMod, PCDBGFADDRESS pModAddress, RTDBGSEGIDX iModSeg, uint32_t fFlags); +VMMR3DECL(int) DBGFR3AsUnlinkModuleByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszModName); + +VMMR3DECL(int) DBGFR3AsSymbolByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t fFlags, + PRTGCINTPTR poffDisp, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod); +VMMR3DECL(PRTDBGSYMBOL) DBGFR3AsSymbolByAddrA(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, uint32_t Flags, + PRTGCINTPTR poffDisp, PRTDBGMOD phMod); +VMMR3DECL(int) DBGFR3AsSymbolByName(PUVM pUVM, RTDBGAS hDbgAs, const char *pszSymbol, PRTDBGSYMBOL pSymbol, PRTDBGMOD phMod); + +VMMR3DECL(int) DBGFR3AsLineByAddr(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, + PRTGCINTPTR poffDisp, PRTDBGLINE pLine, PRTDBGMOD phMod); +VMMR3DECL(PRTDBGLINE) DBGFR3AsLineByAddrA(PUVM pUVM, RTDBGAS hDbgAs, PCDBGFADDRESS pAddress, + PRTGCINTPTR poffDisp, PRTDBGMOD phMod); + +/** @name DBGFMOD_PE_F_XXX - flags for + * @{ */ +/** NT 3.1 images were a little different, so make allowances for that. */ +#define DBGFMODINMEM_F_PE_NT31 RT_BIT_32(0) +/** No container fallback. */ +#define DBGFMODINMEM_F_NO_CONTAINER_FALLBACK RT_BIT_32(1) +/** No in-memory reader fallback. */ +#define DBGFMODINMEM_F_NO_READER_FALLBACK RT_BIT_32(2) +/** Valid flags. */ +#define DBGFMODINMEM_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ +VMMR3DECL(int) DBGFR3ModInMem(PUVM pUVM, PCDBGFADDRESS pImageAddr, uint32_t fFlags, const char *pszName, + const char *pszFilename, RTLDRARCH enmArch, uint32_t cbImage, + PRTDBGMOD phDbgMod, PRTERRINFO pErrInfo); + +#endif /* IN_RING3 */ + +#ifdef IN_RING3 /* The stack API only works in ring-3. */ + +/** Pointer to stack frame info. */ +typedef struct DBGFSTACKFRAME *PDBGFSTACKFRAME; +/** Pointer to const stack frame info. */ +typedef struct DBGFSTACKFRAME const *PCDBGFSTACKFRAME; +/** + * Info about a stack frame. + */ +typedef struct DBGFSTACKFRAME +{ + /** Frame number. */ + uint32_t iFrame; + /** Frame flags (DBGFSTACKFRAME_FLAGS_XXX). */ + uint32_t fFlags; + /** The stack address of the frame. + * The off member is [e|r]sp and the Sel member is ss. */ + DBGFADDRESS AddrStack; + /** The program counter (PC) address of the frame. + * The off member is [e|r]ip and the Sel member is cs. */ + DBGFADDRESS AddrPC; + /** Pointer to the symbol nearest the program counter (PC). NULL if not found. */ + PRTDBGSYMBOL pSymPC; + /** Pointer to the linenumber nearest the program counter (PC). NULL if not found. */ + PRTDBGLINE pLinePC; + /** The frame address. + * The off member is [e|r]bp and the Sel member is ss. */ + DBGFADDRESS AddrFrame; + /** The way this frame returns to the next one. */ + RTDBGRETURNTYPE enmReturnType; + + /** The way the next frame returns. + * Only valid when DBGFSTACKFRAME_FLAGS_UNWIND_INFO_RET is set. */ + RTDBGRETURNTYPE enmReturnFrameReturnType; + /** The return frame address. + * The off member is [e|r]bp and the Sel member is ss. */ + DBGFADDRESS AddrReturnFrame; + /** The return stack address. + * The off member is [e|r]sp and the Sel member is ss. */ + DBGFADDRESS AddrReturnStack; + + /** The program counter (PC) address which the frame returns to. + * The off member is [e|r]ip and the Sel member is cs. */ + DBGFADDRESS AddrReturnPC; + /** Pointer to the symbol nearest the return PC. NULL if not found. */ + PRTDBGSYMBOL pSymReturnPC; + /** Pointer to the linenumber nearest the return PC. NULL if not found. */ + PRTDBGLINE pLineReturnPC; + + /** 32-bytes of stack arguments. */ + union + { + /** 64-bit view */ + uint64_t au64[4]; + /** 32-bit view */ + uint32_t au32[8]; + /** 16-bit view */ + uint16_t au16[16]; + /** 8-bit view */ + uint8_t au8[32]; + } Args; + + /** Number of registers values we can be sure about. + * @note This is generally zero in the first frame. */ + uint32_t cSureRegs; + /** Registers we can be sure about (length given by cSureRegs). */ + struct DBGFREGVALEX *paSureRegs; + + /** Pointer to the next frame. + * Might not be used in some cases, so consider it internal. */ + PCDBGFSTACKFRAME pNextInternal; + /** Pointer to the first frame. + * Might not be used in some cases, so consider it internal. */ + PCDBGFSTACKFRAME pFirstInternal; +} DBGFSTACKFRAME; + +/** @name DBGFSTACKFRAME_FLAGS_XXX - DBGFSTACKFRAME Flags. + * @{ */ +/** This is the last stack frame we can read. + * This flag is not set if the walk stop because of max dept or recursion. */ +# define DBGFSTACKFRAME_FLAGS_LAST RT_BIT(1) +/** This is the last record because we detected a loop. */ +# define DBGFSTACKFRAME_FLAGS_LOOP RT_BIT(2) +/** This is the last record because we reached the maximum depth. */ +# define DBGFSTACKFRAME_FLAGS_MAX_DEPTH RT_BIT(3) +/** 16-bit frame. */ +# define DBGFSTACKFRAME_FLAGS_16BIT RT_BIT(4) +/** 32-bit frame. */ +# define DBGFSTACKFRAME_FLAGS_32BIT RT_BIT(5) +/** 64-bit frame. */ +# define DBGFSTACKFRAME_FLAGS_64BIT RT_BIT(6) +/** Real mode or V86 frame. */ +# define DBGFSTACKFRAME_FLAGS_REAL_V86 RT_BIT(7) +/** Is a trap frame (NT term). */ +# define DBGFSTACKFRAME_FLAGS_TRAP_FRAME RT_BIT(8) + +/** Used Odd/even heuristics for far/near return. */ +# define DBGFSTACKFRAME_FLAGS_USED_ODD_EVEN RT_BIT(29) +/** Set if we used unwind info to construct the frame. (Kind of internal.) */ +# define DBGFSTACKFRAME_FLAGS_USED_UNWIND_INFO RT_BIT(30) +/** Internal: Unwind info used for the return frame. */ +# define DBGFSTACKFRAME_FLAGS_UNWIND_INFO_RET RT_BIT(31) +/** @} */ + +/** @name DBGFCODETYPE + * @{ */ +typedef enum DBGFCODETYPE +{ + /** The usual invalid 0 value. */ + DBGFCODETYPE_INVALID = 0, + /** Stack walk for guest code. */ + DBGFCODETYPE_GUEST, + /** Stack walk for hypervisor code. */ + DBGFCODETYPE_HYPER, + /** Stack walk for ring 0 code. */ + DBGFCODETYPE_RING0, + /** The usual 32-bit blowup. */ + DBGFCODETYPE_32BIT_HACK = 0x7fffffff +} DBGFCODETYPE; +/** @} */ + +VMMR3DECL(int) DBGFR3StackWalkBegin(PUVM pUVM, VMCPUID idCpu, DBGFCODETYPE enmCodeType, + PCDBGFSTACKFRAME *ppFirstFrame); +VMMR3DECL(int) DBGFR3StackWalkBeginEx(PUVM pUVM, VMCPUID idCpu, DBGFCODETYPE enmCodeType, PCDBGFADDRESS pAddrFrame, + PCDBGFADDRESS pAddrStack,PCDBGFADDRESS pAddrPC, + RTDBGRETURNTYPE enmReturnType, PCDBGFSTACKFRAME *ppFirstFrame); +VMMR3DECL(PCDBGFSTACKFRAME) DBGFR3StackWalkNext(PCDBGFSTACKFRAME pCurrent); +VMMR3DECL(void) DBGFR3StackWalkEnd(PCDBGFSTACKFRAME pFirstFrame); + +#endif /* IN_RING3 */ + + +#ifdef IN_RING3 /* The disassembly API only works in ring-3. */ + +/** @name Flags to pass to DBGFR3DisasInstrEx(). + * @{ */ +/** Disassemble the current guest instruction, with annotations. */ +#define DBGF_DISAS_FLAGS_CURRENT_GUEST RT_BIT(0) +/** No annotations for current context. */ +#define DBGF_DISAS_FLAGS_NO_ANNOTATION RT_BIT(2) +/** No symbol lookup. */ +#define DBGF_DISAS_FLAGS_NO_SYMBOLS RT_BIT(3) +/** No instruction bytes. */ +#define DBGF_DISAS_FLAGS_NO_BYTES RT_BIT(4) +/** No address in the output. */ +#define DBGF_DISAS_FLAGS_NO_ADDRESS RT_BIT(5) +/** Disassemble original unpatched bytes (PATM). */ +#define DBGF_DISAS_FLAGS_UNPATCHED_BYTES RT_BIT(7) +/** Annotate patched instructions. */ +#define DBGF_DISAS_FLAGS_ANNOTATE_PATCHED RT_BIT(8) +/** Disassemble in the default mode of the specific context. */ +#define DBGF_DISAS_FLAGS_DEFAULT_MODE UINT32_C(0x00000000) +/** Disassemble in 16-bit mode. */ +#define DBGF_DISAS_FLAGS_16BIT_MODE UINT32_C(0x10000000) +/** Disassemble in 16-bit mode with real mode address translation. */ +#define DBGF_DISAS_FLAGS_16BIT_REAL_MODE UINT32_C(0x20000000) +/** Disassemble in 32-bit mode. */ +#define DBGF_DISAS_FLAGS_32BIT_MODE UINT32_C(0x30000000) +/** Disassemble in 64-bit mode. */ +#define DBGF_DISAS_FLAGS_64BIT_MODE UINT32_C(0x40000000) +/** The disassembly mode mask. */ +#define DBGF_DISAS_FLAGS_MODE_MASK UINT32_C(0x70000000) +/** Mask containing the valid flags. */ +#define DBGF_DISAS_FLAGS_VALID_MASK UINT32_C(0x700001ff) +/** @} */ + +/** Special flat selector. */ +#define DBGF_SEL_FLAT 1 + +VMMR3DECL(int) DBGFR3DisasInstrEx(PUVM pUVM, VMCPUID idCpu, RTSEL Sel, RTGCPTR GCPtr, uint32_t fFlags, + char *pszOutput, uint32_t cbOutput, uint32_t *pcbInstr); +VMMR3_INT_DECL(int) DBGFR3DisasInstrCurrent(PVMCPU pVCpu, char *pszOutput, uint32_t cbOutput); +VMMR3DECL(int) DBGFR3DisasInstrCurrentLogInternal(PVMCPU pVCpu, const char *pszPrefix); + +/** @def DBGFR3_DISAS_INSTR_CUR_LOG + * Disassembles the current guest context instruction and writes it to the log. + * All registers and data will be displayed. Addresses will be attempted resolved to symbols. + */ +#ifdef LOG_ENABLED +# define DBGFR3_DISAS_INSTR_CUR_LOG(pVCpu, pszPrefix) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3DisasInstrCurrentLogInternal(pVCpu, pszPrefix); \ + } while (0) +#else +# define DBGFR3_DISAS_INSTR_CUR_LOG(pVCpu, pszPrefix) do { } while (0) +#endif + +VMMR3DECL(int) DBGFR3DisasInstrLogInternal(PVMCPU pVCpu, RTSEL Sel, RTGCPTR GCPtr, const char *pszPrefix); + +/** @def DBGFR3_DISAS_INSTR_LOG + * Disassembles the specified guest context instruction and writes it to the log. + * Addresses will be attempted resolved to symbols. + * @thread Any EMT. + */ +# ifdef LOG_ENABLED +# define DBGFR3_DISAS_INSTR_LOG(pVCpu, Sel, GCPtr, pszPrefix) \ + do { \ + if (LogIsEnabled()) \ + DBGFR3DisasInstrLogInternal(pVCpu, Sel, GCPtr, pszPrefix); \ + } while (0) +# else +# define DBGFR3_DISAS_INSTR_LOG(pVCpu, Sel, GCPtr, pszPrefix) do { } while (0) +# endif +#endif + + +#ifdef IN_RING3 +VMMR3DECL(int) DBGFR3MemScan(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, RTGCUINTPTR cbRange, RTGCUINTPTR uAlign, + const void *pvNeedle, size_t cbNeedle, PDBGFADDRESS pHitAddress); +VMMR3DECL(int) DBGFR3MemRead(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void *pvBuf, size_t cbRead); +VMMR3DECL(int) DBGFR3MemReadString(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, char *pszBuf, size_t cbBuf); +VMMR3DECL(int) DBGFR3MemWrite(PUVM pUVM, VMCPUID idCpu, PCDBGFADDRESS pAddress, void const *pvBuf, size_t cbRead); +#endif + + +/** @name Flags for DBGFR3PagingDumpEx, PGMR3DumpHierarchyHCEx and + * PGMR3DumpHierarchyGCEx + * @{ */ +/** The CR3 from the current CPU state. */ +#define DBGFPGDMP_FLAGS_CURRENT_CR3 RT_BIT_32(0) +/** The current CPU paging mode (PSE, PAE, LM, EPT, NX). */ +#define DBGFPGDMP_FLAGS_CURRENT_MODE RT_BIT_32(1) +/** Whether PSE is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). + * Same value as X86_CR4_PSE. */ +#define DBGFPGDMP_FLAGS_PSE RT_BIT_32(4) /* */ +/** Whether PAE is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). + * Same value as X86_CR4_PAE. */ +#define DBGFPGDMP_FLAGS_PAE RT_BIT_32(5) /* */ +/** Whether LME is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). + * Same value as MSR_K6_EFER_LME. */ +#define DBGFPGDMP_FLAGS_LME RT_BIT_32(8) +/** Whether nested paging is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). */ +#define DBGFPGDMP_FLAGS_NP RT_BIT_32(9) +/** Whether extended nested page tables are enabled + * (!DBGFPGDMP_FLAGS_CURRENT_STATE). */ +#define DBGFPGDMP_FLAGS_EPT RT_BIT_32(10) +/** Whether no-execution is enabled (!DBGFPGDMP_FLAGS_CURRENT_STATE). + * Same value as MSR_K6_EFER_NXE. */ +#define DBGFPGDMP_FLAGS_NXE RT_BIT_32(11) +/** Whether to print the CR3. */ +#define DBGFPGDMP_FLAGS_PRINT_CR3 RT_BIT_32(27) +/** Whether to print the header. */ +#define DBGFPGDMP_FLAGS_HEADER RT_BIT_32(28) +/** Whether to dump additional page information. */ +#define DBGFPGDMP_FLAGS_PAGE_INFO RT_BIT_32(29) +/** Dump the shadow tables if set. + * Cannot be used together with DBGFPGDMP_FLAGS_GUEST. */ +#define DBGFPGDMP_FLAGS_SHADOW RT_BIT_32(30) +/** Dump the guest tables if set. + * Cannot be used together with DBGFPGDMP_FLAGS_SHADOW. */ +#define DBGFPGDMP_FLAGS_GUEST RT_BIT_32(31) +/** Mask of valid bits. */ +#define DBGFPGDMP_FLAGS_VALID_MASK UINT32_C(0xf8000f33) +/** The mask of bits controlling the paging mode. */ +#define DBGFPGDMP_FLAGS_MODE_MASK UINT32_C(0x00000f32) +/** @} */ +VMMDECL(int) DBGFR3PagingDumpEx(PUVM pUVM, VMCPUID idCpu, uint32_t fFlags, uint64_t cr3, uint64_t u64FirstAddr, + uint64_t u64LastAddr, uint32_t cMaxDepth, PCDBGFINFOHLP pHlp); + + +/** @name DBGFR3SelQueryInfo flags. + * @{ */ +/** Get the info from the guest descriptor table. + * @note This is more or less a given now when raw-mode was kicked out. */ +#define DBGFSELQI_FLAGS_DT_GUEST UINT32_C(0) +/** If currently executing in in 64-bit mode, blow up data selectors. */ +#define DBGFSELQI_FLAGS_DT_ADJ_64BIT_MODE UINT32_C(2) +/** @} */ +VMMR3DECL(int) DBGFR3SelQueryInfo(PUVM pUVM, VMCPUID idCpu, RTSEL Sel, uint32_t fFlags, PDBGFSELINFO pSelInfo); + + +/** + * Register identifiers. + */ +typedef enum DBGFREG +{ + /* General purpose registers: */ + DBGFREG_AL = 0, + DBGFREG_AX = DBGFREG_AL, + DBGFREG_EAX = DBGFREG_AL, + DBGFREG_RAX = DBGFREG_AL, + + DBGFREG_CL, + DBGFREG_CX = DBGFREG_CL, + DBGFREG_ECX = DBGFREG_CL, + DBGFREG_RCX = DBGFREG_CL, + + DBGFREG_DL, + DBGFREG_DX = DBGFREG_DL, + DBGFREG_EDX = DBGFREG_DL, + DBGFREG_RDX = DBGFREG_DL, + + DBGFREG_BL, + DBGFREG_BX = DBGFREG_BL, + DBGFREG_EBX = DBGFREG_BL, + DBGFREG_RBX = DBGFREG_BL, + + DBGFREG_SPL, + DBGFREG_SP = DBGFREG_SPL, + DBGFREG_ESP = DBGFREG_SPL, + DBGFREG_RSP = DBGFREG_SPL, + + DBGFREG_BPL, + DBGFREG_BP = DBGFREG_BPL, + DBGFREG_EBP = DBGFREG_BPL, + DBGFREG_RBP = DBGFREG_BPL, + + DBGFREG_SIL, + DBGFREG_SI = DBGFREG_SIL, + DBGFREG_ESI = DBGFREG_SIL, + DBGFREG_RSI = DBGFREG_SIL, + + DBGFREG_DIL, + DBGFREG_DI = DBGFREG_DIL, + DBGFREG_EDI = DBGFREG_DIL, + DBGFREG_RDI = DBGFREG_DIL, + + DBGFREG_R8, + DBGFREG_R8B = DBGFREG_R8, + DBGFREG_R8W = DBGFREG_R8, + DBGFREG_R8D = DBGFREG_R8, + + DBGFREG_R9, + DBGFREG_R9B = DBGFREG_R9, + DBGFREG_R9W = DBGFREG_R9, + DBGFREG_R9D = DBGFREG_R9, + + DBGFREG_R10, + DBGFREG_R10B = DBGFREG_R10, + DBGFREG_R10W = DBGFREG_R10, + DBGFREG_R10D = DBGFREG_R10, + + DBGFREG_R11, + DBGFREG_R11B = DBGFREG_R11, + DBGFREG_R11W = DBGFREG_R11, + DBGFREG_R11D = DBGFREG_R11, + + DBGFREG_R12, + DBGFREG_R12B = DBGFREG_R12, + DBGFREG_R12W = DBGFREG_R12, + DBGFREG_R12D = DBGFREG_R12, + + DBGFREG_R13, + DBGFREG_R13B = DBGFREG_R13, + DBGFREG_R13W = DBGFREG_R13, + DBGFREG_R13D = DBGFREG_R13, + + DBGFREG_R14, + DBGFREG_R14B = DBGFREG_R14, + DBGFREG_R14W = DBGFREG_R14, + DBGFREG_R14D = DBGFREG_R14, + + DBGFREG_R15, + DBGFREG_R15B = DBGFREG_R15, + DBGFREG_R15W = DBGFREG_R15, + DBGFREG_R15D = DBGFREG_R15, + + /* Segments and other special registers: */ + DBGFREG_CS, + DBGFREG_CS_ATTR, + DBGFREG_CS_BASE, + DBGFREG_CS_LIMIT, + + DBGFREG_DS, + DBGFREG_DS_ATTR, + DBGFREG_DS_BASE, + DBGFREG_DS_LIMIT, + + DBGFREG_ES, + DBGFREG_ES_ATTR, + DBGFREG_ES_BASE, + DBGFREG_ES_LIMIT, + + DBGFREG_FS, + DBGFREG_FS_ATTR, + DBGFREG_FS_BASE, + DBGFREG_FS_LIMIT, + + DBGFREG_GS, + DBGFREG_GS_ATTR, + DBGFREG_GS_BASE, + DBGFREG_GS_LIMIT, + + DBGFREG_SS, + DBGFREG_SS_ATTR, + DBGFREG_SS_BASE, + DBGFREG_SS_LIMIT, + + DBGFREG_IP, + DBGFREG_EIP = DBGFREG_IP, + DBGFREG_RIP = DBGFREG_IP, + + DBGFREG_FLAGS, + DBGFREG_EFLAGS = DBGFREG_FLAGS, + DBGFREG_RFLAGS = DBGFREG_FLAGS, + + /* FPU: */ + DBGFREG_FCW, + DBGFREG_FSW, + DBGFREG_FTW, + DBGFREG_FOP, + DBGFREG_FPUIP, + DBGFREG_FPUCS, + DBGFREG_FPUDP, + DBGFREG_FPUDS, + DBGFREG_MXCSR, + DBGFREG_MXCSR_MASK, + + DBGFREG_ST0, + DBGFREG_ST1, + DBGFREG_ST2, + DBGFREG_ST3, + DBGFREG_ST4, + DBGFREG_ST5, + DBGFREG_ST6, + DBGFREG_ST7, + + DBGFREG_MM0, + DBGFREG_MM1, + DBGFREG_MM2, + DBGFREG_MM3, + DBGFREG_MM4, + DBGFREG_MM5, + DBGFREG_MM6, + DBGFREG_MM7, + + /* SSE: */ + DBGFREG_XMM0, + DBGFREG_XMM1, + DBGFREG_XMM2, + DBGFREG_XMM3, + DBGFREG_XMM4, + DBGFREG_XMM5, + DBGFREG_XMM6, + DBGFREG_XMM7, + DBGFREG_XMM8, + DBGFREG_XMM9, + DBGFREG_XMM10, + DBGFREG_XMM11, + DBGFREG_XMM12, + DBGFREG_XMM13, + DBGFREG_XMM14, + DBGFREG_XMM15, + /** @todo add XMM aliases. */ + + /* AVX: */ + DBGFREG_YMM0, + DBGFREG_YMM1, + DBGFREG_YMM2, + DBGFREG_YMM3, + DBGFREG_YMM4, + DBGFREG_YMM5, + DBGFREG_YMM6, + DBGFREG_YMM7, + DBGFREG_YMM8, + DBGFREG_YMM9, + DBGFREG_YMM10, + DBGFREG_YMM11, + DBGFREG_YMM12, + DBGFREG_YMM13, + DBGFREG_YMM14, + DBGFREG_YMM15, + + /* System registers: */ + DBGFREG_GDTR_BASE, + DBGFREG_GDTR_LIMIT, + DBGFREG_IDTR_BASE, + DBGFREG_IDTR_LIMIT, + DBGFREG_LDTR, + DBGFREG_LDTR_ATTR, + DBGFREG_LDTR_BASE, + DBGFREG_LDTR_LIMIT, + DBGFREG_TR, + DBGFREG_TR_ATTR, + DBGFREG_TR_BASE, + DBGFREG_TR_LIMIT, + + DBGFREG_CR0, + DBGFREG_CR2, + DBGFREG_CR3, + DBGFREG_CR4, + DBGFREG_CR8, + + DBGFREG_DR0, + DBGFREG_DR1, + DBGFREG_DR2, + DBGFREG_DR3, + DBGFREG_DR6, + DBGFREG_DR7, + + /* MSRs: */ + DBGFREG_MSR_IA32_APICBASE, + DBGFREG_MSR_IA32_CR_PAT, + DBGFREG_MSR_IA32_PERF_STATUS, + DBGFREG_MSR_IA32_SYSENTER_CS, + DBGFREG_MSR_IA32_SYSENTER_EIP, + DBGFREG_MSR_IA32_SYSENTER_ESP, + DBGFREG_MSR_IA32_TSC, + DBGFREG_MSR_K6_EFER, + DBGFREG_MSR_K6_STAR, + DBGFREG_MSR_K8_CSTAR, + DBGFREG_MSR_K8_FS_BASE, + DBGFREG_MSR_K8_GS_BASE, + DBGFREG_MSR_K8_KERNEL_GS_BASE, + DBGFREG_MSR_K8_LSTAR, + DBGFREG_MSR_K8_SF_MASK, + DBGFREG_MSR_K8_TSC_AUX, + + /** The number of registers to pass to DBGFR3RegQueryAll. */ + DBGFREG_ALL_COUNT, + + /* Misc aliases that doesn't need be part of the 'all' query: */ + DBGFREG_AH = DBGFREG_ALL_COUNT, + DBGFREG_CH, + DBGFREG_DH, + DBGFREG_BH, + DBGFREG_GDTR, + DBGFREG_IDTR, + + /** The end of the registers. */ + DBGFREG_END, + /** The usual 32-bit type hack. */ + DBGFREG_32BIT_HACK = 0x7fffffff +} DBGFREG; +/** Pointer to a register identifier. */ +typedef DBGFREG *PDBGFREG; +/** Pointer to a const register identifier. */ +typedef DBGFREG const *PCDBGFREG; + +/** + * Register value type. + */ +typedef enum DBGFREGVALTYPE +{ + DBGFREGVALTYPE_INVALID = 0, + /** Unsigned 8-bit register value. */ + DBGFREGVALTYPE_U8, + /** Unsigned 16-bit register value. */ + DBGFREGVALTYPE_U16, + /** Unsigned 32-bit register value. */ + DBGFREGVALTYPE_U32, + /** Unsigned 64-bit register value. */ + DBGFREGVALTYPE_U64, + /** Unsigned 128-bit register value. */ + DBGFREGVALTYPE_U128, + /** Unsigned 256-bit register value. */ + DBGFREGVALTYPE_U256, + /** Unsigned 512-bit register value. */ + DBGFREGVALTYPE_U512, + /** Long double register value. */ + DBGFREGVALTYPE_R80, + /** Descriptor table register value. */ + DBGFREGVALTYPE_DTR, + /** End of the valid register value types. */ + DBGFREGVALTYPE_END, + /** The usual 32-bit type hack. */ + DBGFREGVALTYPE_32BIT_HACK = 0x7fffffff +} DBGFREGVALTYPE; +/** Pointer to a register value type. */ +typedef DBGFREGVALTYPE *PDBGFREGVALTYPE; + +/** + * A generic register value type. + */ +typedef union DBGFREGVAL +{ + uint64_t au64[8]; /**< The 64-bit array view. First because of the initializer. */ + uint32_t au32[16]; /**< The 32-bit array view. */ + uint16_t au16[32]; /**< The 16-bit array view. */ + uint8_t au8[64]; /**< The 8-bit array view. */ + + uint8_t u8; /**< The 8-bit view. */ + uint16_t u16; /**< The 16-bit view. */ + uint32_t u32; /**< The 32-bit view. */ + uint64_t u64; /**< The 64-bit view. */ + RTUINT128U u128; /**< The 128-bit view. */ + RTUINT256U u256; /**< The 256-bit view. */ + RTUINT512U u512; /**< The 512-bit view. */ + RTFLOAT80U r80; /**< The 80-bit floating point view. */ + RTFLOAT80U2 r80Ex; /**< The 80-bit floating point view v2. */ + /** GDTR or LDTR (DBGFREGVALTYPE_DTR). */ + struct + { + /** The table address. */ + uint64_t u64Base; + /** The table limit (length minus 1). */ + uint32_t u32Limit; /**< @todo Limit should be uint16_t */ + } dtr; +} DBGFREGVAL; +/** Pointer to a generic register value type. */ +typedef DBGFREGVAL *PDBGFREGVAL; +/** Pointer to a const generic register value type. */ +typedef DBGFREGVAL const *PCDBGFREGVAL; + +/** Initialize a DBGFREGVAL variable to all zeros. */ +#define DBGFREGVAL_INITIALIZE_ZERO { { 0, 0, 0, 0, 0, 0, 0, 0 } } +/** Initialize a DBGFREGVAL variable to all bits set . */ +#define DBGFREGVAL_INITIALIZE_FFFF { { UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX, UINT64_MAX } } + +/** + * Extended register value, including register ID and type. + * + * This is currently only used by the stack walker. + */ +typedef struct DBGFREGVALEX +{ + /** The register value. */ + DBGFREGVAL Value; + /** The register value type. */ + DBGFREGVALTYPE enmType; + /** The register ID, DBGFREG_END if not applicable. */ + DBGFREG enmReg; + /** Pointer to read-only register name string if no register ID could be found. */ + const char *pszName; +} DBGFREGVALEX; +/** Pointer to an extended register value struct. */ +typedef DBGFREGVALEX *PDBGFREGVALEX; +/** Pointer to a const extended register value struct. */ +typedef DBGFREGVALEX const *PCDBGFREGVALEX; + + +VMMDECL(ssize_t) DBGFR3RegFormatValue(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType, bool fSpecial); +VMMDECL(ssize_t) DBGFR3RegFormatValueEx(char *pszBuf, size_t cbBuf, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType, + unsigned uBase, signed int cchWidth, signed int cchPrecision, uint32_t fFlags); + +/** + * Register sub-field descriptor. + */ +typedef struct DBGFREGSUBFIELD +{ + /** The name of the sub-field. NULL is used to terminate the array. */ + const char *pszName; + /** The index of the first bit. Ignored if pfnGet is set. */ + uint8_t iFirstBit; + /** The number of bits. Mandatory. */ + uint8_t cBits; + /** The shift count. Not applied when pfnGet is set, but used to + * calculate the minimum type. */ + int8_t cShift; + /** Sub-field flags, DBGFREGSUBFIELD_FLAGS_XXX. */ + uint8_t fFlags; + /** Getter (optional). + * @remarks Does not take the device lock or anything like that. + */ + DECLCALLBACKMEMBER(int, pfnGet,(void *pvUser, struct DBGFREGSUBFIELD const *pSubField, PRTUINT128U puValue)); + /** Setter (optional). + * @remarks Does not take the device lock or anything like that. + */ + DECLCALLBACKMEMBER(int, pfnSet,(void *pvUser, struct DBGFREGSUBFIELD const *pSubField, RTUINT128U uValue, RTUINT128U fMask)); +} DBGFREGSUBFIELD; +/** Pointer to a const register sub-field descriptor. */ +typedef DBGFREGSUBFIELD const *PCDBGFREGSUBFIELD; + +/** @name DBGFREGSUBFIELD_FLAGS_XXX + * @{ */ +/** The sub-field is read-only. */ +#define DBGFREGSUBFIELD_FLAGS_READ_ONLY UINT8_C(0x01) +/** @} */ + +/** Macro for creating a read-write sub-field entry without getters. */ +#define DBGFREGSUBFIELD_RW(a_szName, a_iFirstBit, a_cBits, a_cShift) \ + { a_szName, a_iFirstBit, a_cBits, a_cShift, 0 /*fFlags*/, NULL /*pfnGet*/, NULL /*pfnSet*/ } +/** Macro for creating a read-write sub-field entry with getters. */ +#define DBGFREGSUBFIELD_RW_SG(a_szName, a_cBits, a_cShift, a_pfnGet, a_pfnSet) \ + { a_szName, 0 /*iFirstBit*/, a_cBits, a_cShift, 0 /*fFlags*/, a_pfnGet, a_pfnSet } +/** Macro for creating a read-only sub-field entry without getters. */ +#define DBGFREGSUBFIELD_RO(a_szName, a_iFirstBit, a_cBits, a_cShift) \ + { a_szName, a_iFirstBit, a_cBits, a_cShift, DBGFREGSUBFIELD_FLAGS_READ_ONLY, NULL /*pfnGet*/, NULL /*pfnSet*/ } +/** Macro for creating a terminator sub-field entry. */ +#define DBGFREGSUBFIELD_TERMINATOR() \ + { NULL, 0, 0, 0, 0, NULL, NULL } + +/** + * Register alias descriptor. + */ +typedef struct DBGFREGALIAS +{ + /** The alias name. NULL is used to terminate the array. */ + const char *pszName; + /** Set to a valid type if the alias has a different type. */ + DBGFREGVALTYPE enmType; +} DBGFREGALIAS; +/** Pointer to a const register alias descriptor. */ +typedef DBGFREGALIAS const *PCDBGFREGALIAS; + +/** + * Register descriptor. + */ +typedef struct DBGFREGDESC +{ + /** The normal register name. */ + const char *pszName; + /** The register identifier if this is a CPU register. */ + DBGFREG enmReg; + /** The default register type. */ + DBGFREGVALTYPE enmType; + /** Flags, see DBGFREG_FLAGS_XXX. */ + uint32_t fFlags; + /** The internal register indicator. + * For CPU registers this is the offset into the CPUMCTX structure, + * thuse the 'off' prefix. */ + uint32_t offRegister; + /** Getter. + * @remarks Does not take the device lock or anything like that. + */ + DECLCALLBACKMEMBER(int, pfnGet,(void *pvUser, struct DBGFREGDESC const *pDesc, PDBGFREGVAL pValue)); + /** Setter. + * @remarks Does not take the device lock or anything like that. + */ + DECLCALLBACKMEMBER(int, pfnSet,(void *pvUser, struct DBGFREGDESC const *pDesc, PCDBGFREGVAL pValue, PCDBGFREGVAL pfMask)); + /** Aliases (optional). */ + PCDBGFREGALIAS paAliases; + /** Sub fields (optional). */ + PCDBGFREGSUBFIELD paSubFields; +} DBGFREGDESC; + +/** @name Macros for constructing DBGFREGDESC arrays. + * @{ */ +#define DBGFREGDESC_RW(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, 0 /*fFlags*/, a_offRegister, a_pfnGet, a_pfnSet, NULL /*paAlises*/, NULL /*paSubFields*/ } +#define DBGFREGDESC_RO(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, DBGFREG_FLAGS_READ_ONLY, a_offRegister, a_pfnGet, a_pfnSet, NULL /*paAlises*/, NULL /*paSubFields*/ } +#define DBGFREGDESC_RW_A(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, 0 /*fFlags*/, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, NULL /*paSubFields*/ } +#define DBGFREGDESC_RO_A(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, DBGFREG_FLAGS_READ_ONLY, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, NULL /*paSubFields*/ } +#define DBGFREGDESC_RW_S(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paSubFields) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, 0 /*fFlags*/, a_offRegister, a_pfnGet, a_pfnSet, /*paAliases*/, a_paSubFields } +#define DBGFREGDESC_RO_S(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paSubFields) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, DBGFREG_FLAGS_READ_ONLY, a_offRegister, a_pfnGet, a_pfnSet, /*paAliases*/, a_paSubFields } +#define DBGFREGDESC_RW_AS(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, a_paSubFields) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, 0 /*fFlags*/, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, a_paSubFields } +#define DBGFREGDESC_RO_AS(a_szName, a_TypeSuff, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, a_paSubFields) \ + { a_szName, DBGFREG_END, DBGFREGVALTYPE_##a_TypeSuff, DBGFREG_FLAGS_READ_ONLY, a_offRegister, a_pfnGet, a_pfnSet, a_paAliases, a_paSubFields } +#define DBGFREGDESC_TERMINATOR() \ + { NULL, DBGFREG_END, DBGFREGVALTYPE_INVALID, 0, 0, NULL, NULL, NULL, NULL } +/** @} */ + + +/** @name DBGFREG_FLAGS_XXX + * @{ */ +/** The register is read-only. */ +#define DBGFREG_FLAGS_READ_ONLY RT_BIT_32(0) +/** @} */ + +/** + * Entry in a batch query or set operation. + */ +typedef struct DBGFREGENTRY +{ + /** The register identifier. */ + DBGFREG enmReg; + /** The size of the value in bytes. */ + DBGFREGVALTYPE enmType; + /** The register value. The valid view is indicated by enmType. */ + DBGFREGVAL Val; +} DBGFREGENTRY; +/** Pointer to a register entry in a batch operation. */ +typedef DBGFREGENTRY *PDBGFREGENTRY; +/** Pointer to a const register entry in a batch operation. */ +typedef DBGFREGENTRY const *PCDBGFREGENTRY; + +/** Used with DBGFR3Reg* to indicate the hypervisor register set instead of the + * guest. */ +#define DBGFREG_HYPER_VMCPUID UINT32_C(0x01000000) + +VMMR3DECL(int) DBGFR3RegCpuQueryU8( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint8_t *pu8); +VMMR3DECL(int) DBGFR3RegCpuQueryU16( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint16_t *pu16); +VMMR3DECL(int) DBGFR3RegCpuQueryU32( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint32_t *pu32); +VMMR3DECL(int) DBGFR3RegCpuQueryU64( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t *pu64); +VMMR3DECL(int) DBGFR3RegCpuQueryU128(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint128_t *pu128); +/*VMMR3DECL(int) DBGFR3RegCpuQueryLrd( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, long double *plrd);*/ +VMMR3DECL(int) DBGFR3RegCpuQueryXdtr(PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t *pu64Base, uint16_t *pu16Limit); +#if 0 +VMMR3DECL(int) DBGFR3RegCpuQueryBatch(PUVM pUVM,VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs); +VMMR3DECL(int) DBGFR3RegCpuQueryAll( PUVM pUVM, VMCPUID idCpu, PDBGFREGENTRY paRegs, size_t cRegs); + +VMMR3DECL(int) DBGFR3RegCpuSetU8( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint8_t u8); +VMMR3DECL(int) DBGFR3RegCpuSetU16( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint16_t u16); +VMMR3DECL(int) DBGFR3RegCpuSetU32( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint32_t u32); +VMMR3DECL(int) DBGFR3RegCpuSetU64( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint64_t u64); +VMMR3DECL(int) DBGFR3RegCpuSetU128( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, uint128_t u128); +VMMR3DECL(int) DBGFR3RegCpuSetLrd( PUVM pUVM, VMCPUID idCpu, DBGFREG enmReg, long double lrd); +VMMR3DECL(int) DBGFR3RegCpuSetBatch( PUVM pUVM, VMCPUID idCpu, PCDBGFREGENTRY paRegs, size_t cRegs); +#endif + +VMMR3DECL(const char *) DBGFR3RegCpuName(PUVM pUVM, DBGFREG enmReg, DBGFREGVALTYPE enmType); + +VMMR3_INT_DECL(int) DBGFR3RegRegisterCpu(PVM pVM, PVMCPU pVCpu, PCDBGFREGDESC paRegisters, bool fGuestRegs); +VMMR3_INT_DECL(int) DBGFR3RegRegisterDevice(PVM pVM, PCDBGFREGDESC paRegisters, PPDMDEVINS pDevIns, + const char *pszPrefix, uint32_t iInstance); + +/** + * Entry in a named batch query or set operation. + */ +typedef struct DBGFREGENTRYNM +{ + /** The register name. */ + const char *pszName; + /** The size of the value in bytes. */ + DBGFREGVALTYPE enmType; + /** The register value. The valid view is indicated by enmType. */ + DBGFREGVAL Val; +} DBGFREGENTRYNM; +/** Pointer to a named register entry in a batch operation. */ +typedef DBGFREGENTRYNM *PDBGFREGENTRYNM; +/** Pointer to a const named register entry in a batch operation. */ +typedef DBGFREGENTRYNM const *PCDBGFREGENTRYNM; + +VMMR3DECL(int) DBGFR3RegNmValidate( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg); + +VMMR3DECL(int) DBGFR3RegNmQuery( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PDBGFREGVAL pValue, PDBGFREGVALTYPE penmType); +VMMR3DECL(int) DBGFR3RegNmQueryU8( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint8_t *pu8); +VMMR3DECL(int) DBGFR3RegNmQueryU16( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint16_t *pu16); +VMMR3DECL(int) DBGFR3RegNmQueryU32( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint32_t *pu32); +VMMR3DECL(int) DBGFR3RegNmQueryU64( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64); +VMMR3DECL(int) DBGFR3RegNmQueryU128(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PRTUINT128U pu128); +/*VMMR3DECL(int) DBGFR3RegNmQueryLrd( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, long double *plrd);*/ +VMMR3DECL(int) DBGFR3RegNmQueryXdtr(PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64Base, uint16_t *pu16Limit); +VMMR3DECL(int) DBGFR3RegNmQueryBatch(PUVM pUVM,VMCPUID idDefCpu, PDBGFREGENTRYNM paRegs, size_t cRegs); +VMMR3DECL(int) DBGFR3RegNmQueryAllCount(PUVM pUVM, size_t *pcRegs); +VMMR3DECL(int) DBGFR3RegNmQueryAll( PUVM pUVM, PDBGFREGENTRYNM paRegs, size_t cRegs); + +VMMR3DECL(int) DBGFR3RegNmSet( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, PCDBGFREGVAL pValue, DBGFREGVALTYPE enmType); +VMMR3DECL(int) DBGFR3RegNmSetU8( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint8_t u8); +VMMR3DECL(int) DBGFR3RegNmSetU16( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint16_t u16); +VMMR3DECL(int) DBGFR3RegNmSetU32( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint32_t u32); +VMMR3DECL(int) DBGFR3RegNmSetU64( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, uint64_t u64); +VMMR3DECL(int) DBGFR3RegNmSetU128( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, RTUINT128U u128); +VMMR3DECL(int) DBGFR3RegNmSetLrd( PUVM pUVM, VMCPUID idDefCpu, const char *pszReg, long double lrd); +VMMR3DECL(int) DBGFR3RegNmSetBatch( PUVM pUVM, VMCPUID idDefCpu, PCDBGFREGENTRYNM paRegs, size_t cRegs); + +/** @todo add enumeration methods. */ + +VMMR3DECL(int) DBGFR3RegPrintf( PUVM pUVM, VMCPUID idDefCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, ...); +VMMR3DECL(int) DBGFR3RegPrintfV(PUVM pUVM, VMCPUID idDefCpu, char *pszBuf, size_t cbBuf, const char *pszFormat, va_list va); + + +#ifdef IN_RING3 + +/** + * Guest OS digger interface identifier. + * + * This is for use together with PDBGFR3QueryInterface and is used to + * obtain access to optional interfaces. + */ +typedef enum DBGFOSINTERFACE +{ + /** The usual invalid entry. */ + DBGFOSINTERFACE_INVALID = 0, + /** Process info. */ + DBGFOSINTERFACE_PROCESS, + /** Thread info. */ + DBGFOSINTERFACE_THREAD, + /** Kernel message log - DBGFOSIDMESG. */ + DBGFOSINTERFACE_DMESG, + /** Windows NT specifics (for the communication with the KD debugger stub). */ + DBGFOSINTERFACE_WINNT, + /** The end of the valid entries. */ + DBGFOSINTERFACE_END, + /** The usual 32-bit type blowup. */ + DBGFOSINTERFACE_32BIT_HACK = 0x7fffffff +} DBGFOSINTERFACE; +/** Pointer to a Guest OS digger interface identifier. */ +typedef DBGFOSINTERFACE *PDBGFOSINTERFACE; +/** Pointer to a const Guest OS digger interface identifier. */ +typedef DBGFOSINTERFACE const *PCDBGFOSINTERFACE; + + +/** + * Guest OS Digger Registration Record. + * + * This is used with the DBGFR3OSRegister() API. + */ +typedef struct DBGFOSREG +{ + /** Magic value (DBGFOSREG_MAGIC). */ + uint32_t u32Magic; + /** Flags. Reserved. */ + uint32_t fFlags; + /** The size of the instance data. */ + uint32_t cbData; + /** Operative System name. */ + char szName[24]; + + /** + * Constructs the instance. + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(int, pfnConstruct,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Destroys the instance. + * + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(void, pfnDestruct,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Probes the guest memory for OS finger prints. + * + * No setup or so is performed, it will be followed by a call to pfnInit + * or pfnRefresh that should take care of that. + * + * @returns true if is an OS handled by this module, otherwise false. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(bool, pfnProbe,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Initializes a fresly detected guest, loading symbols and such useful stuff. + * + * This is called after pfnProbe. + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(int, pfnInit,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Refreshes symbols and stuff following a redetection of the same OS. + * + * This is called after pfnProbe. + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(int, pfnRefresh,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Terminates an OS when a new (or none) OS has been detected, + * and before destruction. + * + * This is called after pfnProbe and if needed before pfnDestruct. + * + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + */ + DECLCALLBACKMEMBER(void, pfnTerm,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData)); + + /** + * Queries the version of the running OS. + * + * This is only called after pfnInit(). + * + * @returns VBox status code. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + * @param pszVersion Where to store the version string. + * @param cchVersion The size of the version string buffer. + */ + DECLCALLBACKMEMBER(int, pfnQueryVersion,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData, char *pszVersion, size_t cchVersion)); + + /** + * Queries the pointer to a interface. + * + * This is called after pfnProbe. + * + * The returned interface must be valid until pfnDestruct is called. Two calls + * to this method with the same @a enmIf value must return the same pointer. + * + * @returns Pointer to the interface if available, NULL if not available. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + * @param enmIf The interface identifier. + */ + DECLCALLBACKMEMBER(void *, pfnQueryInterface,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData, DBGFOSINTERFACE enmIf)); + + /** + * Stack unwind assist callback. + * + * This is only called after pfnInit(). + * + * @returns VBox status code (allocation error or something of similar fatality). + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pvData Pointer to the instance data. + * @param idCpu The CPU that's unwinding it's stack. + * @param pFrame The current frame. Okay to modify it a little. + * @param pState The unwind state. Okay to modify it. + * @param pInitialCtx The initial register context. + * @param hAs The address space being used for the unwind. + * @param puScratch Scratch area (initialized to zero, no dtor). + */ + DECLCALLBACKMEMBER(int, pfnStackUnwindAssist,(PUVM pUVM, PCVMMR3VTABLE pVMM, void *pvData, VMCPUID idCpu, PDBGFSTACKFRAME pFrame, + PRTDBGUNWINDSTATE pState, PCCPUMCTX pInitialCtx, RTDBGAS hAs, + uint64_t *puScratch)); + + /** Trailing magic (DBGFOSREG_MAGIC). */ + uint32_t u32EndMagic; +} DBGFOSREG; +/** Pointer to a Guest OS digger registration record. */ +typedef DBGFOSREG *PDBGFOSREG; +/** Pointer to a const Guest OS digger registration record. */ +typedef DBGFOSREG const *PCDBGFOSREG; + +/** Magic value for DBGFOSREG::u32Magic and DBGFOSREG::u32EndMagic. (Hitomi Kanehara) */ +#define DBGFOSREG_MAGIC 0x19830808 + + +/** + * Interface for querying kernel log messages (DBGFOSINTERFACE_DMESG). + */ +typedef struct DBGFOSIDMESG +{ + /** Trailing magic (DBGFOSIDMESG_MAGIC). */ + uint32_t u32Magic; + + /** + * Query the kernel log. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the messages could not be located. + * @retval VERR_INVALID_STATE if the messages was found to have unknown/invalid + * format. + * @retval VERR_BUFFER_OVERFLOW if the buffer isn't large enough, pcbActual + * will be set to the required buffer size. The buffer, however, will + * be filled with as much data as it can hold (properly zero terminated + * of course). + * + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param fFlags Flags reserved for future use, MBZ. + * @param cMessages The number of messages to retrieve, counting from the + * end of the log (i.e. like tail), use UINT32_MAX for all. + * @param pszBuf The output buffer. + * @param cbBuf The buffer size. + * @param pcbActual Where to store the number of bytes actually returned, + * including zero terminator. On VERR_BUFFER_OVERFLOW this + * holds the necessary buffer size. Optional. + */ + DECLCALLBACKMEMBER(int, pfnQueryKernelLog,(struct DBGFOSIDMESG *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, uint32_t fFlags, + uint32_t cMessages, char *pszBuf, size_t cbBuf, size_t *pcbActual)); + /** Trailing magic (DBGFOSIDMESG_MAGIC). */ + uint32_t u32EndMagic; +} DBGFOSIDMESG; +/** Pointer to the interface for query kernel log messages (DBGFOSINTERFACE_DMESG). */ +typedef DBGFOSIDMESG *PDBGFOSIDMESG; +/** Magic value for DBGFOSIDMESG::32Magic and DBGFOSIDMESG::u32EndMagic. (Kenazburo Oe) */ +#define DBGFOSIDMESG_MAGIC UINT32_C(0x19350131) + + +/** + * Interface for querying Windows NT guest specifics (DBGFOSINTERFACE_WINNT). + */ +typedef struct DBGFOSIWINNT +{ + /** Trailing magic (DBGFOSIWINNT_MAGIC). */ + uint32_t u32Magic; + + /** + * Queries version information. + * + * @returns VBox status code. + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param puVersMajor Where to store the major version part, optional. + * @param puVersMinor Where to store the minor version part, optional. + * @param puBuildNumber Where to store the build number, optional. + * @param pf32Bit Where to store the flag whether this is a 32bit Windows NT, optional. + */ + DECLCALLBACKMEMBER(int, pfnQueryVersion,(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, + uint32_t *puVersMajor, uint32_t *puVersMinor, + uint32_t *puBuildNumber, bool *pf32Bit)); + + /** + * Queries some base kernel pointers. + * + * @returns VBox status code. + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param pGCPtrKernBase Where to store the kernel base on success. + * @param pGCPtrPsLoadedModuleList Where to store the pointer to the laoded module list head on success. + */ + DECLCALLBACKMEMBER(int, pfnQueryKernelPtrs,(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, + PRTGCUINTPTR pGCPtrKernBase, PRTGCUINTPTR pGCPtrPsLoadedModuleList)); + + /** + * Queries KPCR and KPCRB pointers for the given vCPU. + * + * @returns VBox status code. + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param idCpu The vCPU to query the KPCR/KPCRB for. + * @param pKpcr Where to store the KPCR pointer on success, optional. + * @param pKpcrb Where to store the KPCR pointer on success, optional. + */ + DECLCALLBACKMEMBER(int, pfnQueryKpcrForVCpu,(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, VMCPUID idCpu, + PRTGCUINTPTR pKpcr, PRTGCUINTPTR pKpcrb)); + + /** + * Queries the current thread for the given vCPU. + * + * @returns VBox status code. + * @param pThis Pointer to the interface structure. + * @param pUVM The user mode VM handle. + * @param pVMM The VMM function table. + * @param idCpu The vCPU to query the KPCR/KPCRB for. + * @param pCurThrd Where to store the CurrentThread pointer on success. + */ + DECLCALLBACKMEMBER(int, pfnQueryCurThrdForVCpu,(struct DBGFOSIWINNT *pThis, PUVM pUVM, PCVMMR3VTABLE pVMM, VMCPUID idCpu, + PRTGCUINTPTR pCurThrd)); + + /** Trailing magic (DBGFOSIWINNT_MAGIC). */ + uint32_t u32EndMagic; +} DBGFOSIWINNT; +/** Pointer to the interface for query kernel log messages (DBGFOSINTERFACE_WINNT). */ +typedef DBGFOSIWINNT *PDBGFOSIWINNT; +/** Magic value for DBGFOSIWINNT::32Magic and DBGFOSIWINNT::u32EndMagic. (Dave Cutler) */ +#define DBGFOSIWINNT_MAGIC UINT32_C(0x19420313) + + +VMMR3DECL(int) DBGFR3OSRegister(PUVM pUVM, PCDBGFOSREG pReg); +VMMR3DECL(int) DBGFR3OSDeregister(PUVM pUVM, PCDBGFOSREG pReg); +VMMR3DECL(int) DBGFR3OSDetect(PUVM pUVM, char *pszName, size_t cchName); +VMMR3DECL(int) DBGFR3OSQueryNameAndVersion(PUVM pUVM, char *pszName, size_t cchName, char *pszVersion, size_t cchVersion); +VMMR3DECL(void *) DBGFR3OSQueryInterface(PUVM pUVM, DBGFOSINTERFACE enmIf); + + +VMMR3DECL(int) DBGFR3CoreWrite(PUVM pUVM, const char *pszFilename, bool fReplaceFile); + + + +/** @defgroup grp_dbgf_plug_in The DBGF Plug-in Interface + * @{ + */ + +/** The plug-in module name prefix. */ +# define DBGF_PLUG_IN_PREFIX "DbgPlugIn" + +/** The name of the plug-in entry point (FNDBGFPLUGIN) */ +# define DBGF_PLUG_IN_ENTRYPOINT "DbgPlugInEntry" + +/** + * DBGF plug-in operations. + */ +typedef enum DBGFPLUGINOP +{ + /** The usual invalid first value. */ + DBGFPLUGINOP_INVALID, + /** Initialize the plug-in for a VM, register all the stuff. + * The plug-in will be unloaded on failure. + * uArg: The full VirtualBox version, see VBox/version.h. */ + DBGFPLUGINOP_INIT, + /** Terminate the plug-ing for a VM, deregister all the stuff. + * The plug-in will be unloaded after this call regardless of the return + * code. */ + DBGFPLUGINOP_TERM, + /** The usual 32-bit hack. */ + DBGFPLUGINOP_32BIT_HACK = 0x7fffffff +} DBGFPLUGINOP; + +/** + * DBGF plug-in main entry point. + * + * @returns VBox status code. + * + * @param enmOperation The operation. + * @param pUVM The user mode VM handle. This may be NULL. + * @param pVMM The VMM function table. + * @param uArg Extra argument. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFPLUGIN,(DBGFPLUGINOP enmOperation, PUVM pUVM, PCVMMR3VTABLE pVMM, uintptr_t uArg)); +/** Pointer to a FNDBGFPLUGIN. */ +typedef FNDBGFPLUGIN *PFNDBGFPLUGIN; + +/** @copydoc FNDBGFPLUGIN */ +DECLEXPORT(int) DbgPlugInEntry(DBGFPLUGINOP enmOperation, PUVM pUVM, PCVMMR3VTABLE pVMM, uintptr_t uArg); + +VMMR3DECL(int) DBGFR3PlugInLoad(PUVM pUVM, const char *pszPlugIn, char *pszActual, size_t cbActual, PRTERRINFO pErrInfo); +VMMR3DECL(int) DBGFR3PlugInUnload(PUVM pUVM, const char *pszName); +VMMR3DECL(void) DBGFR3PlugInLoadAll(PUVM pUVM); +VMMR3DECL(void) DBGFR3PlugInUnloadAll(PUVM pUVM); + +/** @} */ + + +/** @defgroup grp_dbgf_types The DBGF type system Interface. + * @{ + */ + +/** A few forward declarations. */ +/** Pointer to a type registration structure. */ +typedef struct DBGFTYPEREG *PDBGFTYPEREG; +/** Pointer to a const type registration structure. */ +typedef const struct DBGFTYPEREG *PCDBGFTYPEREG; +/** Pointer to a typed buffer. */ +typedef struct DBGFTYPEVAL *PDBGFTYPEVAL; + +/** + * DBGF built-in types. + */ +typedef enum DBGFTYPEBUILTIN +{ + /** The usual invalid first value. */ + DBGFTYPEBUILTIN_INVALID, + /** Unsigned 8bit integer. */ + DBGFTYPEBUILTIN_UINT8, + /** Signed 8bit integer. */ + DBGFTYPEBUILTIN_INT8, + /** Unsigned 16bit integer. */ + DBGFTYPEBUILTIN_UINT16, + /** Signed 16bit integer. */ + DBGFTYPEBUILTIN_INT16, + /** Unsigned 32bit integer. */ + DBGFTYPEBUILTIN_UINT32, + /** Signed 32bit integer. */ + DBGFTYPEBUILTIN_INT32, + /** Unsigned 64bit integer. */ + DBGFTYPEBUILTIN_UINT64, + /** Signed 64bit integer. */ + DBGFTYPEBUILTIN_INT64, + /** 32bit Guest pointer */ + DBGFTYPEBUILTIN_PTR32, + /** 64bit Guest pointer */ + DBGFTYPEBUILTIN_PTR64, + /** Guest pointer - size depends on the guest bitness */ + DBGFTYPEBUILTIN_PTR, + /** Type indicating a size, like size_t this can have different sizes + * on 32bit and 64bit systems */ + DBGFTYPEBUILTIN_SIZE, + /** 32bit float. */ + DBGFTYPEBUILTIN_FLOAT32, + /** 64bit float (also known as double). */ + DBGFTYPEBUILTIN_FLOAT64, + /** Compund types like structs and unions. */ + DBGFTYPEBUILTIN_COMPOUND, + /** The usual 32-bit hack. */ + DBGFTYPEBUILTIN_32BIT_HACK = 0x7fffffff +} DBGFTYPEBUILTIN; +/** Pointer to a built-in type. */ +typedef DBGFTYPEBUILTIN *PDBGFTYPEBUILTIN; +/** Pointer to a const built-in type. */ +typedef const DBGFTYPEBUILTIN *PCDBGFTYPEBUILTIN; + +/** + * DBGF type value buffer. + */ +typedef union DBGFTYPEVALBUF +{ + uint8_t u8; + int8_t i8; + uint16_t u16; + int16_t i16; + uint32_t u32; + int32_t i32; + uint64_t u64; + int64_t i64; + float f32; + double f64; + uint64_t size; /* For the built-in size_t which can be either 32-bit or 64-bit. */ + RTGCPTR GCPtr; + /** For embedded structs. */ + PDBGFTYPEVAL pVal; +} DBGFTYPEVALBUF; +/** Pointer to a value. */ +typedef DBGFTYPEVALBUF *PDBGFTYPEVALBUF; + +/** + * DBGF type value entry. + */ +typedef struct DBGFTYPEVALENTRY +{ + /** DBGF built-in type. */ + DBGFTYPEBUILTIN enmType; + /** Size of the type. */ + size_t cbType; + /** Number of entries, for arrays this can be > 1. */ + uint32_t cEntries; + /** Value buffer, depends on whether this is an array. */ + union + { + /** Single value. */ + DBGFTYPEVALBUF Val; + /** Pointer to the array of values. */ + PDBGFTYPEVALBUF pVal; + } Buf; +} DBGFTYPEVALENTRY; +/** Pointer to a type value entry. */ +typedef DBGFTYPEVALENTRY *PDBGFTYPEVALENTRY; +/** Pointer to a const type value entry. */ +typedef const DBGFTYPEVALENTRY *PCDBGFTYPEVALENTRY; + +/** + * DBGF typed value. + */ +typedef struct DBGFTYPEVAL +{ + /** Pointer to the registration structure for this type. */ + PCDBGFTYPEREG pTypeReg; + /** Number of value entries. */ + uint32_t cEntries; + /** Variable sized array of value entries. */ + DBGFTYPEVALENTRY aEntries[1]; +} DBGFTYPEVAL; + +/** + * DBGF type variant. + */ +typedef enum DBGFTYPEVARIANT +{ + /** The usual invalid first value. */ + DBGFTYPEVARIANT_INVALID, + /** A struct. */ + DBGFTYPEVARIANT_STRUCT, + /** Union. */ + DBGFTYPEVARIANT_UNION, + /** Alias for an existing type. */ + DBGFTYPEVARIANT_ALIAS, + /** The usual 32-bit hack. */ + DBGFTYPEVARIANT_32BIT_HACK = 0x7fffffff +} DBGFTYPEVARIANT; + +/** @name DBGFTYPEREGMEMBER Flags. + * @{ */ +/** The member is an array with a fixed size. */ +# define DBGFTYPEREGMEMBER_F_ARRAY RT_BIT_32(0) +/** The member denotes a pointer. */ +# define DBGFTYPEREGMEMBER_F_POINTER RT_BIT_32(1) +/** @} */ + +/** + * DBGF type member. + */ +typedef struct DBGFTYPEREGMEMBER +{ + /** Name of the member. */ + const char *pszName; + /** Flags for this member, see DBGFTYPEREGMEMBER_F_XXX. */ + uint32_t fFlags; + /** Type identifier. */ + const char *pszType; + /** The number of elements in the array, only valid for arrays. */ + uint32_t cElements; +} DBGFTYPEREGMEMBER; +/** Pointer to a member. */ +typedef DBGFTYPEREGMEMBER *PDBGFTYPEREGMEMBER; +/** Pointer to a const member. */ +typedef const DBGFTYPEREGMEMBER *PCDBGFTYPEREGMEMBER; + +/** @name DBGFTYPEREG Flags. + * @{ */ +/** The type is a packed structure. */ +# define DBGFTYPEREG_F_PACKED RT_BIT_32(0) +/** @} */ + +/** + * New type registration structure. + */ +typedef struct DBGFTYPEREG +{ + /** Name of the type. */ + const char *pszType; + /** The type variant. */ + DBGFTYPEVARIANT enmVariant; + /** Some registration flags, see DBGFTYPEREG_F_XXX. */ + uint32_t fFlags; + /** Number of members this type has, only valid for structs or unions. */ + uint32_t cMembers; + /** Pointer to the member fields, only valid for structs or unions. */ + PCDBGFTYPEREGMEMBER paMembers; + /** Name of the aliased type for aliases. */ + const char *pszAliasedType; +} DBGFTYPEREG; + +/** + * DBGF typed value dumper callback. + * + * @returns VBox status code. Any non VINF_SUCCESS status code will abort the dumping. + * + * @param off The byte offset of the entry from the start of the type. + * @param pszField The name of the field for the value. + * @param iLvl The current level. + * @param enmType The type enum. + * @param cbType Size of the type. + * @param pValBuf Pointer to the value buffer. + * @param cValBufs Number of value buffers (for arrays). + * @param pvUser Opaque user data. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFR3TYPEVALDUMP,(uint32_t off, const char *pszField, uint32_t iLvl, + DBGFTYPEBUILTIN enmType, size_t cbType, + PDBGFTYPEVALBUF pValBuf, uint32_t cValBufs, void *pvUser)); +/** Pointer to a FNDBGFR3TYPEVALDUMP. */ +typedef FNDBGFR3TYPEVALDUMP *PFNDBGFR3TYPEVALDUMP; + +/** + * DBGF type information dumper callback. + * + * @returns VBox status code. Any non VINF_SUCCESS status code will abort the dumping. + * + * @param off The byte offset of the entry from the start of the type. + * @param pszField The name of the field for the value. + * @param iLvl The current level. + * @param pszType The type of the field. + * @param fTypeFlags Flags for this type, see DBGFTYPEREGMEMBER_F_XXX. + * @param cElements Number of for the field ( > 0 for arrays). + * @param pvUser Opaque user data. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFR3TYPEDUMP,(uint32_t off, const char *pszField, uint32_t iLvl, + const char *pszType, uint32_t fTypeFlags, + uint32_t cElements, void *pvUser)); +/** Pointer to a FNDBGFR3TYPEDUMP. */ +typedef FNDBGFR3TYPEDUMP *PFNDBGFR3TYPEDUMP; + +VMMR3DECL(int) DBGFR3TypeRegister( PUVM pUVM, uint32_t cTypes, PCDBGFTYPEREG paTypes); +VMMR3DECL(int) DBGFR3TypeDeregister(PUVM pUVM, const char *pszType); +VMMR3DECL(int) DBGFR3TypeQueryReg( PUVM pUVM, const char *pszType, PCDBGFTYPEREG *ppTypeReg); + +VMMR3DECL(int) DBGFR3TypeQuerySize( PUVM pUVM, const char *pszType, size_t *pcbType); +VMMR3DECL(int) DBGFR3TypeSetSize( PUVM pUVM, const char *pszType, size_t cbType); +VMMR3DECL(int) DBGFR3TypeDumpEx( PUVM pUVM, const char *pszType, uint32_t fFlags, + uint32_t cLvlMax, PFNDBGFR3TYPEDUMP pfnDump, void *pvUser); +VMMR3DECL(int) DBGFR3TypeQueryValByType(PUVM pUVM, PCDBGFADDRESS pAddress, const char *pszType, + PDBGFTYPEVAL *ppVal); +VMMR3DECL(void) DBGFR3TypeValFree(PDBGFTYPEVAL pVal); +VMMR3DECL(int) DBGFR3TypeValDumpEx(PUVM pUVM, PCDBGFADDRESS pAddress, const char *pszType, uint32_t fFlags, + uint32_t cLvlMax, FNDBGFR3TYPEVALDUMP pfnDump, void *pvUser); + +/** @} */ + + +/** @defgroup grp_dbgf_flow The DBGF control flow graph Interface. + * @{ + */ + +/** A DBGF control flow graph handle. */ +typedef struct DBGFFLOWINT *DBGFFLOW; +/** Pointer to a DBGF control flow graph handle. */ +typedef DBGFFLOW *PDBGFFLOW; +/** A DBGF control flow graph basic block handle. */ +typedef struct DBGFFLOWBBINT *DBGFFLOWBB; +/** Pointer to a DBGF control flow graph basic block handle. */ +typedef DBGFFLOWBB *PDBGFFLOWBB; +/** A DBGF control flow graph branch table handle. */ +typedef struct DBGFFLOWBRANCHTBLINT *DBGFFLOWBRANCHTBL; +/** Pointer to a DBGF flow control graph branch table handle. */ +typedef DBGFFLOWBRANCHTBL *PDBGFFLOWBRANCHTBL; +/** A DBGF control flow graph iterator. */ +typedef struct DBGFFLOWITINT *DBGFFLOWIT; +/** Pointer to a control flow graph iterator. */ +typedef DBGFFLOWIT *PDBGFFLOWIT; +/** A DBGF control flow graph branch table iterator. */ +typedef struct DBGFFLOWBRANCHTBLITINT *DBGFFLOWBRANCHTBLIT; +/** Pointer to a control flow graph branch table iterator. */ +typedef DBGFFLOWBRANCHTBLIT *PDBGFFLOWBRANCHTBLIT; + +/** @name DBGFFLOWBB Flags. + * @{ */ +/** The basic block is the entry into the owning control flow graph. */ +#define DBGF_FLOW_BB_F_ENTRY RT_BIT_32(0) +/** The basic block was not populated because the limit was reached. */ +#define DBGF_FLOW_BB_F_EMPTY RT_BIT_32(1) +/** The basic block is not complete because an error happened during disassembly. */ +#define DBGF_FLOW_BB_F_INCOMPLETE_ERR RT_BIT_32(2) +/** The basic block is reached through a branch table. */ +#define DBGF_FLOW_BB_F_BRANCH_TABLE RT_BIT_32(3) +/** The basic block consists only of a single call instruction because + * DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB was given. */ +#define DBGF_FLOW_BB_F_CALL_INSN RT_BIT_32(4) +/** The branch target of the call instruction could be deduced and can be queried with + * DBGFR3FlowBbGetBranchAddress(). May only be available when DBGF_FLOW_BB_F_CALL_INSN + * is set. */ +#define DBGF_FLOW_BB_F_CALL_INSN_TARGET_KNOWN RT_BIT_32(5) +/** @} */ + +/** @name Flags controlling the creating of a control flow graph. + * @{ */ +/** Default options. */ +#define DBGF_FLOW_CREATE_F_DEFAULT 0 +/** Tries to resolve indirect branches, useful for code using + * jump tables generated for large switch statements by some compilers. */ +#define DBGF_FLOW_CREATE_F_TRY_RESOLVE_INDIRECT_BRANCHES RT_BIT_32(0) +/** Call instructions are placed in a separate basic block. */ +#define DBGF_FLOW_CREATE_F_CALL_INSN_SEPARATE_BB RT_BIT_32(1) +/** @} */ + +/** + * DBGF control graph basic block end type. + */ +typedef enum DBGFFLOWBBENDTYPE +{ + /** Invalid type. */ + DBGFFLOWBBENDTYPE_INVALID = 0, + /** Basic block is the exit block and has no successor. */ + DBGFFLOWBBENDTYPE_EXIT, + /** Basic block is the last disassembled block because the + * maximum amount to disassemble was reached but is not an + * exit block - no successors. + */ + DBGFFLOWBBENDTYPE_LAST_DISASSEMBLED, + /** Unconditional control flow change because the successor is referenced by multiple + * basic blocks. - 1 successor. */ + DBGFFLOWBBENDTYPE_UNCOND, + /** Unconditional control flow change because of an direct branch - 1 successor. */ + DBGFFLOWBBENDTYPE_UNCOND_JMP, + /** Unconditional control flow change because of an indirect branch - n successors. */ + DBGFFLOWBBENDTYPE_UNCOND_INDIRECT_JMP, + /** Conditional control flow change - 2 successors. */ + DBGFFLOWBBENDTYPE_COND, + /** 32bit hack. */ + DBGFFLOWBBENDTYPE_32BIT_HACK = 0x7fffffff +} DBGFFLOWBBENDTYPE; + +/** + * DBGF control flow graph iteration order. + */ +typedef enum DBGFFLOWITORDER +{ + /** Invalid order. */ + DBGFFLOWITORDER_INVALID = 0, + /** From lowest to highest basic block start address. */ + DBGFFLOWITORDER_BY_ADDR_LOWEST_FIRST, + /** From highest to lowest basic block start address. */ + DBGFFLOWITORDER_BY_ADDR_HIGHEST_FIRST, + /** Depth first traversing starting from the entry block. */ + DBGFFLOWITORDER_DEPTH_FRIST, + /** Breadth first traversing starting from the entry block. */ + DBGFFLOWITORDER_BREADTH_FIRST, + /** Usual 32bit hack. */ + DBGFFLOWITORDER_32BIT_HACK = 0x7fffffff +} DBGFFLOWITORDER; +/** Pointer to a iteration order enum. */ +typedef DBGFFLOWITORDER *PDBGFFLOWITORDER; + + +VMMR3DECL(int) DBGFR3FlowCreate(PUVM pUVM, VMCPUID idCpu, PDBGFADDRESS pAddressStart, uint32_t cbDisasmMax, + uint32_t fFlagsFlow, uint32_t fFlagsDisasm, PDBGFFLOW phFlow); +VMMR3DECL(uint32_t) DBGFR3FlowRetain(DBGFFLOW hFlow); +VMMR3DECL(uint32_t) DBGFR3FlowRelease(DBGFFLOW hFlow); +VMMR3DECL(int) DBGFR3FlowQueryStartBb(DBGFFLOW hFlow, PDBGFFLOWBB phFlowBb); +VMMR3DECL(int) DBGFR3FlowQueryBbByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBB phFlowBb); +VMMR3DECL(int) DBGFR3FlowQueryBranchTblByAddress(DBGFFLOW hFlow, PDBGFADDRESS pAddr, PDBGFFLOWBRANCHTBL phFlowBranchTbl); +VMMR3DECL(uint32_t) DBGFR3FlowGetBbCount(DBGFFLOW hFlow); +VMMR3DECL(uint32_t) DBGFR3FlowGetBranchTblCount(DBGFFLOW hFlow); +VMMR3DECL(uint32_t) DBGFR3FlowGetCallInsnCount(DBGFFLOW hFlow); + +VMMR3DECL(uint32_t) DBGFR3FlowBbRetain(DBGFFLOWBB hFlowBb); +VMMR3DECL(uint32_t) DBGFR3FlowBbRelease(DBGFFLOWBB hFlowBb); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetStartAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrStart); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetEndAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrEnd); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetBranchAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrTarget); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBbGetFollowingAddress(DBGFFLOWBB hFlowBb, PDBGFADDRESS pAddrFollow); +VMMR3DECL(DBGFFLOWBBENDTYPE) DBGFR3FlowBbGetType(DBGFFLOWBB hFlowBb); +VMMR3DECL(uint32_t) DBGFR3FlowBbGetInstrCount(DBGFFLOWBB hFlowBb); +VMMR3DECL(uint32_t) DBGFR3FlowBbGetFlags(DBGFFLOWBB hFlowBb); +VMMR3DECL(int) DBGFR3FlowBbQueryBranchTbl(DBGFFLOWBB hFlowBb, PDBGFFLOWBRANCHTBL phBranchTbl); +VMMR3DECL(int) DBGFR3FlowBbQueryError(DBGFFLOWBB hFlowBb, const char **ppszErr); +VMMR3DECL(int) DBGFR3FlowBbQueryInstr(DBGFFLOWBB hFlowBb, uint32_t idxInstr, PDBGFADDRESS pAddrInstr, + uint32_t *pcbInstr, const char **ppszInstr); +VMMR3DECL(int) DBGFR3FlowBbQuerySuccessors(DBGFFLOWBB hFlowBb, PDBGFFLOWBB phFlowBbFollow, + PDBGFFLOWBB phFlowBbTarget); +VMMR3DECL(uint32_t) DBGFR3FlowBbGetRefBbCount(DBGFFLOWBB hFlowBb); +VMMR3DECL(int) DBGFR3FlowBbGetRefBb(DBGFFLOWBB hFlowBb, PDBGFFLOWBB pahFlowBbRef, uint32_t cRef); + +VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRetain(DBGFFLOWBRANCHTBL hFlowBranchTbl); +VMMR3DECL(uint32_t) DBGFR3FlowBranchTblRelease(DBGFFLOWBRANCHTBL hFlowBranchTbl); +VMMR3DECL(uint32_t) DBGFR3FlowBranchTblGetSlots(DBGFFLOWBRANCHTBL hFlowBranchTbl); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetStartAddress(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS pAddrStart); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowBranchTblGetAddrAtSlot(DBGFFLOWBRANCHTBL hFlowBranchTbl, uint32_t idxSlot, PDBGFADDRESS pAddrSlot); +VMMR3DECL(int) DBGFR3FlowBranchTblQueryAddresses(DBGFFLOWBRANCHTBL hFlowBranchTbl, PDBGFADDRESS paAddrs, uint32_t cAddrs); + +VMMR3DECL(int) DBGFR3FlowItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder, PDBGFFLOWIT phFlowIt); +VMMR3DECL(void) DBGFR3FlowItDestroy(DBGFFLOWIT hFlowIt); +VMMR3DECL(DBGFFLOWBB) DBGFR3FlowItNext(DBGFFLOWIT hFlowIt); +VMMR3DECL(int) DBGFR3FlowItReset(DBGFFLOWIT hFlowIt); + +VMMR3DECL(int) DBGFR3FlowBranchTblItCreate(DBGFFLOW hFlow, DBGFFLOWITORDER enmOrder, PDBGFFLOWBRANCHTBLIT phFlowBranchTblIt); +VMMR3DECL(void) DBGFR3FlowBranchTblItDestroy(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt); +VMMR3DECL(DBGFFLOWBRANCHTBL) DBGFR3FlowBranchTblItNext(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt); +VMMR3DECL(int) DBGFR3FlowBranchTblItReset(DBGFFLOWBRANCHTBLIT hFlowBranchTblIt); + +/** @} */ + + +/** @defgroup grp_dbgf_misc Misc DBGF interfaces. + * @{ */ +VMMR3DECL(VBOXSTRICTRC) DBGFR3ReportBugCheck(PVM pVM, PVMCPU pVCpu, DBGFEVENTTYPE enmEvent, uint64_t uBugCheck, + uint64_t uP1, uint64_t uP2, uint64_t uP3, uint64_t uP4); +VMMR3DECL(int) DBGFR3FormatBugCheck(PUVM pUVM, char *pszDetails, size_t cbDetails, + uint64_t uP0, uint64_t uP1, uint64_t uP2, uint64_t uP3, uint64_t uP4); +/** @} */ +#endif /* IN_RING3 */ + + +/** @defgroup grp_dbgf_tracer DBGF event tracing. + * @{ */ +#ifdef IN_RING3 +VMMR3_INT_DECL(int) DBGFR3TracerRegisterEvtSrc(PVM pVM, const char *pszName, PDBGFTRACEREVTSRC phEvtSrc); +VMMR3_INT_DECL(int) DBGFR3TracerDeregisterEvtSrc(PVM pVM, DBGFTRACEREVTSRC hEvtSrc); +VMMR3_INT_DECL(int) DBGFR3TracerEvtIoPortCreate(PVM pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTIOPORT cPorts, uint32_t fFlags, + uint32_t iPciRegion); +VMMR3_INT_DECL(int) DBGFR3TracerEvtMmioCreate(PVM pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS cbRegion, uint32_t fFlags, + uint32_t iPciRegion); +#endif + +VMM_INT_DECL(int) DBGFTracerEvtMmioMap(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS GCPhysMmio); +VMM_INT_DECL(int) DBGFTracerEvtMmioUnmap(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion); +VMM_INT_DECL(int) DBGFTracerEvtMmioRead(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS offMmio, const void *pvVal, size_t cbVal); +VMM_INT_DECL(int) DBGFTracerEvtMmioWrite(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS offMmio, const void *pvVal, size_t cbVal); +VMM_INT_DECL(int) DBGFTracerEvtMmioFill(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hRegion, RTGCPHYS offMmio, uint32_t u32Item, uint32_t cbItem, uint32_t cItems); +VMM_INT_DECL(int) DBGFTracerEvtIoPortMap(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT IoPortBase); +VMM_INT_DECL(int) DBGFTracerEvtIoPortUnmap(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts); +VMM_INT_DECL(int) DBGFTracerEvtIoPortRead(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT offPort, const void *pvVal, size_t cbVal); +VMM_INT_DECL(int) DBGFTracerEvtIoPortReadStr(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT offPort, const void *pv, size_t cb, + uint32_t cTransfersReq, uint32_t cTransfersRet); +VMM_INT_DECL(int) DBGFTracerEvtIoPortWrite(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT offPort, const void *pvVal, size_t cbVal); +VMM_INT_DECL(int) DBGFTracerEvtIoPortWriteStr(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, uint64_t hIoPorts, RTIOPORT offPort, const void *pv, size_t cb, + uint32_t cTransfersReq, uint32_t cTransfersRet); +VMM_INT_DECL(int) DBGFTracerEvtIrq(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, int32_t iIrq, int32_t fIrqLvl); +VMM_INT_DECL(int) DBGFTracerEvtIoApicMsi(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, RTGCPHYS GCPhys, uint32_t u32Val); +VMM_INT_DECL(int) DBGFTracerEvtGCPhysRead(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, RTGCPHYS GCPhys, const void *pvBuf, size_t cbRead); +VMM_INT_DECL(int) DBGFTracerEvtGCPhysWrite(PVMCC pVM, DBGFTRACEREVTSRC hEvtSrc, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite); +/** @} */ + + +/** @defgroup grp_dbgf_sample_report DBGF sample report. + * @{ */ + +/** + * Callback which provides progress information about a currently running + * lengthy operation. + * + * @return VBox status code. + * @retval VERR_DBGF_CANCELLED to cancel the operation. + * @param pvUser The opaque user data associated with this interface. + * @param uPercentage Completion percentage. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFPROGRESS,(void *pvUser, unsigned uPercentage)); +/** Pointer to FNDBGFPROGRESS() */ +typedef FNDBGFPROGRESS *PFNDBGFPROGRESS; + +/** @name Flags to pass to DBGFR3SampleReportCreate(). + * @{ */ +/** The report creates the call stack in reverse order (bottom to top). */ +#define DBGF_SAMPLE_REPORT_F_STACK_REVERSE RT_BIT(0) +/** Mask containing the valid flags. */ +#define DBGF_SAMPLE_REPORT_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +VMMR3DECL(int) DBGFR3SampleReportCreate(PUVM pUVM, uint32_t cSampleIntervalMs, uint32_t fFlags, PDBGFSAMPLEREPORT phSample); +VMMR3DECL(uint32_t) DBGFR3SampleReportRetain(DBGFSAMPLEREPORT hSample); +VMMR3DECL(uint32_t) DBGFR3SampleReportRelease(DBGFSAMPLEREPORT hSample); +VMMR3DECL(int) DBGFR3SampleReportStart(DBGFSAMPLEREPORT hSample, uint64_t cSampleUs, PFNDBGFPROGRESS pfnProgress, void *pvUser); +VMMR3DECL(int) DBGFR3SampleReportStop(DBGFSAMPLEREPORT hSample); +VMMR3DECL(int) DBGFR3SampleReportDumpToFile(DBGFSAMPLEREPORT hSample, const char *pszFilename); +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_dbgf_h */ + diff --git a/include/VBox/vmm/dbgfcorefmt.h b/include/VBox/vmm/dbgfcorefmt.h new file mode 100644 index 00000000..c2b0cd5e --- /dev/null +++ b/include/VBox/vmm/dbgfcorefmt.h @@ -0,0 +1,188 @@ +/** @file + * DBGF - Debugger Facility, VM Core File Format. + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgfcorefmt_h +#define VBOX_INCLUDED_vmm_dbgfcorefmt_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_dbgf_corefmt VM Core File Format + * @ingroup grp_dbgf + * + * @todo Add description of the core file format and how the structures in this + * file relate to it. Point to X86XSAVEAREA in x86.h for the CPU's + * FPU/SSE/AVX/XXX state. + * @todo Add the note names. + * + * @{ + */ + +/** DBGCORECOREDESCRIPTOR::u32Magic. */ +#define DBGFCORE_MAGIC UINT32_C(0xc01ac0de) +/** DBGCORECOREDESCRIPTOR::u32FmtVersion. */ +#define DBGFCORE_FMT_VERSION UINT32_C(0x00010006) + +/** + * An x86 segment selector. + */ +typedef struct DBGFCORESEL +{ + uint64_t uBase; + uint32_t uLimit; + uint32_t uAttr; + uint16_t uSel; + uint16_t uReserved0; + uint32_t uReserved1; +} DBGFCORESEL; +AssertCompileSizeAlignment(DBGFCORESEL, 8); + +/** + * A gdtr/ldtr descriptor. + */ +typedef struct DBGFCOREXDTR +{ + uint64_t uAddr; + uint32_t cb; + uint32_t uReserved0; +} DBGFCOREXDTR; +AssertCompileSizeAlignment(DBGFCOREXDTR, 8); + +/** + * A simpler to parse CPU dump than CPUMCTX. + * + * Please bump DBGFCORE_FMT_VERSION by 1 if you make any changes to this + * structure. + */ +typedef struct DBGFCORECPU +{ + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + uint64_t rsi; + uint64_t rdi; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + uint64_t rip; + uint64_t rsp; + uint64_t rbp; + uint64_t rflags; + DBGFCORESEL cs; + DBGFCORESEL ds; + DBGFCORESEL es; + DBGFCORESEL fs; + DBGFCORESEL gs; + DBGFCORESEL ss; + uint64_t cr0; + uint64_t cr2; + uint64_t cr3; + uint64_t cr4; + uint64_t dr[8]; + DBGFCOREXDTR gdtr; + DBGFCOREXDTR idtr; + DBGFCORESEL ldtr; + DBGFCORESEL tr; + struct + { + uint64_t cs; + uint64_t eip; + uint64_t esp; + } sysenter; + uint64_t msrEFER; + uint64_t msrSTAR; + uint64_t msrPAT; + uint64_t msrLSTAR; + uint64_t msrCSTAR; + uint64_t msrSFMASK; + uint64_t msrKernelGSBase; + uint64_t msrApicBase; + uint64_t msrTscAux; + uint64_t aXcr[2]; + uint32_t cbExt; + uint32_t uPadding0; + X86XSAVEAREA ext; +} DBGFCORECPU; +/** Pointer to a DBGF-core CPU. */ +typedef DBGFCORECPU *PDBGFCORECPU; +/** Pointer to the const DBGF-core CPU. */ +typedef const DBGFCORECPU *PCDBGFCORECPU; +AssertCompileMemberAlignment(DBGFCORECPU, cr0, 8); +AssertCompileMemberAlignment(DBGFCORECPU, msrEFER, 8); +AssertCompileMemberAlignment(DBGFCORECPU, ext, 8); +AssertCompileSizeAlignment(DBGFCORECPU, 8); + +/** + * The DBGF Core descriptor. + */ +typedef struct DBGFCOREDESCRIPTOR +{ + /** The core file magic (DBGFCORE_MAGIC) */ + uint32_t u32Magic; + /** The core file format version (DBGFCORE_FMT_VERSION). */ + uint32_t u32FmtVersion; + /** Size of this structure (sizeof(DBGFCOREDESCRIPTOR)). */ + uint32_t cbSelf; + /** VirtualBox version. */ + uint32_t u32VBoxVersion; + /** VirtualBox revision. */ + uint32_t u32VBoxRevision; + /** Number of CPUs. */ + uint32_t cCpus; +} DBGFCOREDESCRIPTOR; +AssertCompileSizeAlignment(DBGFCOREDESCRIPTOR, 8); +/** Pointer to DBGFCOREDESCRIPTOR data. */ +typedef DBGFCOREDESCRIPTOR *PDBGFCOREDESCRIPTOR; + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_dbgfcorefmt_h */ + diff --git a/include/VBox/vmm/dbgfflowtrace.h b/include/VBox/vmm/dbgfflowtrace.h new file mode 100644 index 00000000..4906fe7e --- /dev/null +++ b/include/VBox/vmm/dbgfflowtrace.h @@ -0,0 +1,400 @@ +/** @file + * DBGF - Debugger Facility, Guest execution flow tracing. + */ + +/* + * Copyright (C) 2020-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgfflowtrace_h +#define VBOX_INCLUDED_vmm_dbgfflowtrace_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN +/** @defgroup grp_dbgf_flowtrace Guest Execution Flow Tracing + * @ingroup grp_dbgf + * + * @{ + */ + +/** A DBGF flow trace module handle. */ +typedef struct DBGFFLOWTRACEMODINT *DBGFFLOWTRACEMOD; +/** Pointer to a DBGF flow trace module handle. */ +typedef DBGFFLOWTRACEMOD *PDBGFFLOWTRACEMOD; +/** A DBGF flow trace probe handle. */ +typedef struct DBGFFLOWTRACEPROBEINT *DBGFFLOWTRACEPROBE; +/** Pointer to a DBGF flow trace state probe handle. */ +typedef DBGFFLOWTRACEPROBE *PDBGFFLOWTRACEPROBE; +/** A DBGF flow trace report handle. */ +typedef struct DBGFFLOWTRACEREPORTINT *DBGFFLOWTRACEREPORT; +/** Pointer to a DBGF flow trace report handle. */ +typedef DBGFFLOWTRACEREPORT *PDBGFFLOWTRACEREPORT; +/** A DBGF flow trace record handle. */ +typedef struct DBGFFLOWTRACERECORDINT *DBGFFLOWTRACERECORD; +/** Pointer to a DBGF flow trace record handle. */ +typedef DBGFFLOWTRACERECORD *PDBGFFLOWTRACERECORD; + + +/** Pointer to a flow trace probe entry. */ +typedef struct DBGFFLOWTRACEPROBEENTRY *PDBGFFLOWTRACEPROBEENTRY; +/** Pointer to a const flow trace probe entry. */ +typedef const struct DBGFFLOWTRACEPROBEENTRY *PCDBGFFLOWTRACEPROBEENTRY; + +/** @name Flags controlling the type of the addition of a single probe. + * @{ */ +/** Default options. */ +#define DBGF_FLOW_TRACE_PROBE_ADD_F_DEFAULT DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC +/** Collects the data specified by the data probe before the instruction is executed. */ +#define DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC RT_BIT_32(0) +/** Collects the data specified by the data probe after the instruction was executed. */ +#define DBGF_FLOW_TRACE_PROBE_ADD_F_AFTER_EXEC RT_BIT_32(1) +/** Mask of all valid flags. */ +#define DBGF_FLOW_TRACE_PROBE_ADD_F_VALID_MASK ( DBGF_FLOW_TRACE_PROBE_ADD_F_BEFORE_EXEC \ + | DBGF_FLOW_TRACE_PROBE_ADD_F_AFTER_EXEC) +/** @} */ + + +/** + * Probe entry type. + */ +typedef enum DBGFFLOWTRACEPROBEENTRYTYPE +{ + /** Invalid type. */ + DBGFFLOWTRACEPROBEENTRYTYPE_INVALID = 0, + /** Register. */ + DBGFFLOWTRACEPROBEENTRYTYPE_REG, + /** Constant memory buffer pointer. */ + DBGFFLOWTRACEPROBEENTRYTYPE_CONST_MEM, + /** Indirect memory buffer pointer, obtained from the base and index register + * and a constant scale. */ + DBGFFLOWTRACEPROBEENTRYTYPE_INDIRECT_MEM, + /** Callback. */ + DBGFFLOWTRACEPROBEENTRYTYPE_CALLBACK, + /** Halt in the debugger when the entry is collected. */ + DBGFFLOWTRACEPROBEENTRYTYPE_DEBUGGER, + /** 32bit hack. */ + DBGFFLOWTRACEPROBEENTRYTYPE_32BIT_HACK = 0x7fffffff +} DBGFFLOWTRACEPROBEENTRYTYPE; + + +/** + * Register descriptor for a probe entry. + */ +typedef struct DBGFFLOWTRACEPROBEENTRYREG +{ + /** The register name - see DBGFR3RegNm*. */ + const char *pszName; + /** The size of the value in bytes. */ + DBGFREGVALTYPE enmType; +} DBGFFLOWTRACEPROBEENTRYREG; +/** Pointer to data probe register entry. */ +typedef DBGFFLOWTRACEPROBEENTRYREG *PDBGFFLOWTRACEPROBEENTRYREG; +/** Pointer to a const probe register entry. */ +typedef const DBGFFLOWTRACEPROBEENTRYREG *PCDBGFFLOWTRACEPROBEENTRYREG; + + +/** + * Flow trace probe callback. + * + * @returns VBox status code, any error aborts continuing fetching the data for the + * probe containing this callback. + * @param pUVM The usermode VM handle. + * @param idCpu The ID of the vCPU the probe as fired. + * @param hFlowTraceMod The handle to the flow trace module the probe was fired for. + * @param pAddrProbe The guest address the probe was fired at. + * @param hFlowTraceProbe The flow trace probe handle.this callback is in. + * @param pProbeEntry The probe entry this callback is part of. + * @param pvUser The opaque user data for the callback. + */ +typedef DECLCALLBACKTYPE(int, FNDBGFFLOWTRACEPROBECALLBACK, (PUVM pUVM, VMCPUID idCpu, DBGFFLOWTRACEMOD hFlowTraceMod, + PCDBGFADDRESS pAddrProbe, DBGFFLOWTRACEPROBE hFlowTraceProbe, + PCDBGFFLOWTRACEPROBEENTRY pProbeEntry, + void *pvUser)); +/** Pointer to a flow trace probe callback. */ +typedef FNDBGFFLOWTRACEPROBECALLBACK *PFNDBGFFLOWTRACEPROBECALLBACK; + + +/** + * Trace flow probe entry. + */ +typedef struct DBGFFLOWTRACEPROBEENTRY +{ + /** Entry type. */ + DBGFFLOWTRACEPROBEENTRYTYPE enmType; + /** Description for this entry, optional. */ + const char *pszDesc; + /** The data based on the entry type. */ + union + { + /** Register. */ + DBGFFLOWTRACEPROBEENTRYREG Reg; + /** Constant memory pointer. */ + struct + { + /** The address of the memory buffer. */ + DBGFADDRESS AddrMem; + /** Number of bytes to log. */ + size_t cbMem; + } ConstMem; + /** Indirect memory */ + struct + { + /** The base register. */ + DBGFFLOWTRACEPROBEENTRYREG RegBase; + /** The index register. */ + DBGFFLOWTRACEPROBEENTRYREG RegIndex; + /** The scale to apply to the index. */ + uint8_t uScale; + /** A constant offset which is applied at the end. */ + RTGCINTPTR iOffset; + /** Number of bytes to log. */ + size_t cbMem; + } IndirectMem; + /** Callback. */ + struct + { + /** The callback to call. */ + PFNDBGFFLOWTRACEPROBECALLBACK pfnCallback; + /** The opaque user data to provide. */ + void *pvUser; + } Callback; + } Type; +} DBGFFLOWTRACEPROBEENTRY; + + +/** + * Flow trace probe value. + */ +typedef struct DBGFFLOWTRACEPROBEVAL +{ + /** Pointer to the flow trace probe entry this value is for. */ + PCDBGFFLOWTRACEPROBEENTRY pProbeEntry; + /** Data based on the type in the entry. */ + union + { + /** Register value. */ + DBGFREGENTRYNM Reg; + /** Memory value (constant pointer or indirect). */ + struct + { + /** The guest address logged. */ + DBGFADDRESS Addr; + /** Pointer to the data logged. */ + const void *pvBuf; + /** Number of bytes logged. */ + size_t cbBuf; + } Mem; + } Type; +} DBGFFLOWTRACEPROBEVAL; +/** Pointer to a flow trace probe value. */ +typedef DBGFFLOWTRACEPROBEVAL *PDBGFFLOWTRACEPROBEVAL; +/** Pointer to a const flow trace probe value. */ +typedef const DBGFFLOWTRACEPROBEVAL *PCDBGFFLOWTRACEPROBEVAL; + +/** + * Flow trace report filter operation. + */ +typedef enum DBGFFLOWTRACEREPORTFILTEROP +{ + /** Invalid filter operation. */ + DBGFFLOWTRACEREPORTFILTEROP_INVALID = 0, + /** All filters must match with the record. */ + DBGFFLOWTRACEREPORTFILTEROP_AND, + /** Only one filter must match with the record. */ + DBGFFLOWTRACEREPORTFILTEROP_OR, + /** 32bit hack. */ + DBGFFLOWTRACEREPORTFILTEROP_32BIT_HACK = 0x7fffffff +} DBGFFLOWTRACEREPORTFILTEROP; + + +/** + * Flow trace report filter type. + */ +typedef enum DBGFFLOWTRACEREPORTFILTERTYPE +{ + /** Invalid filter type. */ + DBGFFLOWTRACEREPORTFILTERTYPE_INVALID = 0, + /** Filter by sequence number. */ + DBGFFLOWTRACEREPORTFILTERTYPE_SEQ_NUM, + /** Filter by timestamp. */ + DBGFFLOWTRACEREPORTFILTERTYPE_TIMESTAMP, + /** Filter by probe address. */ + DBGFFLOWTRACEREPORTFILTERTYPE_ADDR, + /** Filter by CPU ID. */ + DBGFFLOWTRACEREPORTFILTERTYPE_VMCPU_ID, + /** Filter by specific probe data. */ + DBGFFLOWTRACEREPORTFILTERTYPE_PROBE_DATA, + /** 32bit hack. */ + DBGFFLOWTRACEREPORTFILTERTYPE_32BIT_HACK = 0x7fffffff +} DBGFFLOWTRACEREPORTFILTERTYPE; + + +/** + * Flow trace report filter. + */ +typedef struct DBGFFLOWTRACEREPORTFILTER +{ + /** Filter type. */ + DBGFFLOWTRACEREPORTFILTERTYPE enmType; + /** Filter data, type dependent. */ + struct + { + /** Sequence number filtering. */ + struct + { + /** Sequence number filtering, start value. */ + uint64_t u64SeqNoFirst; + /** Sequence number filtering, last value. */ + uint64_t u64SeqNoLast; + } SeqNo; + /** Timestamp filtering. */ + struct + { + /** Start value. */ + uint64_t u64TsFirst; + /** Last value. */ + uint64_t u64TsLast; + } Timestamp; + /** Probe address filtering. */ + struct + { + /** Start address. */ + DBGFADDRESS AddrStart; + /** Last address. */ + DBGFADDRESS AddrLast; + } Addr; + /** vCPU id filtering. */ + struct + { + /** Start CPU id. */ + VMCPUID idCpuStart; + /** Last CPU id. */ + VMCPUID idCpuLast; + } VCpuId; + /** Probe data filtering. */ + struct + { + /** Pointer to the probe value array. */ + PCDBGFFLOWTRACEPROBEVAL paVal; + /** Number of entries in the array for filtering. */ + uint32_t cVals; + /** Flag whether to look into the common values or the probe specific ones. */ + bool fValCmn; + } ProbeData; + } Type; +} DBGFFLOWTRACEREPORTFILTER; +/** Pointer to a flow trace report filter. */ +typedef DBGFFLOWTRACEREPORTFILTER *PDBGFFLOWTRACEREPORTFILTER; + + +/** @name Flags controlling filtering records. + * @{ */ +/** Add records which don't match the filter. */ +#define DBGF_FLOW_TRACE_REPORT_FILTER_F_REVERSE RT_BIT_32(0) +/** Mask of all valid flags. */ +#define DBGF_FLOW_TRACE_REPORT_FILTER_F_VALID (DBGF_FLOW_TRACE_REPORT_FILTER_F_REVERSE) +/** @} */ + + +/** + * Flow trace report enumeration callback. + * + * @returns VBox status code, any non VINF_SUCCESS code aborts the enumeration and is returned + * by DBGFR3FlowTraceReportEnumRecords(). + * @param hFlowTraceReport The flow trace report handle being enumerated. + * @param hFlowTraceRecord The flow trace record handle. + * @param pvUser Opaque user data given in DBGFR3FlowTraceReportEnumRecords(). + */ +typedef DECLCALLBACKTYPE(int, FNDBGFFLOWTRACEREPORTENUMCLBK,(DBGFFLOWTRACEREPORT hFlowTraceReport, + DBGFFLOWTRACERECORD hFlowTraceRecord, + void *pvUser)); +/** Pointer to a record enumeration callback. */ +typedef FNDBGFFLOWTRACEREPORTENUMCLBK *PFNDBGFFLOWTRACEREPORTENUMCLBK; + + +VMMR3DECL(int) DBGFR3FlowTraceModCreate(PUVM pUVM, VMCPUID idCpu, + DBGFFLOWTRACEPROBE hFlowTraceProbeCommon, + PDBGFFLOWTRACEMOD phFlowTraceMod); +VMMR3DECL(int) DBGFR3FlowTraceModCreateFromFlowGraph(PUVM pUVM, VMCPUID idCpu, DBGFFLOW hFlow, + DBGFFLOWTRACEPROBE hFlowTraceProbeCommon, + DBGFFLOWTRACEPROBE hFlowTraceProbeEntry, + DBGFFLOWTRACEPROBE hFlowTraceProbeRegular, + DBGFFLOWTRACEPROBE hFlowTraceProbeExit, + PDBGFFLOWTRACEMOD phFlowTraceMod); +VMMR3DECL(uint32_t) DBGFR3FlowTraceModRetain(DBGFFLOWTRACEMOD hFlowTraceMod); +VMMR3DECL(uint32_t) DBGFR3FlowTraceModRelease(DBGFFLOWTRACEMOD hFlowTraceMod); +VMMR3DECL(int) DBGFR3FlowTraceModEnable(DBGFFLOWTRACEMOD hFlowTraceMod, uint32_t cHits, uint32_t cRecordsMax); +VMMR3DECL(int) DBGFR3FlowTraceModDisable(DBGFFLOWTRACEMOD hFlowTraceMod); +VMMR3DECL(int) DBGFR3FlowTraceModQueryReport(DBGFFLOWTRACEMOD hFlowTraceMod, + PDBGFFLOWTRACEREPORT phFlowTraceReport); +VMMR3DECL(int) DBGFR3FlowTraceModClear(DBGFFLOWTRACEMOD hFlowTraceMod); +VMMR3DECL(int) DBGFR3FlowTraceModAddProbe(DBGFFLOWTRACEMOD hFlowTraceMod, PCDBGFADDRESS pAddrProbe, + DBGFFLOWTRACEPROBE hFlowTraceProbe, uint32_t fFlags); + +VMMR3DECL(int) DBGFR3FlowTraceProbeCreate(PUVM pUVM, const char *pszDescr, PDBGFFLOWTRACEPROBE phFlowTraceProbe); +VMMR3DECL(uint32_t) DBGFR3FlowTraceProbeRetain(DBGFFLOWTRACEPROBE hFlowTraceProbe); +VMMR3DECL(uint32_t) DBGFR3FlowTraceProbeRelease(DBGFFLOWTRACEPROBE hFlowTraceProbe); +VMMR3DECL(int) DBGFR3FlowTraceProbeEntriesAdd(DBGFFLOWTRACEPROBE hFlowTraceProbe, + PCDBGFFLOWTRACEPROBEENTRY paEntries, uint32_t cEntries); + +VMMR3DECL(uint32_t) DBGFR3FlowTraceReportRetain(DBGFFLOWTRACEREPORT hFlowTraceReport); +VMMR3DECL(uint32_t) DBGFR3FlowTraceReportRelease(DBGFFLOWTRACEREPORT hFlowTraceReport); +VMMR3DECL(uint32_t) DBGFR3FlowTraceReportGetRecordCount(DBGFFLOWTRACEREPORT hFlowTraceReport); +VMMR3DECL(int) DBGFR3FlowTraceReportQueryRecord(DBGFFLOWTRACEREPORT hFlowTraceReport, uint32_t idxRec, PDBGFFLOWTRACERECORD phFlowTraceRec); +VMMR3DECL(int) DBGFR3FlowTraceReportQueryFiltered(DBGFFLOWTRACEREPORT hFlowTraceReport, uint32_t fFlags, + PDBGFFLOWTRACEREPORTFILTER paFilters, uint32_t cFilters, + DBGFFLOWTRACEREPORTFILTEROP enmOp, + PDBGFFLOWTRACEREPORT phFlowTraceReportFiltered); +VMMR3DECL(int) DBGFR3FlowTraceReportEnumRecords(DBGFFLOWTRACEREPORT hFlowTraceReport, + PFNDBGFFLOWTRACEREPORTENUMCLBK pfnEnum, + void *pvUser); + +VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordRetain(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordRelease(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint64_t) DBGFR3FlowTraceRecordGetSeqNo(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint64_t) DBGFR3FlowTraceRecordGetTimestamp(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(PDBGFADDRESS) DBGFR3FlowTraceRecordGetAddr(DBGFFLOWTRACERECORD hFlowTraceRecord, PDBGFADDRESS pAddr); +VMMR3DECL(DBGFFLOWTRACEPROBE) DBGFR3FlowTraceRecordGetProbe(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordGetValCount(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(uint32_t) DBGFR3FlowTraceRecordGetValCommonCount(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(PCDBGFFLOWTRACEPROBEVAL) DBGFR3FlowTraceRecordGetVals(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(PCDBGFFLOWTRACEPROBEVAL) DBGFR3FlowTraceRecordGetValsCommon(DBGFFLOWTRACERECORD hFlowTraceRecord); +VMMR3DECL(VMCPUID) DBGFR3FlowTraceRecordGetCpuId(DBGFFLOWTRACERECORD hFlowTraceRecord); + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_dbgfflowtrace_h */ + diff --git a/include/VBox/vmm/dbgfsel.h b/include/VBox/vmm/dbgfsel.h new file mode 100644 index 00000000..a531ec6f --- /dev/null +++ b/include/VBox/vmm/dbgfsel.h @@ -0,0 +1,117 @@ +/** @file + * DBGF - Debugger Facility, selector interface partly shared with SELM. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgfsel_h +#define VBOX_INCLUDED_vmm_dbgfsel_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @addtogroup grp_dbgf + * @{ */ + +/** + * Selector information structure. + */ +typedef struct DBGFSELINFO +{ + /** The base address. + * For gate descriptors, this is the target address. */ + RTGCPTR GCPtrBase; + /** The limit (-1). + * For gate descriptors, this is set to zero. */ + RTGCUINTPTR cbLimit; + /** The raw descriptor. */ + union + { + X86DESC Raw; + X86DESC64 Raw64; + } u; + /** The selector. */ + RTSEL Sel; + /** The target selector for a gate. + * This is 0 if non-gate descriptor. */ + RTSEL SelGate; + /** Flags. */ + uint32_t fFlags; +} DBGFSELINFO; +/** Pointer to a SELM selector information struct. */ +typedef DBGFSELINFO *PDBGFSELINFO; +/** Pointer to a const SELM selector information struct. */ +typedef const DBGFSELINFO *PCDBGFSELINFO; + +/** @name DBGFSELINFO::fFlags + * @{ */ +/** The CPU is in real mode. */ +#define DBGFSELINFO_FLAGS_REAL_MODE RT_BIT_32(0) +/** The CPU is in protected mode. */ +#define DBGFSELINFO_FLAGS_PROT_MODE RT_BIT_32(1) +/** The CPU is in long mode. */ +#define DBGFSELINFO_FLAGS_LONG_MODE RT_BIT_32(2) +/** The selector is a hyper selector. + * @todo remove me! */ +#define DBGFSELINFO_FLAGS_HYPER RT_BIT_32(3) +/** The selector is a gate selector. */ +#define DBGFSELINFO_FLAGS_GATE RT_BIT_32(4) +/** The selector is invalid. */ +#define DBGFSELINFO_FLAGS_INVALID RT_BIT_32(5) +/** The selector not present. */ +#define DBGFSELINFO_FLAGS_NOT_PRESENT RT_BIT_32(6) +/** @} */ + + +/** + * Tests whether the selector info describes an expand-down selector or now. + * + * @returns true / false. + * @param pSelInfo The selector info. + */ +DECLINLINE(bool) DBGFSelInfoIsExpandDown(PCDBGFSELINFO pSelInfo) +{ + return (pSelInfo)->u.Raw.Gen.u1DescType + && ((pSelInfo)->u.Raw.Gen.u4Type & (X86_SEL_TYPE_DOWN | X86_SEL_TYPE_CODE)) == X86_SEL_TYPE_DOWN; +} + + +VMMR3DECL(int) DBGFR3SelInfoValidateCS(PCDBGFSELINFO pSelInfo, RTSEL SelCPL); + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_dbgfsel_h */ + diff --git a/include/VBox/vmm/dbgftrace.h b/include/VBox/vmm/dbgftrace.h new file mode 100644 index 00000000..254cc677 --- /dev/null +++ b/include/VBox/vmm/dbgftrace.h @@ -0,0 +1,168 @@ +/** @file + * DBGF - Debugger Facility. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_dbgftrace_h +#define VBOX_INCLUDED_vmm_dbgftrace_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN +/** @defgroup grp_dbgf_trace Tracing + * @ingroup grp_dbgf + * + * @{ + */ + +#if (defined(RTTRACE_ENABLED) || defined(DBGFTRACE_ENABLED)) && !defined(DBGFTRACE_DISABLED) +# undef DBGFTRACE_ENABLED +# undef DBGFTRACE_DISABLED +# define DBGFTRACE_ENABLED +#else +# undef DBGFTRACE_ENABLED +# undef DBGFTRACE_DISABLED +# define DBGFTRACE_DISABLED +#endif + +VMMDECL(int) DBGFR3TraceConfig(PVM pVM, const char *pszConfig); + + +/** @name VMM Internal Trace Macros + * @remarks The user of these macros is responsible of including VBox/vmm/vm.h. + * @{ + */ +/** + * Records a 64-bit unsigned integer together with a tag string. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_U64_TAG(a_pVM, a_u64, a_pszTag) \ + do { RTTraceBufAddMsgF((a_pVM)->CTX_SUFF(hTraceBuf), "%'llu %s", (a_u64), (a_pszTag)); } while (0) +#else +# define DBGFTRACE_U64_TAG(a_pVM, a_u64, a_pszTag) do { } while (0) +#endif + +/** + * Records a 64-bit unsigned integer together with two tag strings. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_U64_TAG2(a_pVM, a_u64, a_pszTag1, a_pszTag2) \ + do { RTTraceBufAddMsgF((a_pVM)->CTX_SUFF(hTraceBuf), "%'llu %s %s", (a_u64), (a_pszTag1), (a_pszTag2)); } while (0) +#else +# define DBGFTRACE_U64_TAG2(a_pVM, a_u64, a_pszTag1, a_pszTag2) do { } while (0) +#endif + +#ifdef RT_COMPILER_SUPPORTS_VA_ARGS +/** + * Add a custom string (req. variadict macro support). + */ +# ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_CUSTOM(a_pVM, ...) \ + do { RTTraceBufAddMsgF((a_pVM)->CTX_SUFF(hTraceBuf), __VA_ARGS__); } while (0) +# else +# define DBGFTRACE_CUSTOM(a_pVM, ...) do { } while (0) +# endif +#endif + +/** + * Records the current source position. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_POS(a_pVM) \ + do { RTTraceBufAddPos((a_pVM)->CTX_SUFF(hTraceBuf), RT_SRC_POS); } while (0) +#else +# define DBGFTRACE_POS(a_pVM) do { } while (0) +#endif + +/** + * Records the current source position along with a 64-bit unsigned integer. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_POS_U64(a_pVM, a_u64) \ + do { RTTraceBufAddPosMsgF((a_pVM)->CTX_SUFF(hTraceBuf), RT_SRC_POS, "%'llu", (a_u64)); } while (0) +#else +# define DBGFTRACE_POS_U64(a_pVM, a_u64) do { } while (0) +#endif +/** @} */ + + +/** @name Tracing Macros for PDM Devices, Drivers and USB Devices. + * @{ + */ + +/** + * Get the trace buffer handle. + * @param a_pIns The instance (pDevIns, pDrvIns or pUsbIns). + */ +#define DBGFTRACE_PDM_TRACEBUF(a_pIns) ( (a_pIns)->CTX_SUFF(pHlp)->pfnDBGFTraceBuf((a_pIns)) ) + +/** + * Records a tagged 64-bit unsigned integer. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_PDM_U64_TAG(a_pIns, a_u64, a_pszTag) \ + do { RTTraceBufAddMsgF(DBGFTRACE_PDM_TRACEBUF(a_pIns), "%'llu %s", (a_u64), (a_pszTag)); } while (0) +#else +# define DBGFTRACE_PDM_U64_TAG(a_pIns, a_u64, a_pszTag) do { } while (0) +#endif + +/** + * Records the current source position. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_PDM_POS(a_pIns) \ + do { RTTraceBufAddPos(DBGFTRACE_PDM_TRACEBUF(a_pIns), RT_SRC_POS); } while (0) +#else +# define DBGFTRACE_PDM_POS(a_pIns) do { } while (0) +#endif + +/** + * Records the current source position along with a 64-bit unsigned integer. + */ +#ifdef DBGFTRACE_ENABLED +# define DBGFTRACE_PDM_POS_U64(a_pIns, a_u64) \ + do { RTTraceBufAddPosMsgF(DBGFTRACE_PDM_TRACEBUF(a_pIns), RT_SRC_POS, "%'llu", (a_u64)); } while (0) +#else +# define DBGFTRACE_PDM_POS_U64(a_pIns, a_u64) do { } while (0) +#endif +/** @} */ + + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_dbgftrace_h */ diff --git a/include/VBox/vmm/em.h b/include/VBox/vmm/em.h new file mode 100644 index 00000000..6ea1b65e --- /dev/null +++ b/include/VBox/vmm/em.h @@ -0,0 +1,345 @@ +/** @file + * EM - Execution Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_em_h +#define VBOX_INCLUDED_vmm_em_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_em The Execution Monitor / Manager API + * @ingroup grp_vmm + * @{ + */ + +/** Enable to allow V86 code to run in raw mode. */ +#define VBOX_RAW_V86 + +/** + * The Execution Manager State. + * + * @remarks This is used in the saved state! + */ +typedef enum EMSTATE +{ + /** Not yet started. */ + EMSTATE_NONE = 1, + /** Raw-mode execution. */ + EMSTATE_RAW, + /** Hardware accelerated raw-mode execution. */ + EMSTATE_HM, + /** Executing in IEM. */ + EMSTATE_IEM, + /** Recompiled mode execution. */ + EMSTATE_REM, + /** Execution is halted. (waiting for interrupt) */ + EMSTATE_HALTED, + /** Application processor execution is halted. (waiting for startup IPI (SIPI)) */ + EMSTATE_WAIT_SIPI, + /** Execution is suspended. */ + EMSTATE_SUSPENDED, + /** The VM is terminating. */ + EMSTATE_TERMINATING, + /** Guest debug event from raw-mode is being processed. */ + EMSTATE_DEBUG_GUEST_RAW, + /** Guest debug event from hardware accelerated mode is being processed. */ + EMSTATE_DEBUG_GUEST_HM, + /** Guest debug event from interpreted execution mode is being processed. */ + EMSTATE_DEBUG_GUEST_IEM, + /** Guest debug event from recompiled-mode is being processed. */ + EMSTATE_DEBUG_GUEST_REM, + /** Hypervisor debug event being processed. */ + EMSTATE_DEBUG_HYPER, + /** The VM has encountered a fatal error. (And everyone is panicing....) */ + EMSTATE_GURU_MEDITATION, + /** Executing in IEM, falling back on REM if we cannot switch back to HM or + * RAW after a short while. */ + EMSTATE_IEM_THEN_REM, + /** Executing in native (API) execution monitor. */ + EMSTATE_NEM, + /** Guest debug event from NEM mode is being processed. */ + EMSTATE_DEBUG_GUEST_NEM, + /** Just a hack to ensure that we get a 32-bit integer. */ + EMSTATE_MAKE_32BIT_HACK = 0x7fffffff +} EMSTATE; + + +/** + * EMInterpretInstructionCPU execution modes. + */ +typedef enum +{ + /** Only supervisor code (CPL=0). */ + EMCODETYPE_SUPERVISOR, + /** User-level code only. */ + EMCODETYPE_USER, + /** Supervisor and user-level code (use with great care!). */ + EMCODETYPE_ALL, + /** Just a hack to ensure that we get a 32-bit integer. */ + EMCODETYPE_32BIT_HACK = 0x7fffffff +} EMCODETYPE; + +VMM_INT_DECL(EMSTATE) EMGetState(PVMCPU pVCpu); +VMM_INT_DECL(void) EMSetState(PVMCPU pVCpu, EMSTATE enmNewState); + +/** @name Callback handlers for instruction emulation functions. + * These are placed here because IOM wants to use them as well. + * @{ + */ +typedef DECLCALLBACKTYPE(uint32_t, FNEMULATEPARAM2UINT32,(void *pvParam1, uint64_t val2)); +typedef FNEMULATEPARAM2UINT32 *PFNEMULATEPARAM2UINT32; +typedef DECLCALLBACKTYPE(uint32_t, FNEMULATEPARAM2,(void *pvParam1, size_t val2)); +typedef FNEMULATEPARAM2 *PFNEMULATEPARAM2; +typedef DECLCALLBACKTYPE(uint32_t, FNEMULATEPARAM3,(void *pvParam1, uint64_t val2, size_t val3)); +typedef FNEMULATEPARAM3 *PFNEMULATEPARAM3; +typedef DECLCALLBACKTYPE(int, FNEMULATELOCKPARAM2,(void *pvParam1, uint64_t val2, RTGCUINTREG32 *pf)); +typedef FNEMULATELOCKPARAM2 *PFNEMULATELOCKPARAM2; +typedef DECLCALLBACKTYPE(int, FNEMULATELOCKPARAM3,(void *pvParam1, uint64_t val2, size_t cb, RTGCUINTREG32 *pf)); +typedef FNEMULATELOCKPARAM3 *PFNEMULATELOCKPARAM3; +/** @} */ + +VMMDECL(void) EMSetHypercallInstructionsEnabled(PVMCPU pVCpu, bool fEnabled); +VMMDECL(bool) EMAreHypercallInstructionsEnabled(PVMCPU pVCpu); +VMM_INT_DECL(bool) EMShouldContinueAfterHalt(PVMCPU pVCpu, PCPUMCTX pCtx); +VMM_INT_DECL(bool) EMMonitorWaitShouldContinue(PVMCPU pVCpu, PCPUMCTX pCtx); +VMM_INT_DECL(int) EMMonitorWaitPrepare(PVMCPU pVCpu, uint64_t rax, uint64_t rcx, uint64_t rdx, RTGCPHYS GCPhys); +VMM_INT_DECL(void) EMMonitorWaitClear(PVMCPU pVCpu); +VMM_INT_DECL(bool) EMMonitorIsArmed(PVMCPU pVCpu); +VMM_INT_DECL(unsigned) EMMonitorWaitIsActive(PVMCPU pVCpu); +VMM_INT_DECL(int) EMMonitorWaitPerform(PVMCPU pVCpu, uint64_t rax, uint64_t rcx); +VMM_INT_DECL(int) EMUnhaltAndWakeUp(PVMCC pVM, PVMCPUCC pVCpuDst); +VMMRZ_INT_DECL(VBOXSTRICTRC) EMRZSetPendingIoPortWrite(PVMCPU pVCpu, RTIOPORT uPort, uint8_t cbInstr, uint8_t cbValue, uint32_t uValue); +VMMRZ_INT_DECL(VBOXSTRICTRC) EMRZSetPendingIoPortRead(PVMCPU pVCpu, RTIOPORT uPort, uint8_t cbInstr, uint8_t cbValue); + +/** + * Common defined exit types that EM knows what to do about. + * + * These should be used instead of the VT-x, SVM or NEM specific ones for exits + * worth optimizing. + */ +typedef enum EMEXITTYPE +{ + EMEXITTYPE_INVALID = 0, + EMEXITTYPE_IO_PORT_READ, + EMEXITTYPE_IO_PORT_WRITE, + EMEXITTYPE_IO_PORT_STR_READ, + EMEXITTYPE_IO_PORT_STR_WRITE, + EMEXITTYPE_MMIO, + EMEXITTYPE_MMIO_READ, + EMEXITTYPE_MMIO_WRITE, + EMEXITTYPE_MSR_READ, + EMEXITTYPE_MSR_WRITE, + EMEXITTYPE_CPUID, + EMEXITTYPE_RDTSC, + EMEXITTYPE_MOV_CRX, + EMEXITTYPE_MOV_DRX, + EMEXITTYPE_VMREAD, + EMEXITTYPE_VMWRITE, + + /** @name Raw-mode only (for now), keep at end. + * @{ */ + EMEXITTYPE_INVLPG, + EMEXITTYPE_LLDT, + EMEXITTYPE_RDPMC, + EMEXITTYPE_CLTS, + EMEXITTYPE_STI, + EMEXITTYPE_INT, + EMEXITTYPE_SYSCALL, + EMEXITTYPE_SYSENTER, + EMEXITTYPE_HLT + /** @} */ +} EMEXITTYPE; +AssertCompileSize(EMEXITTYPE, 4); + +/** @name EMEXIT_F_XXX - EM exit flags. + * + * The flags the exit type are combined to a 32-bit number using the + * EMEXIT_MAKE_FT() macro. + * + * @{ */ +#define EMEXIT_F_TYPE_MASK UINT32_C(0x00000fff) /**< The exit type mask. */ +#define EMEXIT_F_KIND_EM UINT32_C(0x00000000) /**< EMEXITTYPE */ +#define EMEXIT_F_KIND_VMX UINT32_C(0x00001000) /**< VT-x exit codes. */ +#define EMEXIT_F_KIND_SVM UINT32_C(0x00002000) /**< SVM exit codes. */ +#define EMEXIT_F_KIND_NEM UINT32_C(0x00003000) /**< NEMEXITTYPE */ +#define EMEXIT_F_KIND_XCPT UINT32_C(0x00004000) /**< Exception numbers (raw-mode). */ +#define EMEXIT_F_KIND_MASK UINT32_C(0x00007000) +#define EMEXIT_F_CS_EIP UINT32_C(0x00010000) /**< The PC is EIP in the low dword and CS in the high. */ +#define EMEXIT_F_UNFLATTENED_PC UINT32_C(0x00020000) /**< The PC hasn't had CS.BASE added to it. */ +/** HM is calling (from ring-0). Preemption is currently disabled or we're using preemption hooks. */ +#define EMEXIT_F_HM UINT32_C(0x00040000) +/** Combines flags and exit type into EMHistoryAddExit() input. */ +#define EMEXIT_MAKE_FT(a_fFlags, a_uType) ((a_fFlags) | (uint32_t)(a_uType)) +/** @} */ + +typedef enum EMEXITACTION +{ + /** The record is free. */ + EMEXITACTION_FREE_RECORD = 0, + /** Take normal action on the exit. */ + EMEXITACTION_NORMAL, + /** Take normal action on the exit, already probed and found nothing. */ + EMEXITACTION_NORMAL_PROBED, + /** Do a probe execution. */ + EMEXITACTION_EXEC_PROBE, + /** Execute using EMEXITREC::cMaxInstructionsWithoutExit. */ + EMEXITACTION_EXEC_WITH_MAX +} EMEXITACTION; +AssertCompileSize(EMEXITACTION, 4); + +/** + * Accumulative exit record. + * + * This could perhaps be squeezed down a bit, but there isn't too much point. + * We'll probably need more data as time goes by. + */ +typedef struct EMEXITREC +{ + /** The flat PC of the exit. */ + uint64_t uFlatPC; + /** Flags and type, see EMEXIT_MAKE_FT. */ + uint32_t uFlagsAndType; + /** The action to take (EMEXITACTION). */ + uint8_t enmAction; + uint8_t bUnused; + /** Maximum number of instructions to execute without hitting an exit. */ + uint16_t cMaxInstructionsWithoutExit; + /** The exit number (EMCPU::iNextExit) at which it was last updated. */ + uint64_t uLastExitNo; + /** Number of hits. */ + uint64_t cHits; +} EMEXITREC; +AssertCompileSize(EMEXITREC, 32); +/** Pointer to an accumulative exit record. */ +typedef EMEXITREC *PEMEXITREC; +/** Pointer to a const accumulative exit record. */ +typedef EMEXITREC const *PCEMEXITREC; + +VMM_INT_DECL(PCEMEXITREC) EMHistoryAddExit(PVMCPUCC pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC, uint64_t uTimestamp); +#ifdef IN_RC +VMMRC_INT_DECL(void) EMRCHistoryAddExitCsEip(PVMCPU pVCpu, uint32_t uFlagsAndType, uint16_t uCs, uint32_t uEip, + uint64_t uTimestamp); +#endif +VMM_INT_DECL(void) EMHistoryUpdatePC(PVMCPUCC pVCpu, uint64_t uFlatPC, bool fFlattened); +VMM_INT_DECL(PCEMEXITREC) EMHistoryUpdateFlagsAndType(PVMCPUCC pVCpu, uint32_t uFlagsAndType); +VMM_INT_DECL(PCEMEXITREC) EMHistoryUpdateFlagsAndTypeAndPC(PVMCPUCC pVCpu, uint32_t uFlagsAndType, uint64_t uFlatPC); +VMM_INT_DECL(VBOXSTRICTRC) EMHistoryExec(PVMCPUCC pVCpu, PCEMEXITREC pExitRec, uint32_t fWillExit); + + +/** @name Deprecated interpretation related APIs (use IEM). + * @{ */ +VMM_INT_DECL(int) EMInterpretDisasCurrent(PVMCPUCC pVCpu, PDISCPUSTATE pCpu, unsigned *pcbInstr); +VMM_INT_DECL(int) EMInterpretDisasOneEx(PVMCPUCC pVCpu, RTGCUINTPTR GCPtrInstr, + PDISCPUSTATE pDISState, unsigned *pcbInstr); +VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstruction(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) EMInterpretInstructionDisasState(PVMCPUCC pVCpu, PDISCPUSTATE pDis, uint64_t rip); +/** @} */ + + +/** @name EM_ONE_INS_FLAGS_XXX - flags for EMR3HmSingleInstruction (et al). + * @{ */ +/** Return when CS:RIP changes or some other important event happens. + * This means running whole REP and LOOP $ sequences for instance. */ +#define EM_ONE_INS_FLAGS_RIP_CHANGE RT_BIT_32(0) +/** Mask of valid flags. */ +#define EM_ONE_INS_FLAGS_MASK UINT32_C(0x00000001) +/** @} */ + + +#ifdef IN_RING0 +/** @defgroup grp_em_r0 The EM Host Context Ring-0 API + * @{ */ +VMMR0_INT_DECL(int) EMR0InitVM(PGVM pGVM); +/** @} */ +#endif + + +#ifdef IN_RING3 +/** @defgroup grp_em_r3 The EM Host Context Ring-3 API + * @{ + */ + +/** + * Command argument for EMR3RawSetMode(). + * + * It's possible to extend this interface to change several + * execution modes at once should the need arise. + */ +typedef enum EMEXECPOLICY +{ + /** The customary invalid zero entry. */ + EMEXECPOLICY_INVALID = 0, + /** Whether to recompile ring-0 code or execute it in raw/hm. */ + EMEXECPOLICY_RECOMPILE_RING0, + /** Whether to recompile ring-3 code or execute it in raw/hm. */ + EMEXECPOLICY_RECOMPILE_RING3, + /** Whether to only use IEM for execution. */ + EMEXECPOLICY_IEM_ALL, + /** End of valid value (not included). */ + EMEXECPOLICY_END, + /** The customary 32-bit type blowup. */ + EMEXECPOLICY_32BIT_HACK = 0x7fffffff +} EMEXECPOLICY; +VMMR3DECL(int) EMR3SetExecutionPolicy(PUVM pUVM, EMEXECPOLICY enmPolicy, bool fEnforce); +VMMR3DECL(int) EMR3QueryExecutionPolicy(PUVM pUVM, EMEXECPOLICY enmPolicy, bool *pfEnforced); +VMMR3DECL(int) EMR3QueryMainExecutionEngine(PUVM pUVM, uint8_t *pbMainExecutionEngine); + +VMMR3_INT_DECL(int) EMR3Init(PVM pVM); +VMMR3_INT_DECL(int) EMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3_INT_DECL(void) EMR3Relocate(PVM pVM); +VMMR3_INT_DECL(void) EMR3ResetCpu(PVMCPU pVCpu); +VMMR3_INT_DECL(void) EMR3Reset(PVM pVM); +VMMR3_INT_DECL(int) EMR3Term(PVM pVM); +VMMR3DECL(DECL_NO_RETURN(void)) EMR3FatalError(PVMCPU pVCpu, int rc); +VMMR3_INT_DECL(int) EMR3ExecuteVM(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(int) EMR3CheckRawForcedActions(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(VBOXSTRICTRC) EMR3HmSingleInstruction(PVM pVM, PVMCPU pVCpu, uint32_t fFlags); + +/** @} */ +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_em_h */ + diff --git a/include/VBox/vmm/gcm.h b/include/VBox/vmm/gcm.h new file mode 100644 index 00000000..0b3102c7 --- /dev/null +++ b/include/VBox/vmm/gcm.h @@ -0,0 +1,95 @@ +/** @file + * GCM - Guest Compatibility Manager. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gcm_h +#define VBOX_INCLUDED_vmm_gcm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_gcm The Guest Compatibility Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * GCM Fixer Identifiers. + * @remarks Part of saved state! + */ +typedef enum GCMFIXERID +{ + /** None. */ + GCMFIXER_NONE = 0, + /** DOS division by zero, the worst. Includes Windows 3.x. */ + GCMFIXER_DBZ_DOS = RT_BIT(0), + /** OS/2 (any version) division by zero. */ + GCMFIXER_DBZ_OS2 = RT_BIT(1), + /** Windows 9x division by zero. */ + GCMFIXER_DBZ_WIN9X = RT_BIT(2), + /** 32-bit hack. */ + GCMFIXER_32BIT_HACK = 0x7fffffff +} GCMFIXERID; +AssertCompileSize(GCMFIXERID, sizeof(uint32_t)); + + +#ifdef IN_RING3 +/** @defgroup grp_gcm_r3 The GCM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) GCMR3Init(PVM pVM); +VMMR3_INT_DECL(void) GCMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) GCMR3Term(PVM pVM); +VMMR3_INT_DECL(void) GCMR3Reset(PVM pVM); +/** @} */ +#endif /* IN_RING3 */ + +VMMDECL(bool) GCMIsEnabled(PVM pVM); +VMM_INT_DECL(bool) GCMShouldTrapXcptDE(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) GCMXcptDE(PVMCPUCC pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr); +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_gcm_h */ + diff --git a/include/VBox/vmm/gim.h b/include/VBox/vmm/gim.h new file mode 100644 index 00000000..b62e1a1e --- /dev/null +++ b/include/VBox/vmm/gim.h @@ -0,0 +1,218 @@ +/** @file + * GIM - Guest Interface Manager. + */ + +/* + * Copyright (C) 2014-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gim_h +#define VBOX_INCLUDED_vmm_gim_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +#include +#include + +/** The value used to specify that VirtualBox must use the newest + * implementation version of the GIM provider. */ +#define GIM_VERSION_LATEST UINT32_C(0) + +RT_C_DECLS_BEGIN + +/** @defgroup grp_gim The Guest Interface Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * GIM Provider Identifiers. + * @remarks Part of saved state! + */ +typedef enum GIMPROVIDERID +{ + /** None. */ + GIMPROVIDERID_NONE = 0, + /** Minimal. */ + GIMPROVIDERID_MINIMAL, + /** Microsoft Hyper-V. */ + GIMPROVIDERID_HYPERV, + /** Linux KVM Interface. */ + GIMPROVIDERID_KVM +} GIMPROVIDERID; +AssertCompileSize(GIMPROVIDERID, sizeof(uint32_t)); + + +/** + * A GIM MMIO2 region record. + */ +typedef struct GIMMMIO2REGION +{ + /** The region index. */ + uint8_t iRegion; + /** Whether an RC mapping is required. */ + bool fRCMapping; + /** Whether this region has been registered. */ + bool fRegistered; + /** Whether this region is currently mapped. */ + bool fMapped; + /** Size of the region (must be page aligned). */ + uint32_t cbRegion; + /** The host ring-0 address of the first page in the region. */ + R0PTRTYPE(void *) pvPageR0; + /** The host ring-3 address of the first page in the region. */ + R3PTRTYPE(void *) pvPageR3; +# ifdef VBOX_WITH_RAW_MODE_KEEP + /** The ring-context address of the first page in the region. */ + RCPTRTYPE(void *) pvPageRC; + RTRCPTR RCPtrAlignment0; +# endif + /** The guest-physical address of the first page in the region. */ + RTGCPHYS GCPhysPage; + /** The MMIO2 handle. */ + PGMMMIO2HANDLE hMmio2; + /** The description of the region. */ + char szDescription[32]; +} GIMMMIO2REGION; +/** Pointer to a GIM MMIO2 region. */ +typedef GIMMMIO2REGION *PGIMMMIO2REGION; +/** Pointer to a const GIM MMIO2 region. */ +typedef GIMMMIO2REGION const *PCGIMMMIO2REGION; +AssertCompileMemberAlignment(GIMMMIO2REGION, pvPageR0, 8); +AssertCompileMemberAlignment(GIMMMIO2REGION, GCPhysPage, 8); + +/** + * Debug data buffer available callback over the GIM debug connection. + * + * @param pVM The cross context VM structure. + */ +typedef DECLCALLBACKTYPE(void, FNGIMDEBUGBUFAVAIL,(PVM pVM)); +/** Pointer to GIM debug buffer available callback. */ +typedef FNGIMDEBUGBUFAVAIL *PFNGIMDEBUGBUFAVAIL; + +/** + * GIM debug setup. + * + * These are parameters/options filled in by the GIM provider and passed along + * to the GIM device. + */ +typedef struct GIMDEBUGSETUP +{ + /** The callback to invoke when the receive buffer has data. */ + PFNGIMDEBUGBUFAVAIL pfnDbgRecvBufAvail; + /** The size of the receive buffer as specified by the GIM provider. */ + uint32_t cbDbgRecvBuf; +} GIMDEBUGSETUP; +/** Pointer to a GIM debug setup struct. */ +typedef struct GIMDEBUGSETUP *PGIMDEBUGSETUP; +/** Pointer to a const GIM debug setup struct. */ +typedef struct GIMDEBUGSETUP const *PCGGIMDEBUGSETUP; + +/** + * GIM debug structure (common to the GIM device and GIM). + * + * This is used to exchanging data between the GIM provider and the GIM device. + */ +typedef struct GIMDEBUG +{ + /** The receive buffer. */ + void *pvDbgRecvBuf; + /** The debug I/O stream driver. */ + PPDMISTREAM pDbgDrvStream; + /** Number of bytes pending to be read from the receive buffer. */ + size_t cbDbgRecvBufRead; + /** The flag synchronizing reads of the receive buffer from EMT. */ + volatile bool fDbgRecvBufRead; + /** The receive thread wakeup semaphore. */ + RTSEMEVENTMULTI hDbgRecvThreadSem; +} GIMDEBUG; +/** Pointer to a GIM debug struct. */ +typedef struct GIMDEBUG *PGIMDEBUG; +/** Pointer to a const GIM debug struct. */ +typedef struct GIMDEBUG const *PCGIMDEBUG; + + +#ifdef IN_RC +/** @defgroup grp_gim_rc The GIM Raw-mode Context API + * @{ + */ +/** @} */ +#endif /* IN_RC */ + +#ifdef IN_RING0 +/** @defgroup grp_gim_r0 The GIM Host Context Ring-0 API + * @{ + */ +VMMR0_INT_DECL(int) GIMR0InitVM(PVMCC pVM); +VMMR0_INT_DECL(int) GIMR0TermVM(PVMCC pVM); +VMMR0_INT_DECL(int) GIMR0UpdateParavirtTsc(PVMCC pVM, uint64_t u64Offset); +/** @} */ +#endif /* IN_RING0 */ + + +#ifdef IN_RING3 +/** @defgroup grp_gim_r3 The GIM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) GIMR3Init(PVM pVM); +VMMR3_INT_DECL(int) GIMR3InitCompleted(PVM pVM); +VMMR3_INT_DECL(void) GIMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) GIMR3Term(PVM pVM); +VMMR3_INT_DECL(void) GIMR3Reset(PVM pVM); +VMMR3DECL(void) GIMR3GimDeviceRegister(PVM pVM, PPDMDEVINS pDevInsR3, PGIMDEBUG pDbg); +VMMR3DECL(int) GIMR3GetDebugSetup(PVM pVM, PGIMDEBUGSETUP pDbgSetup); +/** @} */ +#endif /* IN_RING3 */ + +VMMDECL(bool) GIMIsEnabled(PVM pVM); +VMMDECL(GIMPROVIDERID) GIMGetProvider(PVM pVM); +VMMDECL(PGIMMMIO2REGION) GIMGetMmio2Regions(PVMCC pVM, uint32_t *pcRegions); +VMM_INT_DECL(bool) GIMIsParavirtTscEnabled(PVMCC pVM); +VMM_INT_DECL(bool) GIMAreHypercallsEnabled(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) GIMHypercall(PVMCPUCC pVCpu, PCPUMCTX pCtx); +VMM_INT_DECL(VBOXSTRICTRC) GIMHypercallEx(PVMCPUCC pVCpu, PCPUMCTX pCtx, unsigned uDisOpcode, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) GIMExecHypercallInstr(PVMCPUCC pVCpu, PCPUMCTX pCtx, uint8_t *pcbInstr); +VMM_INT_DECL(VBOXSTRICTRC) GIMXcptUD(PVMCPUCC pVCpu, PCPUMCTX pCtx, PDISCPUSTATE pDis, uint8_t *pcbInstr); +VMM_INT_DECL(bool) GIMShouldTrapXcptUD(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) GIMReadMsr(PVMCPUCC pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t *puValue); +VMM_INT_DECL(VBOXSTRICTRC) GIMWriteMsr(PVMCPUCC pVCpu, uint32_t idMsr, PCCPUMMSRRANGE pRange, uint64_t uValue, uint64_t uRawValue); +VMM_INT_DECL(int) GIMQueryHypercallOpcodeBytes(PVM pVM, void *pvBuf, size_t cbBuf, + size_t *pcbWritten, uint16_t *puDisOpcode); +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_gim_h */ + diff --git a/include/VBox/vmm/gmm.h b/include/VBox/vmm/gmm.h new file mode 100644 index 00000000..4839b737 --- /dev/null +++ b/include/VBox/vmm/gmm.h @@ -0,0 +1,828 @@ +/** @file + * GMM - The Global Memory Manager. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gmm_h +#define VBOX_INCLUDED_vmm_gmm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_gmm GMM - The Global Memory Manager + * @ingroup grp_vmm + * @{ + */ + +/** @def IN_GMM_R0 + * Used to indicate whether we're inside the same link module as the ring 0 + * part of the Global Memory Manager or not. + */ +#ifdef DOXYGEN_RUNNING +# define IN_GMM_R0 +#endif +/** @def GMMR0DECL + * Ring 0 GMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_GMM_R0 +# define GMMR0DECL(type) DECLEXPORT(type) VBOXCALL +#else +# define GMMR0DECL(type) DECLIMPORT(type) VBOXCALL +#endif + +/** @def IN_GMM_R3 + * Used to indicate whether we're inside the same link module as the ring 3 + * part of the Global Memory Manager or not. + */ +#ifdef DOXYGEN_RUNNING +# define IN_GMM_R3 +#endif +/** @def GMMR3DECL + * Ring 3 GMM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_GMM_R3 +# define GMMR3DECL(type) DECLEXPORT(type) VBOXCALL +#else +# define GMMR3DECL(type) DECLIMPORT(type) VBOXCALL +#endif + + +/** The chunk shift. (2^21 = 2 MB) */ +#define GMM_CHUNK_SHIFT 21 +/** The allocation chunk size. */ +#define GMM_CHUNK_SIZE (1U << GMM_CHUNK_SHIFT) +/** The allocation chunk size in (guest) pages. */ +#define GMM_CHUNK_NUM_PAGES (1U << (GMM_CHUNK_SHIFT - GUEST_PAGE_SHIFT)) +/** The shift factor for converting a page id into a chunk id. */ +#define GMM_CHUNKID_SHIFT (GMM_CHUNK_SHIFT - GUEST_PAGE_SHIFT) +/** The last valid Chunk ID value. */ +#define GMM_CHUNKID_LAST (GMM_PAGEID_LAST >> GMM_CHUNKID_SHIFT) +/** The last valid Page ID value. */ +#define GMM_PAGEID_LAST UINT32_C(0xfffffff0) +/** Mask out the page index from the Page ID. */ +#define GMM_PAGEID_IDX_MASK ((1U << GMM_CHUNKID_SHIFT) - 1) +/** The NIL Chunk ID value. */ +#define NIL_GMM_CHUNKID 0 +/** The NIL Page ID value. */ +#define NIL_GMM_PAGEID 0 + +#if 0 /* wrong - these are guest page pfns and not page ids! */ +/** Special Page ID used by unassigned pages. */ +#define GMM_PAGEID_UNASSIGNED 0x0fffffffU +/** Special Page ID used by unsharable pages. + * Like MMIO2, shadow and heap. This is for later, obviously. */ +#define GMM_PAGEID_UNSHARABLE 0x0ffffffeU +/** The end of the valid Page IDs. This is the first special one. */ +#define GMM_PAGEID_END 0x0ffffff0U +#endif + + +/** @def GMM_GCPHYS_LAST + * The last of the valid guest physical address as it applies to GMM pages. + * + * This must reflect the constraints imposed by the RTGCPHYS type and + * the guest page frame number used internally in GMMPAGE. + * + * @note Note this corresponds to GMM_PAGE_PFN_LAST. */ +#if HC_ARCH_BITS == 64 +# define GMM_GCPHYS_LAST UINT64_C(0x00000fffffff0000) /* 2^44 (16TB) - 0x10000 */ +#else +# define GMM_GCPHYS_LAST UINT64_C(0x0000000fffff0000) /* 2^36 (64GB) - 0x10000 */ +#endif + +/** + * Over-commitment policy. + */ +typedef enum GMMOCPOLICY +{ + /** The usual invalid 0 value. */ + GMMOCPOLICY_INVALID = 0, + /** No over-commitment, fully backed. + * The GMM guarantees that it will be able to allocate all of the + * guest RAM for a VM with OC policy. */ + GMMOCPOLICY_NO_OC, + /** to-be-determined. */ + GMMOCPOLICY_TBD, + /** The end of the valid policy range. */ + GMMOCPOLICY_END, + /** The usual 32-bit hack. */ + GMMOCPOLICY_32BIT_HACK = 0x7fffffff +} GMMOCPOLICY; + +/** + * VM / Memory priority. + */ +typedef enum GMMPRIORITY +{ + /** The usual invalid 0 value. */ + GMMPRIORITY_INVALID = 0, + /** High. + * When ballooning, ask these VMs last. + * When running out of memory, try not to interrupt these VMs. */ + GMMPRIORITY_HIGH, + /** Normal. + * When ballooning, don't wait to ask these. + * When running out of memory, pause, save and/or kill these VMs. */ + GMMPRIORITY_NORMAL, + /** Low. + * When ballooning, maximize these first. + * When running out of memory, save or kill these VMs. */ + GMMPRIORITY_LOW, + /** The end of the valid priority range. */ + GMMPRIORITY_END, + /** The custom 32-bit type blowup. */ + GMMPRIORITY_32BIT_HACK = 0x7fffffff +} GMMPRIORITY; + + +/** + * GMM Memory Accounts. + */ +typedef enum GMMACCOUNT +{ + /** The customary invalid zero entry. */ + GMMACCOUNT_INVALID = 0, + /** Account with the base allocations. */ + GMMACCOUNT_BASE, + /** Account with the shadow allocations. */ + GMMACCOUNT_SHADOW, + /** Account with the fixed allocations. */ + GMMACCOUNT_FIXED, + /** The end of the valid values. */ + GMMACCOUNT_END, + /** The usual 32-bit value to finish it off. */ + GMMACCOUNT_32BIT_HACK = 0x7fffffff +} GMMACCOUNT; + + +/** + * Balloon actions. + */ +typedef enum +{ + /** Invalid zero entry. */ + GMMBALLOONACTION_INVALID = 0, + /** Inflate the balloon. */ + GMMBALLOONACTION_INFLATE, + /** Deflate the balloon. */ + GMMBALLOONACTION_DEFLATE, + /** Puncture the balloon because of VM reset. */ + GMMBALLOONACTION_RESET, + /** End of the valid actions. */ + GMMBALLOONACTION_END, + /** hack forcing the size of the enum to 32-bits. */ + GMMBALLOONACTION_MAKE_32BIT_HACK = 0x7fffffff +} GMMBALLOONACTION; + + +/** + * A page descriptor for use when freeing pages. + * See GMMR0FreePages, GMMR0BalloonedPages. + */ +typedef struct GMMFREEPAGEDESC +{ + /** The Page ID of the page to be freed. */ + uint32_t idPage; +} GMMFREEPAGEDESC; +/** Pointer to a page descriptor for freeing pages. */ +typedef GMMFREEPAGEDESC *PGMMFREEPAGEDESC; + + +/** + * A page descriptor for use when updating and allocating pages. + * + * This is a bit complicated because we want to do as much as possible + * with the same structure. + */ +typedef struct GMMPAGEDESC +{ + /** The physical address of the page. + * + * @input GMMR0AllocateHandyPages expects the guest physical address + * to update the GMMPAGE structure with. Pass GMM_GCPHYS_UNSHAREABLE + * when appropriate and NIL_GMMPAGEDESC_PHYS when the page wasn't used + * for any specific guest address. + * + * GMMR0AllocatePage expects the guest physical address to put in + * the GMMPAGE structure for the page it allocates for this entry. + * Pass NIL_GMMPAGEDESC_PHYS and GMM_GCPHYS_UNSHAREABLE as above. + * + * @output The host physical address of the allocated page. + * NIL_GMMPAGEDESC_PHYS on allocation failure. + * + * ASSUMES: sizeof(RTHCPHYS) >= sizeof(RTGCPHYS) and that physical addresses are + * limited to 63 or fewer bits (52 by AMD64 arch spec). + */ + RT_GCC_EXTENSION + RTHCPHYS HCPhysGCPhys : 63; + /** Set if the memory was zeroed. */ + RT_GCC_EXTENSION + RTHCPHYS fZeroed : 1; + + /** The Page ID. + * + * @input GMMR0AllocateHandyPages expects the Page ID of the page to + * update here. NIL_GMM_PAGEID means no page should be updated. + * + * GMMR0AllocatePages requires this to be initialized to + * NIL_GMM_PAGEID currently. + * + * @output The ID of the page, NIL_GMM_PAGEID if the allocation failed. + */ + uint32_t idPage; + + /** The Page ID of the shared page was replaced by this page. + * + * @input GMMR0AllocateHandyPages expects this to indicate a shared + * page that has been replaced by this page and should have its + * reference counter decremented and perhaps be freed up. Use + * NIL_GMM_PAGEID if no shared page was involved. + * + * All other APIs expects NIL_GMM_PAGEID here. + * + * @output All APIs sets this to NIL_GMM_PAGEID. + */ + uint32_t idSharedPage; +} GMMPAGEDESC; +AssertCompileSize(GMMPAGEDESC, 16); +/** Pointer to a page allocation. */ +typedef GMMPAGEDESC *PGMMPAGEDESC; + +/** Special NIL value for GMMPAGEDESC::HCPhysGCPhys. */ +#define NIL_GMMPAGEDESC_PHYS UINT64_C(0x7fffffffffffffff) + +/** GMMPAGEDESC::HCPhysGCPhys value that indicates that the page is unsharable. + * @note This corresponds to GMM_PAGE_PFN_UNSHAREABLE. */ +#if HC_ARCH_BITS == 64 +# define GMM_GCPHYS_UNSHAREABLE UINT64_C(0x00000fffffff1000) +#else +# define GMM_GCPHYS_UNSHAREABLE UINT64_C(0x0000000fffff1000) +#endif + + +/** + * The allocation sizes. + */ +typedef struct GMMVMSIZES +{ + /** The number of pages of base memory. + * This is the sum of RAM, ROMs and handy pages. */ + uint64_t cBasePages; + /** The number of pages for the shadow pool. (Can be squeezed for memory.) */ + uint32_t cShadowPages; + /** The number of pages for fixed allocations like MMIO2 and the hyper heap. */ + uint32_t cFixedPages; +} GMMVMSIZES; +/** Pointer to a GMMVMSIZES. */ +typedef GMMVMSIZES *PGMMVMSIZES; + + +/** + * GMM VM statistics. + */ +typedef struct GMMVMSTATS +{ + /** The reservations. */ + GMMVMSIZES Reserved; + /** The actual allocations. + * This includes both private and shared page allocations. */ + GMMVMSIZES Allocated; + + /** The current number of private pages. */ + uint64_t cPrivatePages; + /** The current number of shared pages. */ + uint64_t cSharedPages; + /** The current number of ballooned pages. */ + uint64_t cBalloonedPages; + /** The max number of pages that can be ballooned. */ + uint64_t cMaxBalloonedPages; + /** The number of pages we've currently requested the guest to give us. + * This is 0 if no pages currently requested. */ + uint64_t cReqBalloonedPages; + /** The number of pages the guest has given us in response to the request. + * This is not reset on request completed and may be used in later decisions. */ + uint64_t cReqActuallyBalloonedPages; + /** The number of pages we've currently requested the guest to take back. */ + uint64_t cReqDeflatePages; + /** The number of shareable module tracked by this VM. */ + uint32_t cShareableModules; + + /** The current over-commitment policy. */ + GMMOCPOLICY enmPolicy; + /** The VM priority for arbitrating VMs in low and out of memory situation. + * Like which VMs to start squeezing first. */ + GMMPRIORITY enmPriority; + /** Whether ballooning is enabled or not. */ + bool fBallooningEnabled; + /** Whether shared paging is enabled or not. */ + bool fSharedPagingEnabled; + /** Whether the VM is allowed to allocate memory or not. + * This is used when the reservation update request fails or when the VM has + * been told to suspend/save/die in an out-of-memory case. */ + bool fMayAllocate; + /** Explicit alignment. */ + bool afReserved[1]; + + +} GMMVMSTATS; + + +/** + * The GMM statistics. + */ +typedef struct GMMSTATS +{ + /** The maximum number of pages we're allowed to allocate + * (GMM::cMaxPages). */ + uint64_t cMaxPages; + /** The number of pages that has been reserved (GMM::cReservedPages). */ + uint64_t cReservedPages; + /** The number of pages that we have over-committed in reservations + * (GMM::cOverCommittedPages). */ + uint64_t cOverCommittedPages; + /** The number of actually allocated (committed if you like) pages + * (GMM::cAllocatedPages). */ + uint64_t cAllocatedPages; + /** The number of pages that are shared. A subset of cAllocatedPages. + * (GMM::cSharedPages) */ + uint64_t cSharedPages; + /** The number of pages that are actually shared between VMs. + * (GMM:cDuplicatePages) */ + uint64_t cDuplicatePages; + /** The number of pages that are shared that has been left behind by + * VMs not doing proper cleanups (GMM::cLeftBehindSharedPages). */ + uint64_t cLeftBehindSharedPages; + /** The number of current ballooned pages (GMM::cBalloonedPages). */ + uint64_t cBalloonedPages; + /** The number of allocation chunks (GMM::cChunks). */ + uint32_t cChunks; + /** The number of freed chunks ever (GMM::cFreedChunks). */ + uint32_t cFreedChunks; + /** The number of shareable modules (GMM:cShareableModules). */ + uint64_t cShareableModules; + /** The current chunk freeing generation use by the per-VM TLB validation (GMM::idFreeGeneration). */ + uint64_t idFreeGeneration; + /** Space reserved for later. */ + uint64_t au64Reserved[1]; + + /** Statistics for the specified VM. (Zero filled if not requested.) */ + GMMVMSTATS VMStats; +} GMMSTATS; +/** Pointer to the GMM statistics. */ +typedef GMMSTATS *PGMMSTATS; +/** Const pointer to the GMM statistics. */ +typedef const GMMSTATS *PCGMMSTATS; + + +GMMR0DECL(int) GMMR0Init(void); +GMMR0DECL(void) GMMR0Term(void); +GMMR0DECL(int) GMMR0InitPerVMData(PGVM pGVM); +GMMR0DECL(void) GMMR0CleanupVM(PGVM pGVM); +GMMR0DECL(int) GMMR0InitialReservation(PGVM pGVM, VMCPUID idCpu, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages, + GMMOCPOLICY enmPolicy, GMMPRIORITY enmPriority); +GMMR0DECL(int) GMMR0UpdateReservation(PGVM pGVM, VMCPUID idCpu, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages); +GMMR0DECL(int) GMMR0AllocateHandyPages(PGVM pGVM, VMCPUID idCpu, uint32_t cPagesToUpdate, + uint32_t cPagesToAlloc, PGMMPAGEDESC paPages); +GMMR0DECL(int) GMMR0AllocatePages(PGVM pGVM, VMCPUID idCpu, uint32_t cPages, PGMMPAGEDESC paPages, GMMACCOUNT enmAccount); +GMMR0DECL(int) GMMR0AllocateLargePage(PGVM pGVM, VMCPUID idCpu, uint32_t cbPage, uint32_t *pIdPage, RTHCPHYS *pHCPhys); +GMMR0DECL(int) GMMR0FreePages(PGVM pGVM, VMCPUID idCpu, uint32_t cPages, PGMMFREEPAGEDESC paPages, GMMACCOUNT enmAccount); +GMMR0DECL(int) GMMR0FreeLargePage(PGVM pGVM, VMCPUID idCpu, uint32_t idPage); +GMMR0DECL(int) GMMR0BalloonedPages(PGVM pGVM, VMCPUID idCpu, GMMBALLOONACTION enmAction, uint32_t cBalloonedPages); +GMMR0DECL(int) GMMR0MapUnmapChunk(PGVM pGVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR ppvR3); +GMMR0DECL(int) GMMR0PageIdToVirt(PGVM pGVM, uint32_t idPage, void **ppv); +GMMR0DECL(int) GMMR0RegisterSharedModule(PGVM pGVM, VMCPUID idCpu, VBOXOSFAMILY enmGuestOS, char *pszModuleName, + char *pszVersion, RTGCPTR GCBaseAddr, uint32_t cbModule, uint32_t cRegions, + struct VMMDEVSHAREDREGIONDESC const *paRegions); +GMMR0DECL(int) GMMR0UnregisterSharedModule(PGVM pGVM, VMCPUID idCpu, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule); +GMMR0DECL(int) GMMR0UnregisterAllSharedModules(PGVM pGVM, VMCPUID idCpu); +GMMR0DECL(int) GMMR0CheckSharedModules(PGVM pGVM, VMCPUID idCpu); +GMMR0DECL(int) GMMR0ResetSharedModules(PGVM pGVM, VMCPUID idCpu); +GMMR0DECL(int) GMMR0QueryStatistics(PGMMSTATS pStats, PSUPDRVSESSION pSession); +GMMR0DECL(int) GMMR0ResetStatistics(PCGMMSTATS pStats, PSUPDRVSESSION pSession); + +/** + * Request buffer for GMMR0InitialReservationReq / VMMR0_DO_GMM_INITIAL_RESERVATION. + * @see GMMR0InitialReservation + */ +typedef struct GMMINITIALRESERVATIONREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + uint64_t cBasePages; /**< @see GMMR0InitialReservation */ + uint32_t cShadowPages; /**< @see GMMR0InitialReservation */ + uint32_t cFixedPages; /**< @see GMMR0InitialReservation */ + GMMOCPOLICY enmPolicy; /**< @see GMMR0InitialReservation */ + GMMPRIORITY enmPriority; /**< @see GMMR0InitialReservation */ +} GMMINITIALRESERVATIONREQ; +/** Pointer to a GMMR0InitialReservationReq / VMMR0_DO_GMM_INITIAL_RESERVATION request buffer. */ +typedef GMMINITIALRESERVATIONREQ *PGMMINITIALRESERVATIONREQ; + +GMMR0DECL(int) GMMR0InitialReservationReq(PGVM pGVM, VMCPUID idCpu, PGMMINITIALRESERVATIONREQ pReq); + + +/** + * Request buffer for GMMR0UpdateReservationReq / VMMR0_DO_GMM_UPDATE_RESERVATION. + * @see GMMR0UpdateReservation + */ +typedef struct GMMUPDATERESERVATIONREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + uint64_t cBasePages; /**< @see GMMR0UpdateReservation */ + uint32_t cShadowPages; /**< @see GMMR0UpdateReservation */ + uint32_t cFixedPages; /**< @see GMMR0UpdateReservation */ +} GMMUPDATERESERVATIONREQ; +/** Pointer to a GMMR0InitialReservationReq / VMMR0_DO_GMM_INITIAL_RESERVATION request buffer. */ +typedef GMMUPDATERESERVATIONREQ *PGMMUPDATERESERVATIONREQ; + +GMMR0DECL(int) GMMR0UpdateReservationReq(PGVM pGVM, VMCPUID idCpu, PGMMUPDATERESERVATIONREQ pReq); + + +/** + * Request buffer for GMMR0AllocatePagesReq / VMMR0_DO_GMM_ALLOCATE_PAGES. + * @see GMMR0AllocatePages. + */ +typedef struct GMMALLOCATEPAGESREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The account to charge the allocation to. */ + GMMACCOUNT enmAccount; + /** The number of pages to allocate. */ + uint32_t cPages; + /** Array of page descriptors. */ + GMMPAGEDESC aPages[1]; +} GMMALLOCATEPAGESREQ; +/** Pointer to a GMMR0AllocatePagesReq / VMMR0_DO_GMM_ALLOCATE_PAGES request buffer. */ +typedef GMMALLOCATEPAGESREQ *PGMMALLOCATEPAGESREQ; + +GMMR0DECL(int) GMMR0AllocatePagesReq(PGVM pGVM, VMCPUID idCpu, PGMMALLOCATEPAGESREQ pReq); + + +/** + * Request buffer for GMMR0FreePagesReq / VMMR0_DO_GMM_FREE_PAGES. + * @see GMMR0FreePages. + */ +typedef struct GMMFREEPAGESREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The account this relates to. */ + GMMACCOUNT enmAccount; + /** The number of pages to free. */ + uint32_t cPages; + /** Array of free page descriptors. */ + GMMFREEPAGEDESC aPages[1]; +} GMMFREEPAGESREQ; +/** Pointer to a GMMR0FreePagesReq / VMMR0_DO_GMM_FREE_PAGES request buffer. */ +typedef GMMFREEPAGESREQ *PGMMFREEPAGESREQ; + +GMMR0DECL(int) GMMR0FreePagesReq(PGVM pGVM, VMCPUID idCpu, PGMMFREEPAGESREQ pReq); + +/** + * Request buffer for GMMR0BalloonedPagesReq / VMMR0_DO_GMM_BALLOONED_PAGES. + * @see GMMR0BalloonedPages. + */ +typedef struct GMMBALLOONEDPAGESREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The number of ballooned pages. */ + uint32_t cBalloonedPages; + /** Inflate or deflate the balloon. */ + GMMBALLOONACTION enmAction; +} GMMBALLOONEDPAGESREQ; +/** Pointer to a GMMR0BalloonedPagesReq / VMMR0_DO_GMM_BALLOONED_PAGES request buffer. */ +typedef GMMBALLOONEDPAGESREQ *PGMMBALLOONEDPAGESREQ; + +GMMR0DECL(int) GMMR0BalloonedPagesReq(PGVM pGVM, VMCPUID idCpu, PGMMBALLOONEDPAGESREQ pReq); + + +/** + * Request buffer for GMMR0QueryHypervisorMemoryStatsReq / VMMR0_DO_GMM_QUERY_VMM_MEM_STATS. + * @see GMMR0QueryHypervisorMemoryStatsReq. + */ +typedef struct GMMMEMSTATSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The number of allocated pages (out). */ + uint64_t cAllocPages; + /** The number of free pages (out). */ + uint64_t cFreePages; + /** The number of ballooned pages (out). */ + uint64_t cBalloonedPages; + /** The number of shared pages (out). */ + uint64_t cSharedPages; + /** Maximum nr of pages (out). */ + uint64_t cMaxPages; +} GMMMEMSTATSREQ; +/** Pointer to a GMMR0QueryHypervisorMemoryStatsReq / VMMR0_DO_GMM_QUERY_HYPERVISOR_MEM_STATS request buffer. */ +typedef GMMMEMSTATSREQ *PGMMMEMSTATSREQ; + +GMMR0DECL(int) GMMR0QueryHypervisorMemoryStatsReq(PGMMMEMSTATSREQ pReq); +GMMR0DECL(int) GMMR0QueryMemoryStatsReq(PGVM pGVM, VMCPUID idCpu, PGMMMEMSTATSREQ pReq); + +/** + * Request buffer for GMMR0MapUnmapChunkReq / VMMR0_DO_GMM_MAP_UNMAP_CHUNK. + * @see GMMR0MapUnmapChunk + */ +typedef struct GMMMAPUNMAPCHUNKREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The chunk to map, NIL_GMM_CHUNKID if unmap only. (IN) */ + uint32_t idChunkMap; + /** The chunk to unmap, NIL_GMM_CHUNKID if map only. (IN) */ + uint32_t idChunkUnmap; + /** Where the mapping address is returned. (OUT) */ + RTR3PTR pvR3; +} GMMMAPUNMAPCHUNKREQ; +/** Pointer to a GMMR0MapUnmapChunkReq / VMMR0_DO_GMM_MAP_UNMAP_CHUNK request buffer. */ +typedef GMMMAPUNMAPCHUNKREQ *PGMMMAPUNMAPCHUNKREQ; + +GMMR0DECL(int) GMMR0MapUnmapChunkReq(PGVM pGVM, PGMMMAPUNMAPCHUNKREQ pReq); + + +/** + * Request buffer for GMMR0FreeLargePageReq / VMMR0_DO_GMM_FREE_LARGE_PAGE. + * @see GMMR0FreeLargePage. + */ +typedef struct GMMFREELARGEPAGEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The Page ID. */ + uint32_t idPage; +} GMMFREELARGEPAGEREQ; +/** Pointer to a GMMR0FreePagesReq / VMMR0_DO_GMM_FREE_PAGES request buffer. */ +typedef GMMFREELARGEPAGEREQ *PGMMFREELARGEPAGEREQ; + +GMMR0DECL(int) GMMR0FreeLargePageReq(PGVM pGVM, VMCPUID idCpu, PGMMFREELARGEPAGEREQ pReq); + +/** Maximum length of the shared module name string, terminator included. */ +#define GMM_SHARED_MODULE_MAX_NAME_STRING 128 +/** Maximum length of the shared module version string, terminator included. */ +#define GMM_SHARED_MODULE_MAX_VERSION_STRING 16 + +/** + * Request buffer for GMMR0RegisterSharedModuleReq / VMMR0_DO_GMM_REGISTER_SHARED_MODULE. + * @see GMMR0RegisterSharedModule. + */ +typedef struct GMMREGISTERSHAREDMODULEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Shared module size. */ + uint32_t cbModule; + /** Number of included region descriptors */ + uint32_t cRegions; + /** Base address of the shared module. */ + RTGCPTR64 GCBaseAddr; + /** Guest OS type. */ + VBOXOSFAMILY enmGuestOS; + /** return code. */ + uint32_t rc; + /** Module name */ + char szName[GMM_SHARED_MODULE_MAX_NAME_STRING]; + /** Module version */ + char szVersion[GMM_SHARED_MODULE_MAX_VERSION_STRING]; + /** Shared region descriptor(s). */ + VMMDEVSHAREDREGIONDESC aRegions[1]; +} GMMREGISTERSHAREDMODULEREQ; +/** Pointer to a GMMR0RegisterSharedModuleReq / VMMR0_DO_GMM_REGISTER_SHARED_MODULE request buffer. */ +typedef GMMREGISTERSHAREDMODULEREQ *PGMMREGISTERSHAREDMODULEREQ; + +GMMR0DECL(int) GMMR0RegisterSharedModuleReq(PGVM pGVM, VMCPUID idCpu, PGMMREGISTERSHAREDMODULEREQ pReq); + +/** + * Shared region descriptor + */ +typedef struct GMMSHAREDREGIONDESC +{ + /** The page offset where the region starts. */ + uint32_t off; + /** Region size - adjusted by the region offset and rounded up to a + * page. */ + uint32_t cb; + /** Pointer to physical GMM page ID array. */ + uint32_t *paidPages; +} GMMSHAREDREGIONDESC; +/** Pointer to a GMMSHAREDREGIONDESC. */ +typedef GMMSHAREDREGIONDESC *PGMMSHAREDREGIONDESC; + + +/** + * Shared module registration info (global) + */ +typedef struct GMMSHAREDMODULE +{ + /** Tree node (keyed by a hash of name & version). */ + AVLLU32NODECORE Core; + /** Shared module size. */ + uint32_t cbModule; + /** Number of included region descriptors */ + uint32_t cRegions; + /** Number of users (VMs). */ + uint32_t cUsers; + /** Guest OS family type. */ + VBOXOSFAMILY enmGuestOS; + /** Module name */ + char szName[GMM_SHARED_MODULE_MAX_NAME_STRING]; + /** Module version */ + char szVersion[GMM_SHARED_MODULE_MAX_VERSION_STRING]; + /** Shared region descriptor(s). */ + GMMSHAREDREGIONDESC aRegions[1]; +} GMMSHAREDMODULE; +/** Pointer to a GMMSHAREDMODULE. */ +typedef GMMSHAREDMODULE *PGMMSHAREDMODULE; + +/** + * Page descriptor for GMMR0SharedModuleCheckRange + */ +typedef struct GMMSHAREDPAGEDESC +{ + /** HC Physical address (in/out) */ + RTHCPHYS HCPhys; + /** GC Physical address (in) */ + RTGCPHYS GCPhys; + /** GMM page id. (in/out) */ + uint32_t idPage; + /** CRC32 of the page in strict builds (0 if page not available). + * In non-strict build this serves as structure alignment. */ + uint32_t u32StrictChecksum; +} GMMSHAREDPAGEDESC; +/** Pointer to a GMMSHAREDPAGEDESC. */ +typedef GMMSHAREDPAGEDESC *PGMMSHAREDPAGEDESC; + +GMMR0DECL(int) GMMR0SharedModuleCheckPage(PGVM pGVM, PGMMSHAREDMODULE pModule, uint32_t idxRegion, uint32_t idxPage, + PGMMSHAREDPAGEDESC pPageDesc); + +/** + * Request buffer for GMMR0UnregisterSharedModuleReq / VMMR0_DO_GMM_UNREGISTER_SHARED_MODULE. + * @see GMMR0UnregisterSharedModule. + */ +typedef struct GMMUNREGISTERSHAREDMODULEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Shared module size. */ + uint32_t cbModule; + /** Align at 8 byte boundary. */ + uint32_t u32Alignment; + /** Base address of the shared module. */ + RTGCPTR64 GCBaseAddr; + /** Module name */ + char szName[GMM_SHARED_MODULE_MAX_NAME_STRING]; + /** Module version */ + char szVersion[GMM_SHARED_MODULE_MAX_VERSION_STRING]; +} GMMUNREGISTERSHAREDMODULEREQ; +/** Pointer to a GMMR0UnregisterSharedModuleReq / VMMR0_DO_GMM_UNREGISTER_SHARED_MODULE request buffer. */ +typedef GMMUNREGISTERSHAREDMODULEREQ *PGMMUNREGISTERSHAREDMODULEREQ; + +GMMR0DECL(int) GMMR0UnregisterSharedModuleReq(PGVM pGVM, VMCPUID idCpu, PGMMUNREGISTERSHAREDMODULEREQ pReq); + +#if defined(VBOX_STRICT) && HC_ARCH_BITS == 64 +/** + * Request buffer for GMMR0FindDuplicatePageReq / VMMR0_DO_GMM_FIND_DUPLICATE_PAGE. + * @see GMMR0FindDuplicatePage. + */ +typedef struct GMMFINDDUPLICATEPAGEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Page id. */ + uint32_t idPage; + /** Duplicate flag (out) */ + bool fDuplicate; +} GMMFINDDUPLICATEPAGEREQ; +/** Pointer to a GMMR0FindDuplicatePageReq / VMMR0_DO_GMM_FIND_DUPLICATE_PAGE request buffer. */ +typedef GMMFINDDUPLICATEPAGEREQ *PGMMFINDDUPLICATEPAGEREQ; + +GMMR0DECL(int) GMMR0FindDuplicatePageReq(PGVM pGVM, PGMMFINDDUPLICATEPAGEREQ pReq); +#endif /* VBOX_STRICT && HC_ARCH_BITS == 64 */ + + +/** + * Request buffer for GMMR0QueryStatisticsReq / VMMR0_DO_GMM_QUERY_STATISTICS. + * @see GMMR0QueryStatistics. + */ +typedef struct GMMQUERYSTATISTICSSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. */ + PSUPDRVSESSION pSession; + /** The statistics. */ + GMMSTATS Stats; +} GMMQUERYSTATISTICSSREQ; +/** Pointer to a GMMR0QueryStatisticsReq / VMMR0_DO_GMM_QUERY_STATISTICS + * request buffer. */ +typedef GMMQUERYSTATISTICSSREQ *PGMMQUERYSTATISTICSSREQ; + +GMMR0DECL(int) GMMR0QueryStatisticsReq(PGVM pGVM, PGMMQUERYSTATISTICSSREQ pReq); + + +/** + * Request buffer for GMMR0ResetStatisticsReq / VMMR0_DO_GMM_RESET_STATISTICS. + * @see GMMR0ResetStatistics. + */ +typedef struct GMMRESETSTATISTICSSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. */ + PSUPDRVSESSION pSession; + /** The statistics to reset. + * Any non-zero entry will be reset (if permitted). */ + GMMSTATS Stats; +} GMMRESETSTATISTICSSREQ; +/** Pointer to a GMMR0ResetStatisticsReq / VMMR0_DO_GMM_RESET_STATISTICS + * request buffer. */ +typedef GMMRESETSTATISTICSSREQ *PGMMRESETSTATISTICSSREQ; + +GMMR0DECL(int) GMMR0ResetStatisticsReq(PGVM pGVM, PGMMRESETSTATISTICSSREQ pReq); + + + +#ifdef IN_RING3 +/** @defgroup grp_gmm_r3 The Global Memory Manager Ring-3 API Wrappers + * @{ + */ +GMMR3DECL(int) GMMR3InitialReservation(PVM pVM, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages, + GMMOCPOLICY enmPolicy, GMMPRIORITY enmPriority); +GMMR3DECL(int) GMMR3UpdateReservation(PVM pVM, uint64_t cBasePages, uint32_t cShadowPages, uint32_t cFixedPages); +GMMR3DECL(int) GMMR3AllocatePagesPrepare(PVM pVM, PGMMALLOCATEPAGESREQ *ppReq, uint32_t cPages, GMMACCOUNT enmAccount); +GMMR3DECL(int) GMMR3AllocatePagesPerform(PVM pVM, PGMMALLOCATEPAGESREQ pReq); +GMMR3DECL(void) GMMR3AllocatePagesCleanup(PGMMALLOCATEPAGESREQ pReq); +GMMR3DECL(int) GMMR3FreePagesPrepare(PVM pVM, PGMMFREEPAGESREQ *ppReq, uint32_t cPages, GMMACCOUNT enmAccount); +GMMR3DECL(void) GMMR3FreePagesRePrep(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t cPages, GMMACCOUNT enmAccount); +GMMR3DECL(int) GMMR3FreePagesPerform(PVM pVM, PGMMFREEPAGESREQ pReq, uint32_t cActualPages); +GMMR3DECL(void) GMMR3FreePagesCleanup(PGMMFREEPAGESREQ pReq); +GMMR3DECL(void) GMMR3FreeAllocatedPages(PVM pVM, GMMALLOCATEPAGESREQ const *pAllocReq); +GMMR3DECL(int) GMMR3AllocateLargePage(PVM pVM, uint32_t cbPage); +GMMR3DECL(int) GMMR3FreeLargePage(PVM pVM, uint32_t idPage); +GMMR3DECL(int) GMMR3MapUnmapChunk(PVM pVM, uint32_t idChunkMap, uint32_t idChunkUnmap, PRTR3PTR ppvR3); +GMMR3DECL(int) GMMR3QueryHypervisorMemoryStats(PVM pVM, uint64_t *pcTotalAllocPages, uint64_t *pcTotalFreePages, uint64_t *pcTotalBalloonPages, uint64_t *puTotalBalloonSize); +GMMR3DECL(int) GMMR3QueryMemoryStats(PVM pVM, uint64_t *pcAllocPages, uint64_t *pcMaxPages, uint64_t *pcBalloonPages); +GMMR3DECL(int) GMMR3BalloonedPages(PVM pVM, GMMBALLOONACTION enmAction, uint32_t cBalloonedPages); +GMMR3DECL(int) GMMR3RegisterSharedModule(PVM pVM, PGMMREGISTERSHAREDMODULEREQ pReq); +GMMR3DECL(int) GMMR3UnregisterSharedModule(PVM pVM, PGMMUNREGISTERSHAREDMODULEREQ pReq); +GMMR3DECL(int) GMMR3CheckSharedModules(PVM pVM); +GMMR3DECL(int) GMMR3ResetSharedModules(PVM pVM); + +# if defined(VBOX_STRICT) && HC_ARCH_BITS == 64 +GMMR3DECL(bool) GMMR3IsDuplicatePage(PVM pVM, uint32_t idPage); +# endif + +/** @} */ +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_gmm_h */ + diff --git a/include/VBox/vmm/gvm.h b/include/VBox/vmm/gvm.h new file mode 100644 index 00000000..8efdcc24 --- /dev/null +++ b/include/VBox/vmm/gvm.h @@ -0,0 +1,351 @@ +/* $Id: gvm.h $ */ +/** @file + * GVM - The Global VM Data. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gvm_h +#define VBOX_INCLUDED_vmm_gvm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef USING_VMM_COMMON_DEFS +# error "Compile job does not include VMM_COMMON_DEFS from src/VBox/Config.kmk - make sure you really need to include this file!" +#endif +#include +#include +#include +#include +#include + + +/** @defgroup grp_gvmcpu GVMCPU - The Global VMCPU Data + * @ingroup grp_vmm + * @{ + */ + +#if defined(__cplusplus) && !defined(GVM_C_STYLE_STRUCTURES) +typedef struct GVMCPU : public VMCPU +#else +typedef struct GVMCPU +#endif +{ +#if !defined(__cplusplus) || defined(GVM_C_STYLE_STRUCTURES) + VMCPU s; +#endif + + /** VCPU id (0 - (pVM->cCpus - 1). */ + VMCPUID idCpu; + /** Padding. */ + uint32_t uPadding0; + + /** Handle to the EMT thread. */ + RTNATIVETHREAD hEMT; + + /** Pointer to the global (ring-0) VM structure this CPU belongs to. */ + R0PTRTYPE(PGVM) pGVM; + /** Pointer to the GVM structure, for CTX_SUFF use in VMMAll code. */ + PGVM pVMR0; + /** The ring-3 address of this structure (only VMCPU part). */ + PVMCPUR3 pVCpuR3; + + /** Padding so the noisy stuff on a 64 byte boundrary. + * @note Keeping this working for 32-bit header syntax checking. */ + uint8_t abPadding1[HC_ARCH_BITS == 32 ? 40 : 24]; + + /** Which host CPU ID is this EMT running on. + * Only valid when in RC or HMR0 with scheduling disabled. */ + RTCPUID volatile idHostCpu; + /** The CPU set index corresponding to idHostCpu, UINT32_MAX if not valid. + * @remarks Best to make sure iHostCpuSet shares cache line with idHostCpu! */ + uint32_t volatile iHostCpuSet; + + /** Padding so gvmm starts on a 64 byte boundrary. + * @note Keeping this working for 32-bit header syntax checking. */ + uint8_t abPadding2[56]; + + /** The GVMM per vcpu data. */ + union + { +#ifdef VMM_INCLUDED_SRC_VMMR0_GVMMR0Internal_h + struct GVMMPERVCPU s; +#endif + uint8_t padding[256]; + } gvmm; + + /** The HM per vcpu data. */ + union + { +#if defined(VMM_INCLUDED_SRC_include_HMInternal_h) && defined(IN_RING0) + struct HMR0PERVCPU s; +#endif + uint8_t padding[1024]; + } hmr0; + +#ifdef VBOX_WITH_NEM_R0 + /** The NEM per vcpu data. */ + union + { +# if defined(VMM_INCLUDED_SRC_include_NEMInternal_h) && defined(IN_RING0) + struct NEMR0PERVCPU s; +# endif + uint8_t padding[64]; + } nemr0; +#endif + + union + { +#if defined(VMM_INCLUDED_SRC_include_VMMInternal_h) && defined(IN_RING0) + struct VMMR0PERVCPU s; +#endif + uint8_t padding[896]; + } vmmr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_PGMInternal_h) && defined(IN_RING0) + struct PGMR0PERVCPU s; +#endif + uint8_t padding[64]; + } pgmr0; + + /** Padding the structure size to page boundrary. */ +#ifdef VBOX_WITH_NEM_R0 + uint8_t abPadding3[16384 - 64*2 - 256 - 1024 - 64 - 896 - 64]; +#else + uint8_t abPadding3[16384 - 64*2 - 256 - 1024 - 896 - 64]; +#endif +} GVMCPU; +#if RT_GNUC_PREREQ(4, 6) && defined(__cplusplus) +# pragma GCC diagnostic push +#endif +#if RT_GNUC_PREREQ(4, 3) && defined(__cplusplus) +# pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif +AssertCompileMemberAlignment(GVMCPU, idCpu, 16384); +AssertCompileMemberAlignment(GVMCPU, gvmm, 64); +#ifdef VBOX_WITH_NEM_R0 +AssertCompileMemberAlignment(GVMCPU, nemr0, 64); +#endif +AssertCompileSizeAlignment(GVMCPU, 16384); +#if RT_GNUC_PREREQ(4, 6) && defined(__cplusplus) +# pragma GCC diagnostic pop +#endif + +/** @} */ + +/** @defgroup grp_gvm GVM - The Global VM Data + * @ingroup grp_vmm + * @{ + */ + +/** + * The Global VM Data. + * + * This is a ring-0 only structure where we put items we don't need to + * share with ring-3 or GC, like for instance various RTR0MEMOBJ handles. + * + * Unlike VM, there are no special alignment restrictions here. The + * paddings are checked by compile time assertions. + */ +#if defined(__cplusplus) && !defined(GVM_C_STYLE_STRUCTURES) +typedef struct GVM : public VM +#else +typedef struct GVM +#endif +{ +#if !defined(__cplusplus) || defined(GVM_C_STYLE_STRUCTURES) + VM s; +#endif + /** Magic / eye-catcher (GVM_MAGIC). */ + uint32_t u32Magic; + /** The global VM handle for this VM. */ + uint32_t hSelf; + /** Pointer to this structure (for validation purposes). */ + PGVM pSelf; + /** The ring-3 mapping of the VM structure. */ + PVMR3 pVMR3; + /** The support driver session the VM is associated with. */ + PSUPDRVSESSION pSession; + /** Number of Virtual CPUs, i.e. how many entries there are in aCpus. + * Same same as VM::cCpus. */ + uint32_t cCpus; + /** Padding so gvmm starts on a 64 byte boundrary. */ + uint8_t abPadding[HC_ARCH_BITS == 32 ? 12 + 28 : 28]; + + /** The GVMM per vm data. */ + union + { +#ifdef VMM_INCLUDED_SRC_VMMR0_GVMMR0Internal_h + struct GVMMPERVM s; +#endif + uint8_t padding[4352]; + } gvmm; + + /** The GMM per vm data. */ + union + { +#ifdef VMM_INCLUDED_SRC_VMMR0_GMMR0Internal_h + struct GMMPERVM s; +#endif + uint8_t padding[1024]; + } gmm; + + /** The HM per vm data. */ + union + { +#if defined(VMM_INCLUDED_SRC_include_HMInternal_h) && defined(IN_RING0) + struct HMR0PERVM s; +#endif + uint8_t padding[256]; + } hmr0; + +#ifdef VBOX_WITH_NEM_R0 + /** The NEM per vcpu data. */ + union + { +# if defined(VMM_INCLUDED_SRC_include_NEMInternal_h) && defined(IN_RING0) + struct NEMR0PERVM s; +# endif + uint8_t padding[256]; + } nemr0; +#endif + + /** The RAWPCIVM per vm data. */ + union + { +#ifdef VBOX_INCLUDED_rawpci_h + struct RAWPCIPERVM s; +#endif + uint8_t padding[64]; + } rawpci; + + union + { +#if defined(VMM_INCLUDED_SRC_include_PDMInternal_h) && defined(IN_RING0) + struct PDMR0PERVM s; +#endif + uint8_t padding[3008]; + } pdmr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_PGMInternal_h) && defined(IN_RING0) + struct PGMR0PERVM s; +#endif + uint8_t padding[1920]; + } pgmr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_IOMInternal_h) && defined(IN_RING0) + struct IOMR0PERVM s; +#endif + uint8_t padding[512]; + } iomr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_APICInternal_h) && defined(IN_RING0) + struct APICR0PERVM s; +#endif + uint8_t padding[64]; + } apicr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_DBGFInternal_h) && defined(IN_RING0) + struct DBGFR0PERVM s; +#endif + uint8_t padding[1024]; + } dbgfr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_TMInternal_h) && defined(IN_RING0) + TMR0PERVM s; +#endif + uint8_t padding[192]; + } tmr0; + + union + { +#if defined(VMM_INCLUDED_SRC_include_VMMInternal_h) && defined(IN_RING0) + VMMR0PERVM s; +#endif + uint8_t padding[704]; + } vmmr0; + + /** Padding so aCpus starts on a page boundrary. */ +#ifdef VBOX_WITH_NEM_R0 + uint8_t abPadding2[16384 - 64 - 4352 - 1024 - 256 - 256 - 64 - 3008 - 1920 - 512 - 64 - 1024 - 192 - 704 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT]; +#else + uint8_t abPadding2[16384 - 64 - 4352 - 1024 - 256 - 64 - 3008 - 1920 - 512 - 64 - 1024 - 192 - 704 - sizeof(PGVMCPU) * VMM_MAX_CPU_COUNT]; +#endif + + /** For simplifying CPU enumeration in VMMAll code. */ + PGVMCPU apCpusR0[VMM_MAX_CPU_COUNT]; + + /** GVMCPU array for the configured number of virtual CPUs. */ + GVMCPU aCpus[1]; +} GVM; +#if 0 +#if RT_GNUC_PREREQ(4, 6) && defined(__cplusplus) +# pragma GCC diagnostic push +#endif +#if RT_GNUC_PREREQ(4, 3) && defined(__cplusplus) +# pragma GCC diagnostic ignored "-Winvalid-offsetof" +#endif +AssertCompileMemberAlignment(GVM, u32Magic, 64); +AssertCompileMemberAlignment(GVM, gvmm, 64); +AssertCompileMemberAlignment(GVM, gmm, 64); +#ifdef VBOX_WITH_NEM_R0 +AssertCompileMemberAlignment(GVM, nemr0, 64); +#endif +AssertCompileMemberAlignment(GVM, rawpci, 64); +AssertCompileMemberAlignment(GVM, pdmr0, 64); +AssertCompileMemberAlignment(GVM, aCpus, 16384); +AssertCompileSizeAlignment(GVM, 16384); +#if RT_GNUC_PREREQ(4, 6) && defined(__cplusplus) +# pragma GCC diagnostic pop +#endif +#endif + +/** The GVM::u32Magic value (Wayne Shorter). */ +#define GVM_MAGIC 0x19330825 + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_gvm_h */ + diff --git a/include/VBox/vmm/gvm.mac b/include/VBox/vmm/gvm.mac new file mode 100644 index 00000000..af43f6ed --- /dev/null +++ b/include/VBox/vmm/gvm.mac @@ -0,0 +1,118 @@ +;; @file +; GVM - The Global VM Data. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_vmm_gvm_mac +%define ___VBox_vmm_gvm_mac + +%include "VBox/vmm/vm.mac" + +struc GVMCPU + .s resb VMCPU_size + + .idCpu resd 1 + + alignb 8 + .hEMT RTR0PTR_RES 1 + .pGVM RTR0PTR_RES 1 + .pVMR0 RTR0PTR_RES 1 + .pVCpuR3 RTR3PTR_RES 1 + + alignb 64 + .idHostCpu resd 1 + .iHostCpuSet resd 1 + + alignb 64 + .gvmm resb 256 + alignb 64 + .hmr0 resb 1024 +%ifdef VBOX_WITH_NEM_R0 + .nemr0 resb 64 +%endif + alignb 64 + .vmmr0 resb 896 + alignb 64 + .pgmr0 resb 64 + alignb 16384 +endstruc + + +struc GVM + .s resb VM_size + + .u32Magic resd 1 + .hSelf resd 1 + alignb 8 + .pSelf RTR0PTR_RES 1 + .pVMR3 RTR3PTR_RES 1 + .pSession RTR0PTR_RES 1 + .cCpus resd 1 + + alignb 64 + .gvmm resb 4352 + alignb 64 + .gmm resb 1024 + alignb 64 + .hmr0 resb 256 +%ifdef VBOX_WITH_NEM_R0 + alignb 64 + .nemr0 resb 256 +%endif + alignb 64 + .rawpci resb 64 + alignb 64 + .pdmr0 resb 3008 + alignb 64 + .pgmr0 resb 1920 + alignb 64 + .iomr0 resb 512 + alignb 64 + .apicr0 resb 64 + alignb 64 + .dbgfr0 resb 1024 + alignb 64 + .tmr0 resb 128 + + times ((($ + VMM_MAX_CPU_COUNT * RTR0PTR_CB + 16383) & ~16383) - ($ + VMM_MAX_CPU_COUNT * RTR0PTR_CB)) resb 1 + .apCpusR0 RTR0PTR_RES VMM_MAX_CPU_COUNT + + alignb 16384 + .aCpus resb GVMCPU_size +endstruc + +%define GVM_MAGIC 0x19330825 + + +%endif + diff --git a/include/VBox/vmm/gvmm.h b/include/VBox/vmm/gvmm.h new file mode 100644 index 00000000..788c41d4 --- /dev/null +++ b/include/VBox/vmm/gvmm.h @@ -0,0 +1,364 @@ +/* $Id: gvmm.h $ */ +/** @file + * GVMM - The Global VM Manager. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_gvmm_h +#define VBOX_INCLUDED_vmm_gvmm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include /* RTCPUSET_MAX_CPUS */ + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_gvmm GVMM - The Global VM Manager. + * @ingroup grp_vmm + * @{ + */ + +/** @def IN_GVMM_R0 + * Used to indicate whether we're inside the same link module as the ring 0 + * part of the Global VM Manager or not. + */ +#ifdef DOXYGEN_RUNNING +# define IN_GVMM_R0 +#endif +/** @def GVMMR0DECL + * Ring 0 VM export or import declaration. + * @param type The return type of the function declaration. + */ +#ifdef IN_GVMM_R0 +# define GVMMR0DECL(type) DECLEXPORT(type) VBOXCALL +#else +# define GVMMR0DECL(type) DECLIMPORT(type) VBOXCALL +#endif + +/** @def NIL_GVM_HANDLE + * The nil GVM VM handle value (VM::hSelf). + */ +#define NIL_GVM_HANDLE 0 + + +/** + * The scheduler statistics + */ +typedef struct GVMMSTATSSCHED +{ + /** The number of calls to GVMMR0SchedHalt. */ + uint64_t cHaltCalls; + /** The number of times we did go to sleep in GVMMR0SchedHalt. */ + uint64_t cHaltBlocking; + /** The number of times we timed out in GVMMR0SchedHalt. */ + uint64_t cHaltTimeouts; + /** The number of times we didn't go to sleep in GVMMR0SchedHalt. */ + uint64_t cHaltNotBlocking; + /** The number of wake ups done during GVMMR0SchedHalt. */ + uint64_t cHaltWakeUps; + + /** The number of calls to GVMMR0WakeUp. */ + uint64_t cWakeUpCalls; + /** The number of times the EMT thread wasn't actually halted when GVMMR0WakeUp + * was called. */ + uint64_t cWakeUpNotHalted; + /** The number of wake ups done during GVMMR0WakeUp (not counting the explicit + * one). */ + uint64_t cWakeUpWakeUps; + + /** The number of calls to GVMMR0Poke. */ + uint64_t cPokeCalls; + /** The number of times the EMT thread wasn't actually busy when + * GVMMR0Poke was called. */ + uint64_t cPokeNotBusy; + + /** The number of calls to GVMMR0SchedPoll. */ + uint64_t cPollCalls; + /** The number of times the EMT has halted in a GVMMR0SchedPoll call. */ + uint64_t cPollHalts; + /** The number of wake ups done during GVMMR0SchedPoll. */ + uint64_t cPollWakeUps; + + uint64_t u64Alignment; /**< padding */ +} GVMMSTATSSCHED; +/** Pointer to the GVMM scheduler statistics. */ +typedef GVMMSTATSSCHED *PGVMMSTATSSCHED; + +/** + * Per host cpu statistics. + */ +typedef struct GVMMSTATSHOSTCPU +{ + /** The CPU ID. */ + RTCPUID idCpu; + /** The CPU's set index. */ + uint32_t idxCpuSet; + /** The desired PPT frequency. */ + uint32_t uDesiredHz; + /** The current PPT timer frequency. */ + uint32_t uTimerHz; + /** The number of times the PPT was changed. */ + uint32_t cChanges; + /** The number of times the PPT was started. */ + uint32_t cStarts; +} GVMMSTATSHOSTCPU; +/** Pointer to the GVMM per host CPU statistics. */ +typedef GVMMSTATSHOSTCPU *PGVMMSTATSHOSTCPU; + +/** + * Per VCpu statistics + */ +typedef struct GVMMSTATSVMCPU +{ + uint32_t cWakeUpTimerHits; + uint32_t cWakeUpTimerMisses; + uint32_t cWakeUpTimerCanceled; + uint32_t cWakeUpTimerSameCpu; + STAMPROFILE Start; + STAMPROFILE Stop; +} GVMMSTATSVMCPU; +/** Ptoiner to the GVMM per VCpu statistics. */ +typedef GVMMSTATSVMCPU *PGVMMSTATSVMCPU; + +/** + * The GVMM statistics. + */ +typedef struct GVMMSTATS +{ + /** The VM statistics if a VM was specified. */ + GVMMSTATSSCHED SchedVM; + /** The sum statistics of all VMs accessible to the caller. */ + GVMMSTATSSCHED SchedSum; + /** The number of VMs accessible to the caller. */ + uint32_t cVMs; + /** The number of emulation threads in those VMs. */ + uint32_t cEMTs; + /** Padding. */ + uint32_t u32Padding; + /** The number of valid entries in aHostCpus. */ + uint32_t cHostCpus; + /** Per EMT statistics for the specified VM, zero if non specified. */ + GVMMSTATSVMCPU aVCpus[VMM_MAX_CPU_COUNT]; + /** Per host CPU statistics. */ + GVMMSTATSHOSTCPU aHostCpus[RTCPUSET_MAX_CPUS]; +} GVMMSTATS; +/** Pointer to the GVMM statistics. */ +typedef GVMMSTATS *PGVMMSTATS; +/** Const pointer to the GVMM statistics. */ +typedef const GVMMSTATS *PCGVMMSTATS; + +/** + * Per-VM callback for GVMMR0EnumVMs. + * + * @note This is called while holding the VM used list lock, so only suitable + * for quick and simple jobs! + * + * @returns VINF_SUCCESS to continue the enumeration, anything stops it and + * returns the status code. + * @param pGVM The VM + * @param pvUser The user parameter. + * */ +typedef DECLCALLBACKTYPE(int, FNGVMMR0ENUMCALLBACK,(PGVM pGVM, void *pvUser)); +/** Pointer to an VM enumeration callback function. */ +typedef FNGVMMR0ENUMCALLBACK *PFNGVMMR0ENUMCALLBACK; + +/** + * Worker thread IDs. + */ +typedef enum GVMMWORKERTHREAD +{ + /** The usual invalid zero value. */ + GVMMWORKERTHREAD_INVALID = 0, + /** PGM handy page allocator thread. */ + GVMMWORKERTHREAD_PGM_ALLOCATOR, + /** End of valid worker thread values. */ + GVMMWORKERTHREAD_END, + /** Make sure the type size is 32 bits. */ + GVMMWORKERTHREAD_32_BIT_HACK = 0x7fffffff +} GVMMWORKERTHREAD; + +GVMMR0DECL(int) GVMMR0Init(void); +GVMMR0DECL(void) GVMMR0Term(void); +GVMMR0DECL(int) GVMMR0SetConfig(PSUPDRVSESSION pSession, const char *pszName, uint64_t u64Value); +GVMMR0DECL(int) GVMMR0QueryConfig(PSUPDRVSESSION pSession, const char *pszName, uint64_t *pu64Value); + +GVMMR0DECL(int) GVMMR0CreateVM(PSUPDRVSESSION pSession, uint32_t cCpus, PVMCC *ppVM); +GVMMR0DECL(int) GVMMR0InitVM(PGVM pGVM); +GVMMR0DECL(void) GVMMR0DoneInitVM(PGVM pGVM); +GVMMR0DECL(bool) GVMMR0DoingTermVM(PGVM pGVM); +GVMMR0DECL(int) GVMMR0DestroyVM(PGVM pGVM); +GVMMR0DECL(int) GVMMR0RegisterVCpu(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0DeregisterVCpu(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0RegisterWorkerThread(PGVM pGVM, GVMMWORKERTHREAD enmWorker, RTNATIVETHREAD hThreadR3); +GVMMR0DECL(int) GVMMR0DeregisterWorkerThread(PGVM pGVM, GVMMWORKERTHREAD enmWorker); +GVMMR0DECL(PGVM) GVMMR0ByHandle(uint32_t hGVM); +GVMMR0DECL(int) GVMMR0ValidateGVM(PGVM pGVM); +GVMMR0DECL(int) GVMMR0ValidateGVMandEMT(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0ValidateGVMandEMTorWorker(PGVM pGVM, VMCPUID idCpu, GVMMWORKERTHREAD enmWorker); +GVMMR0DECL(PVMCC) GVMMR0GetVMByEMT(RTNATIVETHREAD hEMT); +GVMMR0DECL(PGVMCPU) GVMMR0GetGVCpuByEMT(RTNATIVETHREAD hEMT); +GVMMR0DECL(PGVMCPU) GVMMR0GetGVCpuByGVMandEMT(PGVM pGVM, RTNATIVETHREAD hEMT); +GVMMR0DECL(RTNATIVETHREAD) GVMMR0GetRing3ThreadForSelf(PGVM pGVM); +GVMMR0DECL(RTHCPHYS) GVMMR0ConvertGVMPtr2HCPhys(PGVM pGVM, void *pv); +GVMMR0DECL(int) GVMMR0SchedHalt(PGVM pGVM, PGVMCPU pGVCpu, uint64_t u64ExpireGipTime); +GVMMR0DECL(int) GVMMR0SchedHaltReq(PGVM pGVM, VMCPUID idCpu, uint64_t u64ExpireGipTime); +GVMMR0DECL(int) GVMMR0SchedWakeUp(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedWakeUpEx(PGVM pGVM, VMCPUID idCpu, bool fTakeUsedLock); +GVMMR0DECL(int) GVMMR0SchedWakeUpNoGVMNoLock(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedPoke(PGVM pGVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedPokeEx(PGVM pGVM, VMCPUID idCpu, bool fTakeUsedLock); +GVMMR0DECL(int) GVMMR0SchedPokeNoGVMNoLock(PVMCC pVM, VMCPUID idCpu); +GVMMR0DECL(int) GVMMR0SchedWakeUpAndPokeCpus(PGVM pGVM, PCVMCPUSET pSleepSet, PCVMCPUSET pPokeSet); +GVMMR0DECL(int) GVMMR0SchedPoll(PGVM pGVM, VMCPUID idCpu, bool fYield); +GVMMR0DECL(void) GVMMR0SchedUpdatePeriodicPreemptionTimer(PGVM pGVM, RTCPUID idHostCpu, uint32_t uHz); +GVMMR0DECL(int) GVMMR0EnumVMs(PFNGVMMR0ENUMCALLBACK pfnCallback, void *pvUser); +GVMMR0DECL(int) GVMMR0QueryStatistics(PGVMMSTATS pStats, PSUPDRVSESSION pSession, PGVM pGVM); +GVMMR0DECL(int) GVMMR0ResetStatistics(PCGVMMSTATS pStats, PSUPDRVSESSION pSession, PGVM pGVM); + + +/** + * Request packet for calling GVMMR0CreateVM. + */ +typedef struct GVMMCREATEVMREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. (IN) */ + PSUPDRVSESSION pSession; + /** Number of virtual CPUs for the new VM. (IN) */ + uint32_t cCpus; + /** Pointer to the ring-3 mapping of the shared VM structure on return. (OUT) */ + PVMR3 pVMR3; + /** Pointer to the ring-0 mapping of the shared VM structure on return. (OUT) */ + PVMR0 pVMR0; +} GVMMCREATEVMREQ; +/** Pointer to a GVMMR0CreateVM request packet. */ +typedef GVMMCREATEVMREQ *PGVMMCREATEVMREQ; + +GVMMR0DECL(int) GVMMR0CreateVMReq(PGVMMCREATEVMREQ pReq, PSUPDRVSESSION pSession); + + +/** + * Request packet for calling GVMMR0RegisterWorkerThread. + */ +typedef struct GVMMREGISTERWORKERTHREADREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** Ring-3 native thread handle of the caller. (IN) */ + RTNATIVETHREAD hNativeThreadR3; +} GVMMREGISTERWORKERTHREADREQ; +/** Pointer to a GVMMR0RegisterWorkerThread request packet. */ +typedef GVMMREGISTERWORKERTHREADREQ *PGVMMREGISTERWORKERTHREADREQ; + + +/** + * Request buffer for GVMMR0SchedWakeUpAndPokeCpusReq / VMMR0_DO_GVMM_SCHED_WAKE_UP_AND_POKE_CPUS. + * @see GVMMR0SchedWakeUpAndPokeCpus. + */ +typedef struct GVMMSCHEDWAKEUPANDPOKECPUSREQ /* nice and unreadable... */ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The sleeper set. */ + VMCPUSET SleepSet; + /** The set of virtual CPUs to poke. */ + VMCPUSET PokeSet; +} GVMMSCHEDWAKEUPANDPOKECPUSREQ; +/** Pointer to a GVMMR0QueryStatisticsReq / VMMR0_DO_GVMM_QUERY_STATISTICS request buffer. */ +typedef GVMMSCHEDWAKEUPANDPOKECPUSREQ *PGVMMSCHEDWAKEUPANDPOKECPUSREQ; + +GVMMR0DECL(int) GVMMR0SchedWakeUpAndPokeCpusReq(PGVM pGVM, PGVMMSCHEDWAKEUPANDPOKECPUSREQ pReq); + + +/** + * Request buffer for GVMMR0QueryStatisticsReq / VMMR0_DO_GVMM_QUERY_STATISTICS. + * @see GVMMR0QueryStatistics. + */ +typedef struct GVMMQUERYSTATISTICSSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. */ + PSUPDRVSESSION pSession; + /** The statistics. */ + GVMMSTATS Stats; +} GVMMQUERYSTATISTICSSREQ; +/** Pointer to a GVMMR0QueryStatisticsReq / VMMR0_DO_GVMM_QUERY_STATISTICS request buffer. */ +typedef GVMMQUERYSTATISTICSSREQ *PGVMMQUERYSTATISTICSSREQ; + +GVMMR0DECL(int) GVMMR0QueryStatisticsReq(PGVM pGVM, PGVMMQUERYSTATISTICSSREQ pReq, PSUPDRVSESSION pSession); + + +/** + * Request buffer for GVMMR0ResetStatisticsReq / VMMR0_DO_GVMM_RESET_STATISTICS. + * @see GVMMR0ResetStatistics. + */ +typedef struct GVMMRESETSTATISTICSSREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The support driver session. */ + PSUPDRVSESSION pSession; + /** The statistics to reset. + * Any non-zero entry will be reset (if permitted). */ + GVMMSTATS Stats; +} GVMMRESETSTATISTICSSREQ; +/** Pointer to a GVMMR0ResetStatisticsReq / VMMR0_DO_GVMM_RESET_STATISTICS request buffer. */ +typedef GVMMRESETSTATISTICSSREQ *PGVMMRESETSTATISTICSSREQ; + +GVMMR0DECL(int) GVMMR0ResetStatisticsReq(PGVM pGVM, PGVMMRESETSTATISTICSSREQ pReq, PSUPDRVSESSION pSession); + + +#ifdef IN_RING3 +VMMR3_INT_DECL(int) GVMMR3CreateVM(PUVM pUVM, uint32_t cCpus, PSUPDRVSESSION pSession, PVM *ppVM, PRTR0PTR ppVMR0); +VMMR3_INT_DECL(int) GVMMR3DestroyVM(PUVM pUVM, PVM pVM); +VMMR3_INT_DECL(int) GVMMR3RegisterVCpu(PVM pVM, VMCPUID idCpu); +VMMR3_INT_DECL(int) GVMMR3DeregisterVCpu(PVM pVM, VMCPUID idCpu); +VMMR3_INT_DECL(int) GVMMR3RegisterWorkerThread(PVM pVM, GVMMWORKERTHREAD enmWorker); +VMMR3_INT_DECL(int) GVMMR3DeregisterWorkerThread(PVM pVM, GVMMWORKERTHREAD enmWorker); +#endif + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_gvmm_h */ + diff --git a/include/VBox/vmm/hm.h b/include/VBox/vmm/hm.h new file mode 100644 index 00000000..2dc1d976 --- /dev/null +++ b/include/VBox/vmm/hm.h @@ -0,0 +1,336 @@ +/** @file + * HM - Intel/AMD VM Hardware Assisted Virtualization Manager (VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_hm_h +#define VBOX_INCLUDED_vmm_hm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + + +/** @defgroup grp_hm The Hardware Assisted Virtualization Manager API + * @ingroup grp_vmm + * @{ + */ + +RT_C_DECLS_BEGIN + +/** + * Checks whether HM (VT-x/AMD-V) is being used by this VM. + * + * @retval true if used. + * @retval false if software virtualization (raw-mode) or NEM is used. + * + * @param a_pVM The cross context VM structure. + * @deprecated Please use VM_IS_RAW_MODE_ENABLED, VM_IS_HM_OR_NEM_ENABLED, or + * VM_IS_HM_ENABLED instead. + * @internal + */ +#if defined(VBOX_STRICT) && defined(IN_RING3) +# define HMIsEnabled(a_pVM) HMIsEnabledNotMacro(a_pVM) +#else +# define HMIsEnabled(a_pVM) ((a_pVM)->fHMEnabled) +#endif + +/** + * Checks whether raw-mode context is required for HM purposes + * + * @retval true if required by HM for doing switching the cpu to 64-bit mode. + * @retval false if not required by HM. + * + * @param a_pVM The cross context VM structure. + * @internal + */ +#if HC_ARCH_BITS == 64 +# define HMIsRawModeCtxNeeded(a_pVM) (false) +#else +# define HMIsRawModeCtxNeeded(a_pVM) ((a_pVM)->fHMNeedRawModeCtx) +#endif + +/** + * Checks whether we're in the special hardware virtualization context. + * @returns true / false. + * @param a_pVCpu The caller's cross context virtual CPU structure. + * @thread EMT + */ +#ifdef IN_RING0 +# define HMIsInHwVirtCtx(a_pVCpu) (VMCPU_GET_STATE(a_pVCpu) == VMCPUSTATE_STARTED_HM) +#else +# define HMIsInHwVirtCtx(a_pVCpu) (false) +#endif + +/** + * Checks whether we're in the special hardware virtualization context and we + * cannot perform long jump without guru meditating and possibly messing up the + * host and/or guest state. + * + * This is after we've turned interrupts off and such. + * + * @returns true / false. + * @param a_pVCpu The caller's cross context virtual CPU structure. + * @thread EMT + */ +#ifdef IN_RING0 +# define HMIsInHwVirtNoLongJmpCtx(a_pVCpu) (VMCPU_GET_STATE(a_pVCpu) == VMCPUSTATE_STARTED_EXEC) +#else +# define HMIsInHwVirtNoLongJmpCtx(a_pVCpu) (false) +#endif + +/** @name All-context HM API. + * @{ */ +VMMDECL(bool) HMIsEnabledNotMacro(PVM pVM); +VMMDECL(bool) HMCanExecuteGuest(PVMCC pVM, PVMCPUCC pVCpu, PCCPUMCTX pCtx); +VMM_INT_DECL(int) HMInvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCVirt); +VMM_INT_DECL(bool) HMHasPendingIrq(PVMCC pVM); +VMM_INT_DECL(bool) HMSetSingleInstruction(PVMCC pVM, PVMCPUCC pVCpu, bool fEnable); +VMM_INT_DECL(bool) HMIsSvmActive(PVM pVM); +VMM_INT_DECL(bool) HMIsVmxActive(PVM pVM); +VMM_INT_DECL(const char *) HMGetVmxDiagDesc(VMXVDIAG enmDiag); +VMM_INT_DECL(const char *) HMGetVmxExitName(uint32_t uExit); +VMM_INT_DECL(const char *) HMGetSvmExitName(uint32_t uExit); +VMM_INT_DECL(void) HMDumpHwvirtVmxState(PVMCPU pVCpu); +VMM_INT_DECL(void) HMHCChangedPagingMode(PVM pVM, PVMCPUCC pVCpu, PGMMODE enmShadowMode, PGMMODE enmGuestMode); +VMM_INT_DECL(void) HMGetVmxMsrsFromHwvirtMsrs(PCSUPHWVIRTMSRS pMsrs, PVMXMSRS pVmxMsrs); +VMM_INT_DECL(void) HMGetSvmMsrsFromHwvirtMsrs(PCSUPHWVIRTMSRS pMsrs, PSVMMSRS pSvmMsrs); +/** @} */ + +/** @name All-context VMX helpers. + * + * These are hardware-assisted VMX functions (used by IEM/REM/CPUM and HM). Helpers + * based purely on the Intel VT-x specification (used by IEM/REM and HM) can be + * found in CPUM. + * @{ */ +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +VMM_INT_DECL(bool) HMIsSubjectToVmxPreemptTimerErratum(void); +#endif +VMM_INT_DECL(bool) HMCanExecuteVmxGuest(PVMCC pVM, PVMCPUCC pVCpu, PCCPUMCTX pCtx); +VMM_INT_DECL(TRPMEVENT) HMVmxEventTypeToTrpmEventType(uint32_t uIntInfo); +VMM_INT_DECL(uint32_t) HMTrpmEventTypeToVmxEventType(uint8_t uVector, TRPMEVENT enmTrpmEvent, bool fIcebp); +/** @} */ + +/** @name All-context SVM helpers. + * + * These are hardware-assisted SVM functions (used by IEM/REM/CPUM and HM). Helpers + * based purely on the AMD SVM specification (used by IEM/REM and HM) can be found + * in CPUM. + * @{ */ +VMM_INT_DECL(TRPMEVENT) HMSvmEventToTrpmEventType(PCSVMEVENT pSvmEvent, uint8_t uVector); +/** @} */ + +#ifndef IN_RC + +/** @name R0, R3 HM (VMX/SVM agnostic) handlers. + * @{ */ +VMM_INT_DECL(int) HMFlushTlb(PVMCPU pVCpu); +VMM_INT_DECL(int) HMFlushTlbOnAllVCpus(PVMCC pVM); +VMM_INT_DECL(int) HMInvalidatePageOnAllVCpus(PVMCC pVM, RTGCPTR GCVirt); +VMM_INT_DECL(int) HMInvalidatePhysPage(PVMCC pVM, RTGCPHYS GCPhys); +VMM_INT_DECL(bool) HMAreNestedPagingAndFullGuestExecEnabled(PVMCC pVM); +VMM_INT_DECL(bool) HMIsLongModeAllowed(PVMCC pVM); +VMM_INT_DECL(bool) HMIsNestedPagingActive(PVMCC pVM); +VMM_INT_DECL(bool) HMIsMsrBitmapActive(PVM pVM); +# ifdef VBOX_WITH_NESTED_HWVIRT_VMX +VMM_INT_DECL(void) HMNotifyVmxNstGstVmexit(PVMCPU pVCpu); +VMM_INT_DECL(void) HMNotifyVmxNstGstCurrentVmcsChanged(PVMCPU pVCpu); +# endif +/** @} */ + +/** @name R0, R3 SVM handlers. + * @{ */ +VMM_INT_DECL(bool) HMIsSvmVGifActive(PCVMCC pVM); +# ifdef VBOX_WITH_NESTED_HWVIRT_SVM +VMM_INT_DECL(void) HMNotifySvmNstGstVmexit(PVMCPUCC pVCpu, PCPUMCTX pCtx); +# endif +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +VMM_INT_DECL(int) HMIsSubjectToSvmErratum170(uint32_t *pu32Family, uint32_t *pu32Model, uint32_t *pu32Stepping); +# endif +VMM_INT_DECL(int) HMHCMaybeMovTprSvmHypercall(PVMCC pVM, PVMCPUCC pVCpu); +/** @} */ + +#else /* Nops in RC: */ + +/** @name RC HM (VMX/SVM agnostic) handlers. + * @{ */ +# define HMFlushTlb(pVCpu) do { } while (0) +# define HMFlushTlbOnAllVCpus(pVM) do { } while (0) +# define HMInvalidatePageOnAllVCpus(pVM, GCVirt) do { } while (0) +# define HMInvalidatePhysPage(pVM, GCVirt) do { } while (0) +# define HMAreNestedPagingAndFullGuestExecEnabled(pVM) false +# define HMIsLongModeAllowed(pVM) false +# define HMIsNestedPagingActive(pVM) false +# define HMIsMsrBitmapsActive(pVM) false +/** @} */ + +/** @name RC SVM handlers. + * @{ */ +# define HMIsSvmVGifActive(pVM) false +# define HMNotifySvmNstGstVmexit(pVCpu, pCtx) do { } while (0) +# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) +# define HMIsSubjectToSvmErratum170(puFamily, puModel, puStepping) false +# endif +# define HMHCMaybeMovTprSvmHypercall(pVM, pVCpu) do { } while (0) +/** @} */ + +#endif + +/** @name HMVMX_READ_XXX - Flags for reading auxiliary VM-exit VMCS fields. + * + * These flags allow reading VMCS fields that are not necessarily part of the + * guest-CPU state but are needed while handling VM-exits. + * + * @note If you add any fields here, make sure to update VMXR0GetExitAuxInfo. + * + * @{ + */ +#define HMVMX_READ_IDT_VECTORING_INFO RT_BIT_32(0) +#define HMVMX_READ_IDT_VECTORING_ERROR_CODE RT_BIT_32(1) +#define HMVMX_READ_EXIT_QUALIFICATION RT_BIT_32(2) +#define HMVMX_READ_EXIT_INSTR_LEN RT_BIT_32(3) +#define HMVMX_READ_EXIT_INTERRUPTION_INFO RT_BIT_32(4) +#define HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE RT_BIT_32(5) +#define HMVMX_READ_EXIT_INSTR_INFO RT_BIT_32(6) +#define HMVMX_READ_GUEST_LINEAR_ADDR RT_BIT_32(7) +#define HMVMX_READ_GUEST_PHYSICAL_ADDR RT_BIT_32(8) +#define HMVMX_READ_GUEST_PENDING_DBG_XCPTS RT_BIT_32(9) + +/** All the VMCS fields required for processing of exception/NMI VM-exits. */ +#define HMVMX_READ_XCPT_INFO ( HMVMX_READ_EXIT_INTERRUPTION_INFO \ + | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE \ + | HMVMX_READ_EXIT_INSTR_LEN \ + | HMVMX_READ_IDT_VECTORING_INFO \ + | HMVMX_READ_IDT_VECTORING_ERROR_CODE) + +/** Mask of all valid HMVMX_READ_XXX flags. */ +#define HMVMX_READ_VALID_MASK ( HMVMX_READ_IDT_VECTORING_INFO \ + | HMVMX_READ_IDT_VECTORING_ERROR_CODE \ + | HMVMX_READ_EXIT_QUALIFICATION \ + | HMVMX_READ_EXIT_INSTR_LEN \ + | HMVMX_READ_EXIT_INTERRUPTION_INFO \ + | HMVMX_READ_EXIT_INTERRUPTION_ERROR_CODE \ + | HMVMX_READ_EXIT_INSTR_INFO \ + | HMVMX_READ_GUEST_LINEAR_ADDR \ + | HMVMX_READ_GUEST_PHYSICAL_ADDR \ + | HMVMX_READ_GUEST_PENDING_DBG_XCPTS) +/** @} */ + +#ifdef IN_RING0 +/** @defgroup grp_hm_r0 The HM ring-0 Context API + * @{ + */ +/** + * HM VM-exit auxiliary info. + */ +typedef union +{ + /** VMX VM-exit auxiliary info. */ + VMXEXITAUX Vmx; + /** SVM \#VMEXIT auxiliary info. */ + SVMEXITAUX Svm; +} HMEXITAUX; +/** Pointer to HM-exit auxiliary info union. */ +typedef HMEXITAUX *PHMEXITAUX; +/** Pointer to a const HM-exit auxiliary info union. */ +typedef const HMEXITAUX *PCHMEXITAUX; + +VMMR0_INT_DECL(int) HMR0Init(void); +VMMR0_INT_DECL(int) HMR0Term(void); +VMMR0_INT_DECL(int) HMR0InitVM(PVMCC pVM); +VMMR0_INT_DECL(int) HMR0TermVM(PVMCC pVM); +VMMR0_INT_DECL(int) HMR0EnableAllCpus(PVMCC pVM); +# ifdef VBOX_WITH_RAW_MODE +VMMR0_INT_DECL(int) HMR0EnterSwitcher(PVMCC pVM, VMMSWITCHER enmSwitcher, bool *pfVTxDisabled); +VMMR0_INT_DECL(void) HMR0LeaveSwitcher(PVMCC pVM, bool fVTxDisabled); +# endif + +VMMR0_INT_DECL(int) HMR0SetupVM(PVMCC pVM); +VMMR0_INT_DECL(int) HMR0RunGuestCode(PVMCC pVM, PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) HMR0Enter(PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) HMR0LeaveCpu(PVMCPUCC pVCpu); +VMMR0_INT_DECL(void) HMR0ThreadCtxCallback(RTTHREADCTXEVENT enmEvent, void *pvUser); +VMMR0_INT_DECL(void) HMR0NotifyCpumUnloadedGuestFpuState(PVMCPUCC VCpu); +VMMR0_INT_DECL(void) HMR0NotifyCpumModifiedHostCr0(PVMCPUCC VCpu); +VMMR0_INT_DECL(bool) HMR0SuspendPending(void); +VMMR0_INT_DECL(int) HMR0InvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCVirt); +VMMR0_INT_DECL(int) HMR0ImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat); +VMMR0_INT_DECL(int) HMR0GetExitAuxInfo(PVMCPUCC pVCpu, PHMEXITAUX pHmExitAux, uint32_t fWhat); +/** @} */ +#endif /* IN_RING0 */ + + +#ifdef IN_RING3 +/** @defgroup grp_hm_r3 The HM ring-3 Context API + * @{ + */ +VMMR3DECL(bool) HMR3IsEnabled(PUVM pUVM); +VMMR3DECL(bool) HMR3IsNestedPagingActive(PUVM pUVM); +VMMR3DECL(bool) HMR3AreVirtApicRegsEnabled(PUVM pUVM); +VMMR3DECL(bool) HMR3IsPostedIntrsEnabled(PUVM pUVM); +VMMR3DECL(bool) HMR3IsVpidActive(PUVM pUVM); +VMMR3DECL(bool) HMR3IsUXActive(PUVM pUVM); +VMMR3DECL(bool) HMR3IsSvmEnabled(PUVM pUVM); +VMMR3DECL(bool) HMR3IsVmxEnabled(PUVM pUVM); + +VMMR3_INT_DECL(int) HMR3Init(PVM pVM); +VMMR3_INT_DECL(int) HMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3_INT_DECL(void) HMR3Relocate(PVM pVM); +VMMR3_INT_DECL(int) HMR3Term(PVM pVM); +VMMR3_INT_DECL(void) HMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) HMR3ResetCpu(PVMCPU pVCpu); +VMMR3_INT_DECL(void) HMR3CheckError(PVM pVM, int iStatusCode); +VMMR3_INT_DECL(void) HMR3NotifyDebugEventChanged(PVM pVM); +VMMR3_INT_DECL(void) HMR3NotifyDebugEventChangedPerCpu(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(bool) HMR3IsActive(PCVMCPU pVCpu); +VMMR3_INT_DECL(int) HMR3EnablePatching(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3_INT_DECL(int) HMR3DisablePatching(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3_INT_DECL(int) HMR3PatchTprInstr(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(bool) HMR3IsRescheduleRequired(PVM pVM, PCCPUMCTX pCtx); +VMMR3_INT_DECL(bool) HMR3IsVmxPreemptionTimerUsed(PVM pVM); +/** @} */ +#endif /* IN_RING3 */ + +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_hm_h */ + diff --git a/include/VBox/vmm/hm_svm.h b/include/VBox/vmm/hm_svm.h new file mode 100644 index 00000000..403480c5 --- /dev/null +++ b/include/VBox/vmm/hm_svm.h @@ -0,0 +1,1169 @@ +/** @file + * HM - SVM (AMD-V) Structures and Definitions. (VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_hm_svm_h +#define VBOX_INCLUDED_vmm_hm_svm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +#ifdef RT_OS_SOLARIS +# undef ES +# undef CS +# undef DS +# undef SS +# undef FS +# undef GS +#endif + +/** @defgroup grp_hm_svm SVM (AMD-V) Types and Definitions + * @ingroup grp_hm + * @{ + */ + +/** @name SVM generic / convenient defines. + * @{ + */ +/** Number of pages required for the VMCB. */ +#define SVM_VMCB_PAGES 1 +/** Number of pages required for the MSR permission bitmap. */ +#define SVM_MSRPM_PAGES 2 +/** Number of pages required for the IO permission bitmap. */ +#define SVM_IOPM_PAGES 3 +/** @} */ + +/* + * Ugly! + * When compiling the recompiler, its own svm.h defines clash with + * the following defines. Avoid just the duplicates here as we still + * require other definitions and structures in this header. + */ +#ifndef IN_REM_R3 +/** @name SVM_EXIT_XXX - SVM Basic Exit Reasons. + * @{ + */ +/** Invalid guest state in VMCB. */ +# define SVM_EXIT_INVALID (uint64_t)(-1) +/** Read from CR0-CR15. */ +# define SVM_EXIT_READ_CR0 0x0 +# define SVM_EXIT_READ_CR1 0x1 +# define SVM_EXIT_READ_CR2 0x2 +# define SVM_EXIT_READ_CR3 0x3 +# define SVM_EXIT_READ_CR4 0x4 +# define SVM_EXIT_READ_CR5 0x5 +# define SVM_EXIT_READ_CR6 0x6 +# define SVM_EXIT_READ_CR7 0x7 +# define SVM_EXIT_READ_CR8 0x8 +# define SVM_EXIT_READ_CR9 0x9 +# define SVM_EXIT_READ_CR10 0xa +# define SVM_EXIT_READ_CR11 0xb +# define SVM_EXIT_READ_CR12 0xc +# define SVM_EXIT_READ_CR13 0xd +# define SVM_EXIT_READ_CR14 0xe +# define SVM_EXIT_READ_CR15 0xf +/** Writes to CR0-CR15. */ +# define SVM_EXIT_WRITE_CR0 0x10 +# define SVM_EXIT_WRITE_CR1 0x11 +# define SVM_EXIT_WRITE_CR2 0x12 +# define SVM_EXIT_WRITE_CR3 0x13 +# define SVM_EXIT_WRITE_CR4 0x14 +# define SVM_EXIT_WRITE_CR5 0x15 +# define SVM_EXIT_WRITE_CR6 0x16 +# define SVM_EXIT_WRITE_CR7 0x17 +# define SVM_EXIT_WRITE_CR8 0x18 +# define SVM_EXIT_WRITE_CR9 0x19 +# define SVM_EXIT_WRITE_CR10 0x1a +# define SVM_EXIT_WRITE_CR11 0x1b +# define SVM_EXIT_WRITE_CR12 0x1c +# define SVM_EXIT_WRITE_CR13 0x1d +# define SVM_EXIT_WRITE_CR14 0x1e +# define SVM_EXIT_WRITE_CR15 0x1f +/** Read from DR0-DR15. */ +# define SVM_EXIT_READ_DR0 0x20 +# define SVM_EXIT_READ_DR1 0x21 +# define SVM_EXIT_READ_DR2 0x22 +# define SVM_EXIT_READ_DR3 0x23 +# define SVM_EXIT_READ_DR4 0x24 +# define SVM_EXIT_READ_DR5 0x25 +# define SVM_EXIT_READ_DR6 0x26 +# define SVM_EXIT_READ_DR7 0x27 +# define SVM_EXIT_READ_DR8 0x28 +# define SVM_EXIT_READ_DR9 0x29 +# define SVM_EXIT_READ_DR10 0x2a +# define SVM_EXIT_READ_DR11 0x2b +# define SVM_EXIT_READ_DR12 0x2c +# define SVM_EXIT_READ_DR13 0x2d +# define SVM_EXIT_READ_DR14 0x2e +# define SVM_EXIT_READ_DR15 0x2f +/** Writes to DR0-DR15. */ +# define SVM_EXIT_WRITE_DR0 0x30 +# define SVM_EXIT_WRITE_DR1 0x31 +# define SVM_EXIT_WRITE_DR2 0x32 +# define SVM_EXIT_WRITE_DR3 0x33 +# define SVM_EXIT_WRITE_DR4 0x34 +# define SVM_EXIT_WRITE_DR5 0x35 +# define SVM_EXIT_WRITE_DR6 0x36 +# define SVM_EXIT_WRITE_DR7 0x37 +# define SVM_EXIT_WRITE_DR8 0x38 +# define SVM_EXIT_WRITE_DR9 0x39 +# define SVM_EXIT_WRITE_DR10 0x3a +# define SVM_EXIT_WRITE_DR11 0x3b +# define SVM_EXIT_WRITE_DR12 0x3c +# define SVM_EXIT_WRITE_DR13 0x3d +# define SVM_EXIT_WRITE_DR14 0x3e +# define SVM_EXIT_WRITE_DR15 0x3f +/* Exception 0-31. */ +# define SVM_EXIT_XCPT_0 0x40 +# define SVM_EXIT_XCPT_1 0x41 +# define SVM_EXIT_XCPT_2 0x42 +# define SVM_EXIT_XCPT_3 0x43 +# define SVM_EXIT_XCPT_4 0x44 +# define SVM_EXIT_XCPT_5 0x45 +# define SVM_EXIT_XCPT_6 0x46 +# define SVM_EXIT_XCPT_7 0x47 +# define SVM_EXIT_XCPT_8 0x48 +# define SVM_EXIT_XCPT_9 0x49 +# define SVM_EXIT_XCPT_10 0x4a +# define SVM_EXIT_XCPT_11 0x4b +# define SVM_EXIT_XCPT_12 0x4c +# define SVM_EXIT_XCPT_13 0x4d +# define SVM_EXIT_XCPT_14 0x4e +# define SVM_EXIT_XCPT_15 0x4f +# define SVM_EXIT_XCPT_16 0x50 +# define SVM_EXIT_XCPT_17 0x51 +# define SVM_EXIT_XCPT_18 0x52 +# define SVM_EXIT_XCPT_19 0x53 +# define SVM_EXIT_XCPT_20 0x54 +# define SVM_EXIT_XCPT_21 0x55 +# define SVM_EXIT_XCPT_22 0x56 +# define SVM_EXIT_XCPT_23 0x57 +# define SVM_EXIT_XCPT_24 0x58 +# define SVM_EXIT_XCPT_25 0x59 +# define SVM_EXIT_XCPT_26 0x5a +# define SVM_EXIT_XCPT_27 0x5b +# define SVM_EXIT_XCPT_28 0x5c +# define SVM_EXIT_XCPT_29 0x5d +# define SVM_EXIT_XCPT_30 0x5e +# define SVM_EXIT_XCPT_31 0x5f +/* Exception (more readable) */ +# define SVM_EXIT_XCPT_DE SVM_EXIT_XCPT_0 +# define SVM_EXIT_XCPT_DB SVM_EXIT_XCPT_1 +# define SVM_EXIT_XCPT_NMI SVM_EXIT_XCPT_2 +# define SVM_EXIT_XCPT_BP SVM_EXIT_XCPT_3 +# define SVM_EXIT_XCPT_OF SVM_EXIT_XCPT_4 +# define SVM_EXIT_XCPT_BR SVM_EXIT_XCPT_5 +# define SVM_EXIT_XCPT_UD SVM_EXIT_XCPT_6 +# define SVM_EXIT_XCPT_NM SVM_EXIT_XCPT_7 +# define SVM_EXIT_XCPT_DF SVM_EXIT_XCPT_8 +# define SVM_EXIT_XCPT_CO_SEG_OVERRUN SVM_EXIT_XCPT_9 +# define SVM_EXIT_XCPT_TS SVM_EXIT_XCPT_10 +# define SVM_EXIT_XCPT_NP SVM_EXIT_XCPT_11 +# define SVM_EXIT_XCPT_SS SVM_EXIT_XCPT_12 +# define SVM_EXIT_XCPT_GP SVM_EXIT_XCPT_13 +# define SVM_EXIT_XCPT_PF SVM_EXIT_XCPT_14 +# define SVM_EXIT_XCPT_MF SVM_EXIT_XCPT_16 +# define SVM_EXIT_XCPT_AC SVM_EXIT_XCPT_17 +# define SVM_EXIT_XCPT_MC SVM_EXIT_XCPT_18 +# define SVM_EXIT_XCPT_XF SVM_EXIT_XCPT_19 +# define SVM_EXIT_XCPT_VE SVM_EXIT_XCPT_20 +# define SVM_EXIT_XCPT_SX SVM_EXIT_XCPT_30 +/** Physical maskable interrupt. */ +# define SVM_EXIT_INTR 0x60 +/** Non-maskable interrupt. */ +# define SVM_EXIT_NMI 0x61 +/** System Management interrupt. */ +# define SVM_EXIT_SMI 0x62 +/** Physical INIT signal. */ +# define SVM_EXIT_INIT 0x63 +/** Virtual interrupt. */ +# define SVM_EXIT_VINTR 0x64 +/** Write to CR0 that changed any bits other than CR0.TS or CR0.MP. */ +# define SVM_EXIT_CR0_SEL_WRITE 0x65 +/** IDTR read. */ +# define SVM_EXIT_IDTR_READ 0x66 +/** GDTR read. */ +# define SVM_EXIT_GDTR_READ 0x67 +/** LDTR read. */ +# define SVM_EXIT_LDTR_READ 0x68 +/** TR read. */ +# define SVM_EXIT_TR_READ 0x69 +/** IDTR write. */ +# define SVM_EXIT_IDTR_WRITE 0x6a +/** GDTR write. */ +# define SVM_EXIT_GDTR_WRITE 0x6b +/** LDTR write. */ +# define SVM_EXIT_LDTR_WRITE 0x6c +/** TR write. */ +# define SVM_EXIT_TR_WRITE 0x6d +/** RDTSC instruction. */ +# define SVM_EXIT_RDTSC 0x6e +/** RDPMC instruction. */ +# define SVM_EXIT_RDPMC 0x6f +/** PUSHF instruction. */ +# define SVM_EXIT_PUSHF 0x70 +/** POPF instruction. */ +# define SVM_EXIT_POPF 0x71 +/** CPUID instruction. */ +# define SVM_EXIT_CPUID 0x72 +/** RSM instruction. */ +# define SVM_EXIT_RSM 0x73 +/** IRET instruction. */ +# define SVM_EXIT_IRET 0x74 +/** Software interrupt (INTn instructions). */ +# define SVM_EXIT_SWINT 0x75 +/** INVD instruction. */ +# define SVM_EXIT_INVD 0x76 +/** PAUSE instruction. */ +# define SVM_EXIT_PAUSE 0x77 +/** HLT instruction. */ +# define SVM_EXIT_HLT 0x78 +/** INVLPG instructions. */ +# define SVM_EXIT_INVLPG 0x79 +/** INVLPGA instruction. */ +# define SVM_EXIT_INVLPGA 0x7a +/** IN or OUT accessing protected port (the EXITINFO1 field provides more information). */ +# define SVM_EXIT_IOIO 0x7b +/** RDMSR or WRMSR access to protected MSR. */ +# define SVM_EXIT_MSR 0x7c +/** task switch. */ +# define SVM_EXIT_TASK_SWITCH 0x7d +/** FP legacy handling enabled, and processor is frozen in an x87/mmx instruction waiting for an interrupt. */ +# define SVM_EXIT_FERR_FREEZE 0x7e +/** Shutdown. */ +# define SVM_EXIT_SHUTDOWN 0x7f +/** VMRUN instruction. */ +# define SVM_EXIT_VMRUN 0x80 +/** VMMCALL instruction. */ +# define SVM_EXIT_VMMCALL 0x81 +/** VMLOAD instruction. */ +# define SVM_EXIT_VMLOAD 0x82 +/** VMSAVE instruction. */ +# define SVM_EXIT_VMSAVE 0x83 +/** STGI instruction. */ +# define SVM_EXIT_STGI 0x84 +/** CLGI instruction. */ +# define SVM_EXIT_CLGI 0x85 +/** SKINIT instruction. */ +# define SVM_EXIT_SKINIT 0x86 +/** RDTSCP instruction. */ +# define SVM_EXIT_RDTSCP 0x87 +/** ICEBP instruction. */ +# define SVM_EXIT_ICEBP 0x88 +/** WBINVD instruction. */ +# define SVM_EXIT_WBINVD 0x89 +/** MONITOR instruction. */ +# define SVM_EXIT_MONITOR 0x8a +/** MWAIT instruction. */ +# define SVM_EXIT_MWAIT 0x8b +/** MWAIT instruction, when armed. */ +# define SVM_EXIT_MWAIT_ARMED 0x8c +/** XSETBV instruction. */ +# define SVM_EXIT_XSETBV 0x8d +/** RDPRU instruction. */ +# define SVM_EXIT_RDPRU 0x8e +/** Write to EFER (after guest instruction completes). */ +# define SVM_EXIT_WRITE_EFER_TRAP 0x8f +/** Write to CR0-CR15 (after guest instruction completes). */ +# define SVM_EXIT_WRITE_CR0_TRAP 0x90 +# define SVM_EXIT_WRITE_CR1_TRAP 0x91 +# define SVM_EXIT_WRITE_CR2_TRAP 0x92 +# define SVM_EXIT_WRITE_CR3_TRAP 0x93 +# define SVM_EXIT_WRITE_CR4_TRAP 0x94 +# define SVM_EXIT_WRITE_CR5_TRAP 0x95 +# define SVM_EXIT_WRITE_CR6_TRAP 0x96 +# define SVM_EXIT_WRITE_CR7_TRAP 0x97 +# define SVM_EXIT_WRITE_CR8_TRAP 0x98 +# define SVM_EXIT_WRITE_CR9_TRAP 0x99 +# define SVM_EXIT_WRITE_CR10_TRAP 0x9a +# define SVM_EXIT_WRITE_CR11_TRAP 0x9b +# define SVM_EXIT_WRITE_CR12_TRAP 0x9c +# define SVM_EXIT_WRITE_CR13_TRAP 0x9d +# define SVM_EXIT_WRITE_CR14_TRAP 0x9e +# define SVM_EXIT_WRITE_CR15_TRAP 0x9f +/** MCOMMIT instruction. */ +# define SVM_EXIT_MCOMMIT 0xa3 + +/** Nested paging: host-level page fault occurred (EXITINFO1 contains fault errorcode; EXITINFO2 contains the guest physical address causing the fault). */ +# define SVM_EXIT_NPF 0x400 +/** AVIC: Virtual IPI delivery not completed. */ +# define SVM_EXIT_AVIC_INCOMPLETE_IPI 0x401 +/** AVIC: Attempted access by guest to a vAPIC register not handled by AVIC + * hardware. */ +# define SVM_EXIT_AVIC_NOACCEL 0x402 +/** The maximum possible exit value. */ +# define SVM_EXIT_MAX (SVM_EXIT_AVIC_NOACCEL) +/** @} */ +#endif /* !IN_REM_R3*/ + + +/** @name SVMVMCB.u64ExitInfo2 for task switches + * @{ + */ +/** Set to 1 if the task switch was caused by an IRET; else cleared to 0. */ +#define SVM_EXIT2_TASK_SWITCH_IRET RT_BIT_64(36) +/** Set to 1 if the task switch was caused by a far jump; else cleared to 0. */ +#define SVM_EXIT2_TASK_SWITCH_JUMP RT_BIT_64(38) +/** Set to 1 if the task switch has an error code; else cleared to 0. */ +#define SVM_EXIT2_TASK_SWITCH_HAS_ERROR_CODE RT_BIT_64(44) +/** The value of EFLAGS.RF that would be saved in the outgoing TSS if the task switch were not intercepted. */ +#define SVM_EXIT2_TASK_SWITCH_EFLAGS_RF RT_BIT_64(48) +/** @} */ + +/** @name SVMVMCB.u64ExitInfo1 for MSR accesses + * @{ + */ +/** The access was a read MSR. */ +#define SVM_EXIT1_MSR_READ 0x0 +/** The access was a write MSR. */ +#define SVM_EXIT1_MSR_WRITE 0x1 +/** @} */ + +/** @name SVMVMCB.u64ExitInfo1 for Mov CRx accesses. + * @{ + */ +/** The mask of whether the access was via a Mov CRx instruction. */ +#define SVM_EXIT1_MOV_CRX_MASK RT_BIT_64(63) +/** The mask for the GPR number of the Mov CRx instruction. */ +#define SVM_EXIT1_MOV_CRX_GPR_NUMBER 0xf +/** @} */ + +/** @name SVMVMCB.u64ExitInfo1 for Mov DRx accesses. + * @{ + */ +/** The mask for the GPR number of the Mov DRx instruction. */ +#define SVM_EXIT1_MOV_DRX_GPR_NUMBER 0xf +/** @} */ + +/** @name SVMVMCB.ctrl.u64InterceptCtrl + * @{ + */ +/** Intercept INTR (physical maskable interrupt). */ +#define SVM_CTRL_INTERCEPT_INTR RT_BIT_64(0) +/** Intercept NMI. */ +#define SVM_CTRL_INTERCEPT_NMI RT_BIT_64(1) +/** Intercept SMI. */ +#define SVM_CTRL_INTERCEPT_SMI RT_BIT_64(2) +/** Intercept INIT. */ +#define SVM_CTRL_INTERCEPT_INIT RT_BIT_64(3) +/** Intercept VINTR (virtual maskable interrupt). */ +#define SVM_CTRL_INTERCEPT_VINTR RT_BIT_64(4) +/** Intercept CR0 writes that change bits other than CR0.TS or CR0.MP */ +#define SVM_CTRL_INTERCEPT_CR0_SEL_WRITE RT_BIT_64(5) +/** Intercept reads of IDTR. */ +#define SVM_CTRL_INTERCEPT_IDTR_READS RT_BIT_64(6) +/** Intercept reads of GDTR. */ +#define SVM_CTRL_INTERCEPT_GDTR_READS RT_BIT_64(7) +/** Intercept reads of LDTR. */ +#define SVM_CTRL_INTERCEPT_LDTR_READS RT_BIT_64(8) +/** Intercept reads of TR. */ +#define SVM_CTRL_INTERCEPT_TR_READS RT_BIT_64(9) +/** Intercept writes of IDTR. */ +#define SVM_CTRL_INTERCEPT_IDTR_WRITES RT_BIT_64(10) +/** Intercept writes of GDTR. */ +#define SVM_CTRL_INTERCEPT_GDTR_WRITES RT_BIT_64(11) +/** Intercept writes of LDTR. */ +#define SVM_CTRL_INTERCEPT_LDTR_WRITES RT_BIT_64(12) +/** Intercept writes of TR. */ +#define SVM_CTRL_INTERCEPT_TR_WRITES RT_BIT_64(13) +/** Intercept RDTSC instruction. */ +#define SVM_CTRL_INTERCEPT_RDTSC RT_BIT_64(14) +/** Intercept RDPMC instruction. */ +#define SVM_CTRL_INTERCEPT_RDPMC RT_BIT_64(15) +/** Intercept PUSHF instruction. */ +#define SVM_CTRL_INTERCEPT_PUSHF RT_BIT_64(16) +/** Intercept POPF instruction. */ +#define SVM_CTRL_INTERCEPT_POPF RT_BIT_64(17) +/** Intercept CPUID instruction. */ +#define SVM_CTRL_INTERCEPT_CPUID RT_BIT_64(18) +/** Intercept RSM instruction. */ +#define SVM_CTRL_INTERCEPT_RSM RT_BIT_64(19) +/** Intercept IRET instruction. */ +#define SVM_CTRL_INTERCEPT_IRET RT_BIT_64(20) +/** Intercept INTn instruction. */ +#define SVM_CTRL_INTERCEPT_INTN RT_BIT_64(21) +/** Intercept INVD instruction. */ +#define SVM_CTRL_INTERCEPT_INVD RT_BIT_64(22) +/** Intercept PAUSE instruction. */ +#define SVM_CTRL_INTERCEPT_PAUSE RT_BIT_64(23) +/** Intercept HLT instruction. */ +#define SVM_CTRL_INTERCEPT_HLT RT_BIT_64(24) +/** Intercept INVLPG instruction. */ +#define SVM_CTRL_INTERCEPT_INVLPG RT_BIT_64(25) +/** Intercept INVLPGA instruction. */ +#define SVM_CTRL_INTERCEPT_INVLPGA RT_BIT_64(26) +/** IOIO_PROT Intercept IN/OUT accesses to selected ports. */ +#define SVM_CTRL_INTERCEPT_IOIO_PROT RT_BIT_64(27) +/** MSR_PROT Intercept RDMSR or WRMSR accesses to selected MSRs. */ +#define SVM_CTRL_INTERCEPT_MSR_PROT RT_BIT_64(28) +/** Intercept task switches. */ +#define SVM_CTRL_INTERCEPT_TASK_SWITCH RT_BIT_64(29) +/** FERR_FREEZE: intercept processor "freezing" during legacy FERR handling. */ +#define SVM_CTRL_INTERCEPT_FERR_FREEZE RT_BIT_64(30) +/** Intercept shutdown events. */ +#define SVM_CTRL_INTERCEPT_SHUTDOWN RT_BIT_64(31) +/** Intercept VMRUN instruction. */ +#define SVM_CTRL_INTERCEPT_VMRUN RT_BIT_64(32 + 0) +/** Intercept VMMCALL instruction. */ +#define SVM_CTRL_INTERCEPT_VMMCALL RT_BIT_64(32 + 1) +/** Intercept VMLOAD instruction. */ +#define SVM_CTRL_INTERCEPT_VMLOAD RT_BIT_64(32 + 2) +/** Intercept VMSAVE instruction. */ +#define SVM_CTRL_INTERCEPT_VMSAVE RT_BIT_64(32 + 3) +/** Intercept STGI instruction. */ +#define SVM_CTRL_INTERCEPT_STGI RT_BIT_64(32 + 4) +/** Intercept CLGI instruction. */ +#define SVM_CTRL_INTERCEPT_CLGI RT_BIT_64(32 + 5) +/** Intercept SKINIT instruction. */ +#define SVM_CTRL_INTERCEPT_SKINIT RT_BIT_64(32 + 6) +/** Intercept RDTSCP instruction. */ +#define SVM_CTRL_INTERCEPT_RDTSCP RT_BIT_64(32 + 7) +/** Intercept ICEBP instruction. */ +#define SVM_CTRL_INTERCEPT_ICEBP RT_BIT_64(32 + 8) +/** Intercept WBINVD instruction. */ +#define SVM_CTRL_INTERCEPT_WBINVD RT_BIT_64(32 + 9) +/** Intercept MONITOR instruction. */ +#define SVM_CTRL_INTERCEPT_MONITOR RT_BIT_64(32 + 10) +/** Intercept MWAIT instruction unconditionally. */ +#define SVM_CTRL_INTERCEPT_MWAIT RT_BIT_64(32 + 11) +/** Intercept MWAIT instruction when armed. */ +#define SVM_CTRL_INTERCEPT_MWAIT_ARMED RT_BIT_64(32 + 12) +/** Intercept XSETBV instruction. */ +#define SVM_CTRL_INTERCEPT_XSETBV RT_BIT_64(32 + 13) +/** Intercept RDPRU instruction. */ +#define SVM_CTRL_INTERCEPT_RDPRU RT_BIT_64(32 + 14) +/** Intercept EFER writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_EFER_WRITES_TRAP RT_BIT_64(32 + 15) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR0_WRITES_TRAP RT_BIT_64(32 + 16) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR1_WRITES_TRAP RT_BIT_64(32 + 17) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR2_WRITES_TRAP RT_BIT_64(32 + 18) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR3_WRITES_TRAP RT_BIT_64(32 + 19) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR4_WRITES_TRAP RT_BIT_64(32 + 20) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR5_WRITES_TRAP RT_BIT_64(32 + 21) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR6_WRITES_TRAP RT_BIT_64(32 + 22) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR7_WRITES_TRAP RT_BIT_64(32 + 23) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR8_WRITES_TRAP RT_BIT_64(32 + 24) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR9_WRITES_TRAP RT_BIT_64(32 + 25) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR10_WRITES_TRAP RT_BIT_64(32 + 26) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR11_WRITES_TRAP RT_BIT_64(32 + 27) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR12_WRITES_TRAP RT_BIT_64(32 + 28) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR13_WRITES_TRAP RT_BIT_64(32 + 29) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR14_WRITES_TRAP RT_BIT_64(32 + 30) +/** Intercept CR0 writes after guest instruction finishes. */ +#define SVM_CTRL_INTERCEPT_CR15_WRITES_TRAP RT_BIT_64(32 + 31) +/** @} */ + +/** @name SVMINTCTRL.u3Type + * @{ + */ +/** External or virtual interrupt. */ +#define SVM_EVENT_EXTERNAL_IRQ 0 +/** Non-maskable interrupt. */ +#define SVM_EVENT_NMI 2 +/** Exception; fault or trap. */ +#define SVM_EVENT_EXCEPTION 3 +/** Software interrupt. */ +#define SVM_EVENT_SOFTWARE_INT 4 +/** @} */ + +/** @name SVMVMCB.ctrl.TLBCtrl.n.u8TLBFlush + * @{ + */ +/** Flush nothing. */ +#define SVM_TLB_FLUSH_NOTHING 0 +/** Flush entire TLB (host+guest entries) */ +#define SVM_TLB_FLUSH_ENTIRE 1 +/** Flush this guest's TLB entries (by ASID) */ +#define SVM_TLB_FLUSH_SINGLE_CONTEXT 3 +/** Flush this guest's non-global TLB entries (by ASID) */ +#define SVM_TLB_FLUSH_SINGLE_CONTEXT_RETAIN_GLOBALS 7 +/** @} */ + +/** + * SVM selector/segment register type. + */ +typedef struct +{ + uint16_t u16Sel; + uint16_t u16Attr; + uint32_t u32Limit; + uint64_t u64Base; /**< Only lower 32 bits are implemented for CS, DS, ES & SS. */ +} SVMSELREG; +AssertCompileSize(SVMSELREG, 16); +/** Pointer to the SVMSELREG struct. */ +typedef SVMSELREG *PSVMSELREG; +/** Pointer to a const SVMSELREG struct. */ +typedef const SVMSELREG *PCSVMSELREG; + +/** + * SVM GDTR/IDTR type. + */ +typedef struct +{ + uint16_t u16Reserved0; + uint16_t u16Reserved1; + uint32_t u32Limit; /**< Only lower 16 bits are implemented. */ + uint64_t u64Base; +} SVMXDTR; +AssertCompileSize(SVMXDTR, 16); +typedef SVMXDTR SVMIDTR; +typedef SVMXDTR SVMGDTR; +/** Pointer to the SVMXDTR struct. */ +typedef SVMXDTR *PSVMXDTR; +/** Pointer to a const SVMXDTR struct. */ +typedef const SVMXDTR *PCSVMXDTR; + +/** + * SVM Event injection structure (EVENTINJ and EXITINTINFO). + */ +typedef union +{ + struct + { + uint32_t u8Vector : 8; + uint32_t u3Type : 3; + uint32_t u1ErrorCodeValid : 1; + uint32_t u19Reserved : 19; + uint32_t u1Valid : 1; + uint32_t u32ErrorCode : 32; + } n; + uint64_t u; +} SVMEVENT; +/** Pointer to the SVMEVENT union. */ +typedef SVMEVENT *PSVMEVENT; +/** Pointer to a const SVMEVENT union. */ +typedef const SVMEVENT *PCSVMEVENT; + +/** Gets the event type given an SVMEVENT parameter. */ +#define SVM_EVENT_GET_TYPE(a_SvmEvent) (((a_SvmEvent) >> 8) & 7) + +/** + * SVM Interrupt control structure (Virtual Interrupt Control). + */ +typedef union +{ + struct + { + uint32_t u8VTPR : 8; /* V_TPR */ + uint32_t u1VIrqPending : 1; /* V_IRQ */ + uint32_t u1VGif : 1; /* VGIF */ + uint32_t u6Reserved : 6; + uint32_t u4VIntrPrio : 4; /* V_INTR_PRIO */ + uint32_t u1IgnoreTPR : 1; /* V_IGN_TPR */ + uint32_t u3Reserved : 3; + uint32_t u1VIntrMasking : 1; /* V_INTR_MASKING */ + uint32_t u1VGifEnable : 1; /* VGIF enable */ + uint32_t u5Reserved : 5; + uint32_t u1AvicEnable : 1; /* AVIC enable */ + uint32_t u8VIntrVector : 8; /* V_INTR_VECTOR */ + uint32_t u24Reserved : 24; + } n; + uint64_t u; +} SVMINTCTRL; +/** Pointer to an SVMINTCTRL structure. */ +typedef SVMINTCTRL *PSVMINTCTRL; +/** Pointer to a const SVMINTCTRL structure. */ +typedef const SVMINTCTRL *PCSVMINTCTRL; + +/** + * SVM TLB control structure. + */ +typedef union +{ + struct + { + uint32_t u32ASID : 32; + uint32_t u8TLBFlush : 8; + uint32_t u24Reserved : 24; + } n; + uint64_t u; +} SVMTLBCTRL; + +/** + * SVM IOIO exit info. structure (EXITINFO1 for IOIO intercepts). + */ +typedef union +{ + struct + { + uint32_t u1Type : 1; /**< Bit 0: 0 = out, 1 = in */ + uint32_t u1Reserved : 1; /**< Bit 1: Reserved */ + uint32_t u1Str : 1; /**< Bit 2: String I/O (1) or not (0). */ + uint32_t u1Rep : 1; /**< Bit 3: Repeat prefixed string I/O. */ + uint32_t u1Op8 : 1; /**< Bit 4: 8-bit operand. */ + uint32_t u1Op16 : 1; /**< Bit 5: 16-bit operand. */ + uint32_t u1Op32 : 1; /**< Bit 6: 32-bit operand. */ + uint32_t u1Addr16 : 1; /**< Bit 7: 16-bit address size. */ + uint32_t u1Addr32 : 1; /**< Bit 8: 32-bit address size. */ + uint32_t u1Addr64 : 1; /**< Bit 9: 64-bit address size. */ + uint32_t u3Seg : 3; /**< Bits 12:10: Effective segment number. Added w/ decode assist in APM v3.17. */ + uint32_t u3Reserved : 3; + uint32_t u16Port : 16; /**< Bits 31:16: Port number. */ + } n; + uint32_t u; +} SVMIOIOEXITINFO; +/** Pointer to an SVM IOIO exit info. structure. */ +typedef SVMIOIOEXITINFO *PSVMIOIOEXITINFO; +/** Pointer to a const SVM IOIO exit info. structure. */ +typedef const SVMIOIOEXITINFO *PCSVMIOIOEXITINFO; + +/** 8-bit IO transfer. */ +#define SVM_IOIO_8_BIT_OP RT_BIT_32(4) +/** 16-bit IO transfer. */ +#define SVM_IOIO_16_BIT_OP RT_BIT_32(5) +/** 32-bit IO transfer. */ +#define SVM_IOIO_32_BIT_OP RT_BIT_32(6) +/** Number of bits to shift right to get the operand sizes. */ +#define SVM_IOIO_OP_SIZE_SHIFT 4 +/** Mask of all possible IO transfer sizes. */ +#define SVM_IOIO_OP_SIZE_MASK (SVM_IOIO_8_BIT_OP | SVM_IOIO_16_BIT_OP | SVM_IOIO_32_BIT_OP) +/** 16-bit address for the IO buffer. */ +#define SVM_IOIO_16_BIT_ADDR RT_BIT_32(7) +/** 32-bit address for the IO buffer. */ +#define SVM_IOIO_32_BIT_ADDR RT_BIT_32(8) +/** 64-bit address for the IO buffer. */ +#define SVM_IOIO_64_BIT_ADDR RT_BIT_32(9) +/** Number of bits to shift right to get the address sizes. */ +#define SVM_IOIO_ADDR_SIZE_SHIFT 7 +/** Mask of all the IO address sizes. */ +#define SVM_IOIO_ADDR_SIZE_MASK (SVM_IOIO_16_BIT_ADDR | SVM_IOIO_32_BIT_ADDR | SVM_IOIO_64_BIT_ADDR) +/** Number of bits to shift right to get the IO port number. */ +#define SVM_IOIO_PORT_SHIFT 16 +/** IO write. */ +#define SVM_IOIO_WRITE 0 +/** IO read. */ +#define SVM_IOIO_READ 1 +/** + * SVM IOIO transfer type. + */ +typedef enum +{ + SVMIOIOTYPE_OUT = SVM_IOIO_WRITE, + SVMIOIOTYPE_IN = SVM_IOIO_READ +} SVMIOIOTYPE; + +/** + * SVM AVIC. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u12Reserved0 : 12; + RT_GCC_EXTENSION uint64_t u40Addr : 40; + RT_GCC_EXTENSION uint64_t u12Reserved1 : 12; + } n; + uint64_t u; +} SVMAVIC; +AssertCompileSize(SVMAVIC, 8); + +/** + * SVM AVIC PHYSICAL_TABLE pointer. + */ +typedef union +{ + struct + { + RT_GCC_EXTENSION uint64_t u8LastGuestCoreId : 8; + RT_GCC_EXTENSION uint64_t u4Reserved : 4; + RT_GCC_EXTENSION uint64_t u40Addr : 40; + RT_GCC_EXTENSION uint64_t u12Reserved : 12; + } n; + uint64_t u; +} SVMAVICPHYS; +AssertCompileSize(SVMAVICPHYS, 8); + +/** + * SVM Nested Paging struct. + */ +typedef union +{ + struct + { + uint32_t u1NestedPaging : 1; + uint32_t u1Sev : 1; + uint32_t u1SevEs : 1; + uint32_t u29Reserved : 29; + } n; + uint64_t u; +} SVMNP; +AssertCompileSize(SVMNP, 8); + +/** + * SVM Interrupt shadow struct. + */ +typedef union +{ + struct + { + uint32_t u1IntShadow : 1; + uint32_t u1GuestIntMask : 1; + uint32_t u30Reserved : 30; + } n; + uint64_t u; +} SVMINTSHADOW; +AssertCompileSize(SVMINTSHADOW, 8); + +/** + * SVM LBR virtualization struct. + */ +typedef union +{ + struct + { + uint32_t u1LbrVirt : 1; + uint32_t u1VirtVmsaveVmload : 1; + uint32_t u30Reserved : 30; + } n; + uint64_t u; +} SVMLBRVIRT; +AssertCompileSize(SVMLBRVIRT, 8); + +/** Maximum number of bytes in the Guest-instruction bytes field. */ +#define SVM_CTRL_GUEST_INSTR_BYTES_MAX 15 + +/** + * SVM VMCB control area. + */ +#pragma pack(1) +typedef struct +{ + /** Offset 0x00 - Intercept reads of CR0-CR15. */ + uint16_t u16InterceptRdCRx; + /** Offset 0x02 - Intercept writes to CR0-CR15. */ + uint16_t u16InterceptWrCRx; + /** Offset 0x04 - Intercept reads of DR0-DR15. */ + uint16_t u16InterceptRdDRx; + /** Offset 0x06 - Intercept writes to DR0-DR15. */ + uint16_t u16InterceptWrDRx; + /** Offset 0x08 - Intercept exception vectors 0-31. */ + uint32_t u32InterceptXcpt; + /** Offset 0x0c - Intercept control. */ + uint64_t u64InterceptCtrl; + /** Offset 0x14-0x3f - Reserved. */ + uint8_t u8Reserved0[0x3c - 0x14]; + /** Offset 0x3c - PAUSE filter threshold. */ + uint16_t u16PauseFilterThreshold; + /** Offset 0x3e - PAUSE intercept filter count. */ + uint16_t u16PauseFilterCount; + /** Offset 0x40 - Physical address of IOPM. */ + uint64_t u64IOPMPhysAddr; + /** Offset 0x48 - Physical address of MSRPM. */ + uint64_t u64MSRPMPhysAddr; + /** Offset 0x50 - TSC Offset. */ + uint64_t u64TSCOffset; + /** Offset 0x58 - TLB control field. */ + SVMTLBCTRL TLBCtrl; + /** Offset 0x60 - Interrupt control field. */ + SVMINTCTRL IntCtrl; + /** Offset 0x68 - Interrupt shadow. */ + SVMINTSHADOW IntShadow; + /** Offset 0x70 - Exit code. */ + uint64_t u64ExitCode; + /** Offset 0x78 - Exit info 1. */ + uint64_t u64ExitInfo1; + /** Offset 0x80 - Exit info 2. */ + uint64_t u64ExitInfo2; + /** Offset 0x88 - Exit Interrupt info. */ + SVMEVENT ExitIntInfo; + /** Offset 0x90 - Nested Paging control. */ + SVMNP NestedPagingCtrl; + /** Offset 0x98 - AVIC APIC BAR. */ + SVMAVIC AvicBar; + /** Offset 0xa0-0xa7 - Reserved. */ + uint8_t u8Reserved1[0xa8 - 0xa0]; + /** Offset 0xa8 - Event injection. */ + SVMEVENT EventInject; + /** Offset 0xb0 - Host CR3 for nested paging. */ + uint64_t u64NestedPagingCR3; + /** Offset 0xb8 - LBR Virtualization. */ + SVMLBRVIRT LbrVirt; + /** Offset 0xc0 - VMCB Clean Bits. */ + uint32_t u32VmcbCleanBits; + uint32_t u32Reserved0; + /** Offset 0xc8 - Next sequential instruction pointer. */ + uint64_t u64NextRIP; + /** Offset 0xd0 - Number of bytes fetched. */ + uint8_t cbInstrFetched; + /** Offset 0xd1 - Guest instruction bytes. */ + uint8_t abInstr[SVM_CTRL_GUEST_INSTR_BYTES_MAX]; + /** Offset 0xe0 - AVIC APIC_BACKING_PAGE pointer. */ + SVMAVIC AvicBackingPagePtr; + /** Offset 0xe8-0xef - Reserved. */ + uint8_t u8Reserved2[0xf0 - 0xe8]; + /** Offset 0xf0 - AVIC LOGICAL_TABLE pointer. */ + SVMAVIC AvicLogicalTablePtr; + /** Offset 0xf8 - AVIC PHYSICAL_TABLE pointer. */ + SVMAVICPHYS AvicPhysicalTablePtr; +} SVMVMCBCTRL; +#pragma pack() +/** Pointer to the SVMVMCBSTATESAVE structure. */ +typedef SVMVMCBCTRL *PSVMVMCBCTRL; +/** Pointer to a const SVMVMCBSTATESAVE structure. */ +typedef const SVMVMCBCTRL *PCSVMVMCBCTRL; +AssertCompileSize(SVMVMCBCTRL, 0x100); +AssertCompileMemberOffset(SVMVMCBCTRL, u16InterceptRdCRx, 0x00); +AssertCompileMemberOffset(SVMVMCBCTRL, u16InterceptWrCRx, 0x02); +AssertCompileMemberOffset(SVMVMCBCTRL, u16InterceptRdDRx, 0x04); +AssertCompileMemberOffset(SVMVMCBCTRL, u16InterceptWrDRx, 0x06); +AssertCompileMemberOffset(SVMVMCBCTRL, u32InterceptXcpt, 0x08); +AssertCompileMemberOffset(SVMVMCBCTRL, u64InterceptCtrl, 0x0c); +AssertCompileMemberOffset(SVMVMCBCTRL, u8Reserved0, 0x14); +AssertCompileMemberOffset(SVMVMCBCTRL, u16PauseFilterThreshold, 0x3c); +AssertCompileMemberOffset(SVMVMCBCTRL, u16PauseFilterCount, 0x3e); +AssertCompileMemberOffset(SVMVMCBCTRL, u64IOPMPhysAddr, 0x40); +AssertCompileMemberOffset(SVMVMCBCTRL, u64MSRPMPhysAddr, 0x48); +AssertCompileMemberOffset(SVMVMCBCTRL, u64TSCOffset, 0x50); +AssertCompileMemberOffset(SVMVMCBCTRL, TLBCtrl, 0x58); +AssertCompileMemberOffset(SVMVMCBCTRL, IntCtrl, 0x60); +AssertCompileMemberOffset(SVMVMCBCTRL, IntShadow, 0x68); +AssertCompileMemberOffset(SVMVMCBCTRL, u64ExitCode, 0x70); +AssertCompileMemberOffset(SVMVMCBCTRL, u64ExitInfo1, 0x78); +AssertCompileMemberOffset(SVMVMCBCTRL, u64ExitInfo2, 0x80); +AssertCompileMemberOffset(SVMVMCBCTRL, ExitIntInfo, 0x88); +AssertCompileMemberOffset(SVMVMCBCTRL, NestedPagingCtrl, 0x90); +AssertCompileMemberOffset(SVMVMCBCTRL, AvicBar, 0x98); +AssertCompileMemberOffset(SVMVMCBCTRL, u8Reserved1, 0xa0); +AssertCompileMemberOffset(SVMVMCBCTRL, EventInject, 0xa8); +AssertCompileMemberOffset(SVMVMCBCTRL, u64NestedPagingCR3, 0xb0); +AssertCompileMemberOffset(SVMVMCBCTRL, LbrVirt, 0xb8); +AssertCompileMemberOffset(SVMVMCBCTRL, u32VmcbCleanBits, 0xc0); +AssertCompileMemberOffset(SVMVMCBCTRL, u64NextRIP, 0xc8); +AssertCompileMemberOffset(SVMVMCBCTRL, cbInstrFetched, 0xd0); +AssertCompileMemberOffset(SVMVMCBCTRL, abInstr, 0xd1); +AssertCompileMemberOffset(SVMVMCBCTRL, AvicBackingPagePtr, 0xe0); +AssertCompileMemberOffset(SVMVMCBCTRL, u8Reserved2, 0xe8); +AssertCompileMemberOffset(SVMVMCBCTRL, AvicLogicalTablePtr, 0xf0); +AssertCompileMemberOffset(SVMVMCBCTRL, AvicPhysicalTablePtr, 0xf8); +AssertCompileMemberSize(SVMVMCBCTRL, abInstr, 0x0f); + +/** + * SVM VMCB state save area. + */ +#pragma pack(1) +typedef struct +{ + /** Offset 0x400 - Guest ES register + hidden parts. */ + SVMSELREG ES; + /** Offset 0x410 - Guest CS register + hidden parts. */ + SVMSELREG CS; + /** Offset 0x420 - Guest SS register + hidden parts. */ + SVMSELREG SS; + /** Offset 0x430 - Guest DS register + hidden parts. */ + SVMSELREG DS; + /** Offset 0x440 - Guest FS register + hidden parts. */ + SVMSELREG FS; + /** Offset 0x450 - Guest GS register + hidden parts. */ + SVMSELREG GS; + /** Offset 0x460 - Guest GDTR register. */ + SVMGDTR GDTR; + /** Offset 0x470 - Guest LDTR register + hidden parts. */ + SVMSELREG LDTR; + /** Offset 0x480 - Guest IDTR register. */ + SVMIDTR IDTR; + /** Offset 0x490 - Guest TR register + hidden parts. */ + SVMSELREG TR; + /** Offset 0x4A0-0x4CA - Reserved. */ + uint8_t u8Reserved0[0x4cb - 0x4a0]; + /** Offset 0x4CB - CPL. */ + uint8_t u8CPL; + /** Offset 0x4CC-0x4CF - Reserved. */ + uint8_t u8Reserved1[0x4d0 - 0x4cc]; + /** Offset 0x4D0 - EFER. */ + uint64_t u64EFER; + /** Offset 0x4D8-0x547 - Reserved. */ + uint8_t u8Reserved2[0x548 - 0x4d8]; + /** Offset 0x548 - CR4. */ + uint64_t u64CR4; + /** Offset 0x550 - CR3. */ + uint64_t u64CR3; + /** Offset 0x558 - CR0. */ + uint64_t u64CR0; + /** Offset 0x560 - DR7. */ + uint64_t u64DR7; + /** Offset 0x568 - DR6. */ + uint64_t u64DR6; + /** Offset 0x570 - RFLAGS. */ + uint64_t u64RFlags; + /** Offset 0x578 - RIP. */ + uint64_t u64RIP; + /** Offset 0x580-0x5D7 - Reserved. */ + uint8_t u8Reserved3[0x5d8 - 0x580]; + /** Offset 0x5D8 - RSP. */ + uint64_t u64RSP; + /** Offset 0x5E0-0x5F7 - Reserved. */ + uint8_t u8Reserved4[0x5f8 - 0x5e0]; + /** Offset 0x5F8 - RAX. */ + uint64_t u64RAX; + /** Offset 0x600 - STAR. */ + uint64_t u64STAR; + /** Offset 0x608 - LSTAR. */ + uint64_t u64LSTAR; + /** Offset 0x610 - CSTAR. */ + uint64_t u64CSTAR; + /** Offset 0x618 - SFMASK. */ + uint64_t u64SFMASK; + /** Offset 0x620 - KernelGSBase. */ + uint64_t u64KernelGSBase; + /** Offset 0x628 - SYSENTER_CS. */ + uint64_t u64SysEnterCS; + /** Offset 0x630 - SYSENTER_ESP. */ + uint64_t u64SysEnterESP; + /** Offset 0x638 - SYSENTER_EIP. */ + uint64_t u64SysEnterEIP; + /** Offset 0x640 - CR2. */ + uint64_t u64CR2; + /** Offset 0x648-0x667 - Reserved. */ + uint8_t u8Reserved5[0x668 - 0x648]; + /** Offset 0x668 - PAT (Page Attribute Table) MSR. */ + uint64_t u64PAT; + /** Offset 0x670 - DBGCTL. */ + uint64_t u64DBGCTL; + /** Offset 0x678 - BR_FROM. */ + uint64_t u64BR_FROM; + /** Offset 0x680 - BR_TO. */ + uint64_t u64BR_TO; + /** Offset 0x688 - LASTEXCPFROM. */ + uint64_t u64LASTEXCPFROM; + /** Offset 0x690 - LASTEXCPTO. */ + uint64_t u64LASTEXCPTO; +} SVMVMCBSTATESAVE; +#pragma pack() +/** Pointer to the SVMVMCBSTATESAVE structure. */ +typedef SVMVMCBSTATESAVE *PSVMVMCBSTATESAVE; +/** Pointer to a const SVMVMCBSTATESAVE structure. */ +typedef const SVMVMCBSTATESAVE *PCSVMVMCBSTATESAVE; +AssertCompileSize(SVMVMCBSTATESAVE, 0x298); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, ES, 0x400 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, CS, 0x410 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, SS, 0x420 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, DS, 0x430 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, FS, 0x440 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, GS, 0x450 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, GDTR, 0x460 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, LDTR, 0x470 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, IDTR, 0x480 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, TR, 0x490 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved0, 0x4a0 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8CPL, 0x4cb - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved1, 0x4cc - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64EFER, 0x4d0 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved2, 0x4d8 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CR4, 0x548 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CR3, 0x550 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CR0, 0x558 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64DR7, 0x560 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64DR6, 0x568 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64RFlags, 0x570 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64RIP, 0x578 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved3, 0x580 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64RSP, 0x5d8 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved4, 0x5e0 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64RAX, 0x5f8 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64STAR, 0x600 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64LSTAR, 0x608 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CSTAR, 0x610 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64SFMASK, 0x618 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64KernelGSBase, 0x620 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64SysEnterCS, 0x628 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64SysEnterESP, 0x630 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64SysEnterEIP, 0x638 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64CR2, 0x640 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u8Reserved5, 0x648 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64PAT, 0x668 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64DBGCTL, 0x670 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64BR_FROM, 0x678 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64BR_TO, 0x680 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64LASTEXCPFROM, 0x688 - 0x400); +AssertCompileMemberOffset(SVMVMCBSTATESAVE, u64LASTEXCPTO, 0x690 - 0x400); + +/** + * SVM VM Control Block. (VMCB) + */ +#pragma pack(1) +typedef struct SVMVMCB +{ + /** Offset 0x00 - Control area. */ + SVMVMCBCTRL ctrl; + /** Offset 0x100-0x3FF - Reserved. */ + uint8_t u8Reserved0[0x400 - 0x100]; + /** Offset 0x400 - State save area. */ + SVMVMCBSTATESAVE guest; + /** Offset 0x698-0xFFF- Reserved. */ + uint8_t u8Reserved1[0x1000 - 0x698]; +} SVMVMCB; +#pragma pack() +/** Pointer to the SVMVMCB structure. */ +typedef SVMVMCB *PSVMVMCB; +/** Pointer to a const SVMVMCB structure. */ +typedef const SVMVMCB *PCSVMVMCB; +AssertCompileMemberOffset(SVMVMCB, ctrl, 0x00); +AssertCompileMemberOffset(SVMVMCB, u8Reserved0, 0x100); +AssertCompileMemberOffset(SVMVMCB, guest, 0x400); +AssertCompileMemberOffset(SVMVMCB, u8Reserved1, 0x698); +AssertCompileSize(SVMVMCB, 0x1000); + +/** + * SVM MSRs. + */ +typedef struct SVMMSRS +{ + /** HWCR MSR. */ + uint64_t u64MsrHwcr; + /** Reserved for future. */ + uint64_t u64Padding[27]; +} SVMMSRS; +AssertCompileSizeAlignment(SVMMSRS, 8); +AssertCompileSize(SVMMSRS, 224); +/** Pointer to a SVMMSRS struct. */ +typedef SVMMSRS *PSVMMSRS; +/** Pointer to a const SVMMSRS struct. */ +typedef const SVMMSRS *PCSVMMSRS; + +/** + * SVM VM-exit auxiliary information. + * + * This includes information that isn't necessarily stored in the guest-CPU + * context but provided as part of \#VMEXITs. + */ +typedef struct +{ + uint64_t u64ExitCode; + uint64_t u64ExitInfo1; + uint64_t u64ExitInfo2; + SVMEVENT ExitIntInfo; +} SVMEXITAUX; +/** Pointer to a SVMEXITAUX struct. */ +typedef SVMEXITAUX *PSVMEXITAUX; +/** Pointer to a const SVMEXITAUX struct. */ +typedef const SVMEXITAUX *PCSVMEXITAUX; + +/** + * Segment attribute conversion between CPU and AMD-V VMCB format. + * + * The CPU format of the segment attribute is described in X86DESCATTRBITS + * which is 16-bits (i.e. includes 4 bits of the segment limit). + * + * The AMD-V VMCB format the segment attribute is compact 12-bits (strictly + * only the attribute bits and nothing else). Upper 4-bits are unused. + */ +#define HMSVM_CPU_2_VMCB_SEG_ATTR(a) ( ((a) & 0xff) | (((a) & 0xf000) >> 4) ) +#define HMSVM_VMCB_2_CPU_SEG_ATTR(a) ( ((a) & 0xff) | (((a) & 0x0f00) << 4) ) + +/** @def HMSVM_SEG_REG_COPY_TO_VMCB + * Copies the specified segment register to a VMCB from a virtual CPU context. + * + * @param a_pCtx The virtual-CPU context. + * @param a_pVmcbStateSave Pointer to the VMCB state-save area. + * @param a_REG The segment register in the VMCB state-save + * struct (ES/CS/SS/DS). + * @param a_reg The segment register in the virtual CPU struct + * (es/cs/ss/ds). + */ +#define HMSVM_SEG_REG_COPY_TO_VMCB(a_pCtx, a_pVmcbStateSave, a_REG, a_reg) \ + do \ + { \ + Assert((a_pCtx)->a_reg.fFlags & CPUMSELREG_FLAGS_VALID); \ + Assert((a_pCtx)->a_reg.ValidSel == (a_pCtx)->a_reg.Sel); \ + (a_pVmcbStateSave)->a_REG.u16Sel = (a_pCtx)->a_reg.Sel; \ + (a_pVmcbStateSave)->a_REG.u32Limit = (a_pCtx)->a_reg.u32Limit; \ + (a_pVmcbStateSave)->a_REG.u64Base = (a_pCtx)->a_reg.u64Base; \ + (a_pVmcbStateSave)->a_REG.u16Attr = HMSVM_CPU_2_VMCB_SEG_ATTR((a_pCtx)->a_reg.Attr.u); \ + } while (0) + +/** @def HMSVM_SEG_REG_COPY_FROM_VMCB + * Copies the specified segment register from the VMCB to a virtual CPU + * context. + * + * @param a_pCtx The virtual-CPU context. + * @param a_pVmcbStateSave Pointer to the VMCB state-save area. + * @param a_REG The segment register in the VMCB state-save + * struct (ES/CS/SS/DS). + * @param a_reg The segment register in the virtual CPU struct + * (es/ds/ss/ds). + */ +#define HMSVM_SEG_REG_COPY_FROM_VMCB(a_pCtx, a_pVmcbStateSave, a_REG, a_reg) \ + do \ + { \ + (a_pCtx)->a_reg.Sel = (a_pVmcbStateSave)->a_REG.u16Sel; \ + (a_pCtx)->a_reg.ValidSel = (a_pVmcbStateSave)->a_REG.u16Sel; \ + (a_pCtx)->a_reg.fFlags = CPUMSELREG_FLAGS_VALID; \ + (a_pCtx)->a_reg.u32Limit = (a_pVmcbStateSave)->a_REG.u32Limit; \ + (a_pCtx)->a_reg.u64Base = (a_pVmcbStateSave)->a_REG.u64Base; \ + (a_pCtx)->a_reg.Attr.u = HMSVM_VMCB_2_CPU_SEG_ATTR((a_pVmcbStateSave)->a_REG.u16Attr); \ + } while (0) + + +/** @defgroup grp_hm_svm_hwexec SVM Hardware-assisted execution Helpers + * + * These functions are only here because the inline functions in cpum.h calls them. + * Don't add any more functions here unless there is no other option. + * @{ + */ +VMM_INT_DECL(bool) HMGetGuestSvmCtrlIntercepts(PCVMCPU pVCpu, uint64_t *pu64Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmReadCRxIntercepts(PCVMCPU pVCpu, uint16_t *pu16Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmWriteCRxIntercepts(PCVMCPU pVCpu, uint16_t *pu16Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmReadDRxIntercepts(PCVMCPU pVCpu, uint16_t *pu16Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmWriteDRxIntercepts(PCVMCPU pVCpu, uint16_t *pu16Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmXcptIntercepts(PCVMCPU pVCpu, uint32_t *pu32Intercepts); +VMM_INT_DECL(bool) HMGetGuestSvmVirtIntrMasking(PCVMCPU pVCpu, bool *pfVIntrMasking); +VMM_INT_DECL(bool) HMGetGuestSvmNestedPaging(PCVMCPU pVCpu, bool *pfNestedPagingCtrl); +VMM_INT_DECL(bool) HMGetGuestSvmPauseFilterCount(PCVMCPU pVCpu, uint16_t *pu16PauseFilterCount); +VMM_INT_DECL(bool) HMGetGuestSvmTscOffset(PCVMCPU pVCpu, uint64_t *pu64TscOffset); +/** @} */ + + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_hm_svm_h */ + diff --git a/include/VBox/vmm/hm_vmx.h b/include/VBox/vmm/hm_vmx.h new file mode 100644 index 00000000..95794dca --- /dev/null +++ b/include/VBox/vmm/hm_vmx.h @@ -0,0 +1,4644 @@ +/** @file + * HM - VMX Structures and Definitions. (VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_hm_vmx_h +#define VBOX_INCLUDED_vmm_hm_vmx_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +/** @defgroup grp_hm_vmx VMX Types and Definitions + * @ingroup grp_hm + * @{ + */ + +/** @name Host-state MSR lazy-restoration flags. + * @{ + */ +/** The host MSRs have been saved. */ +#define VMX_LAZY_MSRS_SAVED_HOST RT_BIT(0) +/** The guest MSRs are loaded and in effect. */ +#define VMX_LAZY_MSRS_LOADED_GUEST RT_BIT(1) +/** @} */ + +/** @name VMX HM-error codes for VERR_HM_UNSUPPORTED_CPU_FEATURE_COMBO. + * UFC = Unsupported Feature Combination. + * @{ + */ +/** Unsupported pin-based VM-execution controls combo. */ +#define VMX_UFC_CTRL_PIN_EXEC 1 +/** Unsupported processor-based VM-execution controls combo. */ +#define VMX_UFC_CTRL_PROC_EXEC 2 +/** Unsupported move debug register VM-exit combo. */ +#define VMX_UFC_CTRL_PROC_MOV_DRX_EXIT 3 +/** Unsupported VM-entry controls combo. */ +#define VMX_UFC_CTRL_ENTRY 4 +/** Unsupported VM-exit controls combo. */ +#define VMX_UFC_CTRL_EXIT 5 +/** MSR storage capacity of the VMCS autoload/store area is not sufficient + * for storing host MSRs. */ +#define VMX_UFC_INSUFFICIENT_HOST_MSR_STORAGE 6 +/** MSR storage capacity of the VMCS autoload/store area is not sufficient + * for storing guest MSRs. */ +#define VMX_UFC_INSUFFICIENT_GUEST_MSR_STORAGE 7 +/** Invalid VMCS size. */ +#define VMX_UFC_INVALID_VMCS_SIZE 8 +/** Unsupported secondary processor-based VM-execution controls combo. */ +#define VMX_UFC_CTRL_PROC_EXEC2 9 +/** Invalid unrestricted-guest execution controls combo. */ +#define VMX_UFC_INVALID_UX_COMBO 10 +/** EPT flush type not supported. */ +#define VMX_UFC_EPT_FLUSH_TYPE_UNSUPPORTED 11 +/** EPT paging structure memory type is not write-back. */ +#define VMX_UFC_EPT_MEM_TYPE_NOT_WB 12 +/** EPT requires INVEPT instr. support but it's not available. */ +#define VMX_UFC_EPT_INVEPT_UNAVAILABLE 13 +/** EPT requires page-walk length of 4. */ +#define VMX_UFC_EPT_PAGE_WALK_LENGTH_UNSUPPORTED 14 +/** VMX VMWRITE all feature exposed to the guest but not supported on host. */ +#define VMX_UFC_GST_HOST_VMWRITE_ALL 15 +/** LBR stack size cannot be determined for the current CPU. */ +#define VMX_UFC_LBR_STACK_SIZE_UNKNOWN 16 +/** LBR stack size of the CPU exceeds our buffer size. */ +#define VMX_UFC_LBR_STACK_SIZE_OVERFLOW 17 +/** @} */ + +/** @name VMX HM-error codes for VERR_VMX_VMCS_FIELD_CACHE_INVALID. + * VCI = VMCS-field Cache Invalid. + * @{ + */ +/** Cache of VM-entry controls invalid. */ +#define VMX_VCI_CTRL_ENTRY 300 +/** Cache of VM-exit controls invalid. */ +#define VMX_VCI_CTRL_EXIT 301 +/** Cache of pin-based VM-execution controls invalid. */ +#define VMX_VCI_CTRL_PIN_EXEC 302 +/** Cache of processor-based VM-execution controls invalid. */ +#define VMX_VCI_CTRL_PROC_EXEC 303 +/** Cache of secondary processor-based VM-execution controls invalid. */ +#define VMX_VCI_CTRL_PROC_EXEC2 304 +/** Cache of exception bitmap invalid. */ +#define VMX_VCI_CTRL_XCPT_BITMAP 305 +/** Cache of TSC offset invalid. */ +#define VMX_VCI_CTRL_TSC_OFFSET 306 +/** Cache of tertiary processor-based VM-execution controls invalid. */ +#define VMX_VCI_CTRL_PROC_EXEC3 307 +/** @} */ + +/** @name VMX HM-error codes for VERR_VMX_INVALID_GUEST_STATE. + * IGS = Invalid Guest State. + * @{ + */ +/** An error occurred while checking invalid-guest-state. */ +#define VMX_IGS_ERROR 500 +/** The invalid guest-state checks did not find any reason why. */ +#define VMX_IGS_REASON_NOT_FOUND 501 +/** CR0 fixed1 bits invalid. */ +#define VMX_IGS_CR0_FIXED1 502 +/** CR0 fixed0 bits invalid. */ +#define VMX_IGS_CR0_FIXED0 503 +/** CR0.PE and CR0.PE invalid VT-x/host combination. */ +#define VMX_IGS_CR0_PG_PE_COMBO 504 +/** CR4 fixed1 bits invalid. */ +#define VMX_IGS_CR4_FIXED1 505 +/** CR4 fixed0 bits invalid. */ +#define VMX_IGS_CR4_FIXED0 506 +/** Reserved bits in VMCS' DEBUGCTL MSR field not set to 0 when + * VMX_VMCS_CTRL_ENTRY_LOAD_DEBUG is used. */ +#define VMX_IGS_DEBUGCTL_MSR_RESERVED 507 +/** CR0.PG not set for long-mode when not using unrestricted guest. */ +#define VMX_IGS_CR0_PG_LONGMODE 508 +/** CR4.PAE not set for long-mode guest when not using unrestricted guest. */ +#define VMX_IGS_CR4_PAE_LONGMODE 509 +/** CR4.PCIDE set for 32-bit guest. */ +#define VMX_IGS_CR4_PCIDE 510 +/** VMCS' DR7 reserved bits not set to 0. */ +#define VMX_IGS_DR7_RESERVED 511 +/** VMCS' PERF_GLOBAL MSR reserved bits not set to 0. */ +#define VMX_IGS_PERF_GLOBAL_MSR_RESERVED 512 +/** VMCS' EFER MSR reserved bits not set to 0. */ +#define VMX_IGS_EFER_MSR_RESERVED 513 +/** VMCS' EFER MSR.LMA does not match the IA32e mode guest control. */ +#define VMX_IGS_EFER_LMA_GUEST_MODE_MISMATCH 514 +/** VMCS' EFER MSR.LMA does not match EFER.LME of the guest when using paging + * without unrestricted guest. */ +#define VMX_IGS_EFER_LMA_LME_MISMATCH 515 +/** CS.Attr.P bit invalid. */ +#define VMX_IGS_CS_ATTR_P_INVALID 516 +/** CS.Attr reserved bits not set to 0. */ +#define VMX_IGS_CS_ATTR_RESERVED 517 +/** CS.Attr.G bit invalid. */ +#define VMX_IGS_CS_ATTR_G_INVALID 518 +/** CS is unusable. */ +#define VMX_IGS_CS_ATTR_UNUSABLE 519 +/** CS and SS DPL unequal. */ +#define VMX_IGS_CS_SS_ATTR_DPL_UNEQUAL 520 +/** CS and SS DPL mismatch. */ +#define VMX_IGS_CS_SS_ATTR_DPL_MISMATCH 521 +/** CS Attr.Type invalid. */ +#define VMX_IGS_CS_ATTR_TYPE_INVALID 522 +/** CS and SS RPL unequal. */ +#define VMX_IGS_SS_CS_RPL_UNEQUAL 523 +/** SS.Attr.DPL and SS RPL unequal. */ +#define VMX_IGS_SS_ATTR_DPL_RPL_UNEQUAL 524 +/** SS.Attr.DPL invalid for segment type. */ +#define VMX_IGS_SS_ATTR_DPL_INVALID 525 +/** SS.Attr.Type invalid. */ +#define VMX_IGS_SS_ATTR_TYPE_INVALID 526 +/** SS.Attr.P bit invalid. */ +#define VMX_IGS_SS_ATTR_P_INVALID 527 +/** SS.Attr reserved bits not set to 0. */ +#define VMX_IGS_SS_ATTR_RESERVED 528 +/** SS.Attr.G bit invalid. */ +#define VMX_IGS_SS_ATTR_G_INVALID 529 +/** DS.Attr.A bit invalid. */ +#define VMX_IGS_DS_ATTR_A_INVALID 530 +/** DS.Attr.P bit invalid. */ +#define VMX_IGS_DS_ATTR_P_INVALID 531 +/** DS.Attr.DPL and DS RPL unequal. */ +#define VMX_IGS_DS_ATTR_DPL_RPL_UNEQUAL 532 +/** DS.Attr reserved bits not set to 0. */ +#define VMX_IGS_DS_ATTR_RESERVED 533 +/** DS.Attr.G bit invalid. */ +#define VMX_IGS_DS_ATTR_G_INVALID 534 +/** DS.Attr.Type invalid. */ +#define VMX_IGS_DS_ATTR_TYPE_INVALID 535 +/** ES.Attr.A bit invalid. */ +#define VMX_IGS_ES_ATTR_A_INVALID 536 +/** ES.Attr.P bit invalid. */ +#define VMX_IGS_ES_ATTR_P_INVALID 537 +/** ES.Attr.DPL and DS RPL unequal. */ +#define VMX_IGS_ES_ATTR_DPL_RPL_UNEQUAL 538 +/** ES.Attr reserved bits not set to 0. */ +#define VMX_IGS_ES_ATTR_RESERVED 539 +/** ES.Attr.G bit invalid. */ +#define VMX_IGS_ES_ATTR_G_INVALID 540 +/** ES.Attr.Type invalid. */ +#define VMX_IGS_ES_ATTR_TYPE_INVALID 541 +/** FS.Attr.A bit invalid. */ +#define VMX_IGS_FS_ATTR_A_INVALID 542 +/** FS.Attr.P bit invalid. */ +#define VMX_IGS_FS_ATTR_P_INVALID 543 +/** FS.Attr.DPL and DS RPL unequal. */ +#define VMX_IGS_FS_ATTR_DPL_RPL_UNEQUAL 544 +/** FS.Attr reserved bits not set to 0. */ +#define VMX_IGS_FS_ATTR_RESERVED 545 +/** FS.Attr.G bit invalid. */ +#define VMX_IGS_FS_ATTR_G_INVALID 546 +/** FS.Attr.Type invalid. */ +#define VMX_IGS_FS_ATTR_TYPE_INVALID 547 +/** GS.Attr.A bit invalid. */ +#define VMX_IGS_GS_ATTR_A_INVALID 548 +/** GS.Attr.P bit invalid. */ +#define VMX_IGS_GS_ATTR_P_INVALID 549 +/** GS.Attr.DPL and DS RPL unequal. */ +#define VMX_IGS_GS_ATTR_DPL_RPL_UNEQUAL 550 +/** GS.Attr reserved bits not set to 0. */ +#define VMX_IGS_GS_ATTR_RESERVED 551 +/** GS.Attr.G bit invalid. */ +#define VMX_IGS_GS_ATTR_G_INVALID 552 +/** GS.Attr.Type invalid. */ +#define VMX_IGS_GS_ATTR_TYPE_INVALID 553 +/** V86 mode CS.Base invalid. */ +#define VMX_IGS_V86_CS_BASE_INVALID 554 +/** V86 mode CS.Limit invalid. */ +#define VMX_IGS_V86_CS_LIMIT_INVALID 555 +/** V86 mode CS.Attr invalid. */ +#define VMX_IGS_V86_CS_ATTR_INVALID 556 +/** V86 mode SS.Base invalid. */ +#define VMX_IGS_V86_SS_BASE_INVALID 557 +/** V86 mode SS.Limit invalid. */ +#define VMX_IGS_V86_SS_LIMIT_INVALID 558 +/** V86 mode SS.Attr invalid. */ +#define VMX_IGS_V86_SS_ATTR_INVALID 559 +/** V86 mode DS.Base invalid. */ +#define VMX_IGS_V86_DS_BASE_INVALID 560 +/** V86 mode DS.Limit invalid. */ +#define VMX_IGS_V86_DS_LIMIT_INVALID 561 +/** V86 mode DS.Attr invalid. */ +#define VMX_IGS_V86_DS_ATTR_INVALID 562 +/** V86 mode ES.Base invalid. */ +#define VMX_IGS_V86_ES_BASE_INVALID 563 +/** V86 mode ES.Limit invalid. */ +#define VMX_IGS_V86_ES_LIMIT_INVALID 564 +/** V86 mode ES.Attr invalid. */ +#define VMX_IGS_V86_ES_ATTR_INVALID 565 +/** V86 mode FS.Base invalid. */ +#define VMX_IGS_V86_FS_BASE_INVALID 566 +/** V86 mode FS.Limit invalid. */ +#define VMX_IGS_V86_FS_LIMIT_INVALID 567 +/** V86 mode FS.Attr invalid. */ +#define VMX_IGS_V86_FS_ATTR_INVALID 568 +/** V86 mode GS.Base invalid. */ +#define VMX_IGS_V86_GS_BASE_INVALID 569 +/** V86 mode GS.Limit invalid. */ +#define VMX_IGS_V86_GS_LIMIT_INVALID 570 +/** V86 mode GS.Attr invalid. */ +#define VMX_IGS_V86_GS_ATTR_INVALID 571 +/** Longmode CS.Base invalid. */ +#define VMX_IGS_LONGMODE_CS_BASE_INVALID 572 +/** Longmode SS.Base invalid. */ +#define VMX_IGS_LONGMODE_SS_BASE_INVALID 573 +/** Longmode DS.Base invalid. */ +#define VMX_IGS_LONGMODE_DS_BASE_INVALID 574 +/** Longmode ES.Base invalid. */ +#define VMX_IGS_LONGMODE_ES_BASE_INVALID 575 +/** SYSENTER ESP is not canonical. */ +#define VMX_IGS_SYSENTER_ESP_NOT_CANONICAL 576 +/** SYSENTER EIP is not canonical. */ +#define VMX_IGS_SYSENTER_EIP_NOT_CANONICAL 577 +/** PAT MSR invalid. */ +#define VMX_IGS_PAT_MSR_INVALID 578 +/** PAT MSR reserved bits not set to 0. */ +#define VMX_IGS_PAT_MSR_RESERVED 579 +/** GDTR.Base is not canonical. */ +#define VMX_IGS_GDTR_BASE_NOT_CANONICAL 580 +/** IDTR.Base is not canonical. */ +#define VMX_IGS_IDTR_BASE_NOT_CANONICAL 581 +/** GDTR.Limit invalid. */ +#define VMX_IGS_GDTR_LIMIT_INVALID 582 +/** IDTR.Limit invalid. */ +#define VMX_IGS_IDTR_LIMIT_INVALID 583 +/** Longmode RIP is invalid. */ +#define VMX_IGS_LONGMODE_RIP_INVALID 584 +/** RFLAGS reserved bits not set to 0. */ +#define VMX_IGS_RFLAGS_RESERVED 585 +/** RFLAGS RA1 reserved bits not set to 1. */ +#define VMX_IGS_RFLAGS_RESERVED1 586 +/** RFLAGS.VM (V86 mode) invalid. */ +#define VMX_IGS_RFLAGS_VM_INVALID 587 +/** RFLAGS.IF invalid. */ +#define VMX_IGS_RFLAGS_IF_INVALID 588 +/** Activity state invalid. */ +#define VMX_IGS_ACTIVITY_STATE_INVALID 589 +/** Activity state HLT invalid when SS.Attr.DPL is not zero. */ +#define VMX_IGS_ACTIVITY_STATE_HLT_INVALID 590 +/** Activity state ACTIVE invalid when block-by-STI or MOV SS. */ +#define VMX_IGS_ACTIVITY_STATE_ACTIVE_INVALID 591 +/** Activity state SIPI WAIT invalid. */ +#define VMX_IGS_ACTIVITY_STATE_SIPI_WAIT_INVALID 592 +/** Interruptibility state reserved bits not set to 0. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_RESERVED 593 +/** Interruptibility state cannot be block-by-STI -and- MOV SS. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_STI_MOVSS_INVALID 594 +/** Interruptibility state block-by-STI invalid for EFLAGS. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_STI_EFL_INVALID 595 +/** Interruptibility state invalid while trying to deliver external + * interrupt. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_EXT_INT_INVALID 596 +/** Interruptibility state block-by-MOVSS invalid while trying to deliver an + * NMI. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_MOVSS_INVALID 597 +/** Interruptibility state block-by-SMI invalid when CPU is not in SMM. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_SMI_INVALID 598 +/** Interruptibility state block-by-SMI invalid when trying to enter SMM. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_SMI_SMM_INVALID 599 +/** Interruptibility state block-by-STI (maybe) invalid when trying to + * deliver an NMI. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_STI_INVALID 600 +/** Interruptibility state block-by-NMI invalid when virtual-NMIs control is + * active. */ +#define VMX_IGS_INTERRUPTIBILITY_STATE_NMI_INVALID 601 +/** Pending debug exceptions reserved bits not set to 0. */ +#define VMX_IGS_PENDING_DEBUG_RESERVED 602 +/** Longmode pending debug exceptions reserved bits not set to 0. */ +#define VMX_IGS_LONGMODE_PENDING_DEBUG_RESERVED 603 +/** Pending debug exceptions.BS bit is not set when it should be. */ +#define VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_SET 604 +/** Pending debug exceptions.BS bit is not clear when it should be. */ +#define VMX_IGS_PENDING_DEBUG_XCPT_BS_NOT_CLEAR 605 +/** VMCS link pointer reserved bits not set to 0. */ +#define VMX_IGS_VMCS_LINK_PTR_RESERVED 606 +/** TR cannot index into LDT, TI bit MBZ. */ +#define VMX_IGS_TR_TI_INVALID 607 +/** LDTR cannot index into LDT. TI bit MBZ. */ +#define VMX_IGS_LDTR_TI_INVALID 608 +/** TR.Base is not canonical. */ +#define VMX_IGS_TR_BASE_NOT_CANONICAL 609 +/** FS.Base is not canonical. */ +#define VMX_IGS_FS_BASE_NOT_CANONICAL 610 +/** GS.Base is not canonical. */ +#define VMX_IGS_GS_BASE_NOT_CANONICAL 611 +/** LDTR.Base is not canonical. */ +#define VMX_IGS_LDTR_BASE_NOT_CANONICAL 612 +/** TR is unusable. */ +#define VMX_IGS_TR_ATTR_UNUSABLE 613 +/** TR.Attr.S bit invalid. */ +#define VMX_IGS_TR_ATTR_S_INVALID 614 +/** TR is not present. */ +#define VMX_IGS_TR_ATTR_P_INVALID 615 +/** TR.Attr reserved bits not set to 0. */ +#define VMX_IGS_TR_ATTR_RESERVED 616 +/** TR.Attr.G bit invalid. */ +#define VMX_IGS_TR_ATTR_G_INVALID 617 +/** Longmode TR.Attr.Type invalid. */ +#define VMX_IGS_LONGMODE_TR_ATTR_TYPE_INVALID 618 +/** TR.Attr.Type invalid. */ +#define VMX_IGS_TR_ATTR_TYPE_INVALID 619 +/** CS.Attr.S invalid. */ +#define VMX_IGS_CS_ATTR_S_INVALID 620 +/** CS.Attr.DPL invalid. */ +#define VMX_IGS_CS_ATTR_DPL_INVALID 621 +/** PAE PDPTE reserved bits not set to 0. */ +#define VMX_IGS_PAE_PDPTE_RESERVED 623 +/** VMCS link pointer does not point to a shadow VMCS. */ +#define VMX_IGS_VMCS_LINK_PTR_NOT_SHADOW 624 +/** VMCS link pointer to a shadow VMCS with invalid VMCS revision identifer. */ +#define VMX_IGS_VMCS_LINK_PTR_SHADOW_VMCS_ID_INVALID 625 +/** @} */ + +/** @name VMX VMCS-Read cache indices. + * @{ + */ +#define VMX_VMCS_GUEST_ES_BASE_CACHE_IDX 0 +#define VMX_VMCS_GUEST_CS_BASE_CACHE_IDX 1 +#define VMX_VMCS_GUEST_SS_BASE_CACHE_IDX 2 +#define VMX_VMCS_GUEST_DS_BASE_CACHE_IDX 3 +#define VMX_VMCS_GUEST_FS_BASE_CACHE_IDX 4 +#define VMX_VMCS_GUEST_GS_BASE_CACHE_IDX 5 +#define VMX_VMCS_GUEST_LDTR_BASE_CACHE_IDX 6 +#define VMX_VMCS_GUEST_TR_BASE_CACHE_IDX 7 +#define VMX_VMCS_GUEST_GDTR_BASE_CACHE_IDX 8 +#define VMX_VMCS_GUEST_IDTR_BASE_CACHE_IDX 9 +#define VMX_VMCS_GUEST_RSP_CACHE_IDX 10 +#define VMX_VMCS_GUEST_RIP_CACHE_IDX 11 +#define VMX_VMCS_GUEST_SYSENTER_ESP_CACHE_IDX 12 +#define VMX_VMCS_GUEST_SYSENTER_EIP_CACHE_IDX 13 +#define VMX_VMCS_RO_EXIT_QUALIFICATION_CACHE_IDX 14 +#define VMX_VMCS_RO_GUEST_LINEAR_ADDR_CACHE_IDX 15 +#define VMX_VMCS_MAX_CACHE_IDX (VMX_VMCS_RO_GUEST_LINEAR_ADDR_CACHE_IDX + 1) +#define VMX_VMCS_GUEST_CR3_CACHE_IDX 16 +#define VMX_VMCS_MAX_NESTED_PAGING_CACHE_IDX (VMX_VMCS_GUEST_CR3_CACHE_IDX + 1) +/** @} */ + + +/** @name VMX Extended Page Tables (EPT) Common Bits. + * @{ */ +/** Bit 0 - Readable (we often think of it as present). */ +#define EPT_E_BIT_READ 0 +#define EPT_E_READ RT_BIT_64(EPT_E_BIT_READ) /**< @see EPT_E_BIT_READ */ +/** Bit 1 - Writable. */ +#define EPT_E_BIT_WRITE 1 +#define EPT_E_WRITE RT_BIT_64(EPT_E_BIT_WRITE) /**< @see EPT_E_BIT_WRITE */ +/** Bit 2 - Executable. + * @note This controls supervisor instruction fetching if mode-based + * execution control is enabled. */ +#define EPT_E_BIT_EXECUTE 2 +#define EPT_E_EXECUTE RT_BIT_64(EPT_E_BIT_EXECUTE) /**< @see EPT_E_BIT_EXECUTE */ +/** Bits 3-5 - Memory type mask (leaf only, MBZ). + * The memory type is only applicable for leaf entries and MBZ for + * non-leaf (causes miconfiguration exit). */ +#define EPT_E_MEMTYPE_MASK UINT64_C(0x0038) +/** Bits 3-5 - Memory type shifted mask. */ +#define EPT_E_MEMTYPE_SMASK UINT64_C(0x0007) +/** Bits 3-5 - Memory type shift count. */ +#define EPT_E_MEMTYPE_SHIFT 3 +/** Bits 3-5 - Memory type: UC (Uncacheable). */ +#define EPT_E_MEMTYPE_UC (UINT64_C(0) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: WC (Write Combining). */ +#define EPT_E_MEMTYPE_WC (UINT64_C(1) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: Invalid (2). */ +#define EPT_E_MEMTYPE_INVALID_2 (UINT64_C(2) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: Invalid (3). */ +#define EPT_E_MEMTYPE_INVALID_3 (UINT64_C(3) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: WT (Write Through). */ +#define EPT_E_MEMTYPE_WT (UINT64_C(4) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: WP (Write Protected). */ +#define EPT_E_MEMTYPE_WP (UINT64_C(5) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: WB (Write Back). */ +#define EPT_E_MEMTYPE_WB (UINT64_C(6) << EPT_E_MEMTYPE_SHIFT) +/** Bits 3-5 - Memory type: Invalid (7). */ +#define EPT_E_MEMTYPE_INVALID_7 (UINT64_C(7) << EPT_E_MEMTYPE_SHIFT) +/** Bit 6 - Ignore page attribute table (leaf, MBZ). */ +#define EPT_E_BIT_IGNORE_PAT 6 +#define EPT_E_IGNORE_PAT RT_BIT_64(EPT_E_BIT_IGNORE_PAT) /**< @see EPT_E_BIT_IGNORE_PAT */ +/** Bit 7 - Leaf entry (MBZ in PML4, ignored in PT). */ +#define EPT_E_BIT_LEAF 7 +#define EPT_E_LEAF RT_BIT_64(EPT_E_BIT_LEAF) /**< @see EPT_E_BIT_LEAF */ +/** Bit 8 - Accessed (all levels). + * @note Ignored and not written when EPTP bit 6 is 0. */ +#define EPT_E_BIT_ACCESSED 8 +#define EPT_E_ACCESSED RT_BIT_64(EPT_E_BIT_ACCESSED) /**< @see EPT_E_BIT_ACCESSED */ +/** Bit 9 - Dirty (leaf only). + * @note Ignored and not written when EPTP bit 6 is 0. */ +#define EPT_E_BIT_DIRTY 9 +#define EPT_E_DIRTY RT_BIT_64(EPT_E_BIT_DIRTY) /**< @see EPT_E_BIT_DIRTY */ +/** Bit 10 - Executable for usermode. + * @note This ignored if mode-based execution control is disabled. */ +#define EPT_E_BIT_USER_EXECUTE 10 +#define EPT_E_USER_EXECUTE RT_BIT_64(EPT_E_BIT_USER_EXECUTE) /**< @see EPT_E_BIT_USER_EXECUTE */ +/* Bit 11 is always ignored. */ +/** Bits 12-51 - Physical Page number of the next level. */ +#define EPT_E_PG_MASK UINT64_C(0x000ffffffffff000) +/** Bit 58 - Page-write access (leaf only, ignored). + * @note Ignored if EPT page-write control is disabled. */ +#define EPT_E_BIT_PAGING_WRITE 58 +#define EPT_E_PAGING_WRITE RT_BIT_64(EPT_E_BIT_PAGING_WRITE) /**< @see EPT_E_BIT_PAGING_WRITE*/ +/* Bit 59 is always ignored. */ +/** Bit 60 - Supervisor shadow stack (leaf only, ignored). + * @note Ignored if EPT bit 7 is 0. */ +#define EPT_E_BIT_SUPER_SHW_STACK 60 +#define EPT_E_SUPER_SHW_STACK RT_BIT_64(EPT_E_BIT_SUPER_SHW_STACK) /**< @see EPT_E_BIT_SUPER_SHW_STACK */ +/** Bit 61 - Sub-page write permission (leaf only, ignored). + * @note Ignored if sub-page write permission for EPT is disabled. */ +#define EPT_E_BIT_SUBPAGE_WRITE_PERM 61 +#define EPT_E_SUBPAGE_WRITE_PERM RT_BIT_64(EPT_E_BIT_SUBPAGE_WRITE_PERM) /**< @see EPT_E_BIT_SUBPAGE_WRITE_PERM*/ +/* Bit 62 is always ignored. */ +/** Bit 63 - Suppress \#VE (leaf only, ignored). + * @note Ignored if EPT violation to \#VE conversion is disabled. */ +#define EPT_E_BIT_SUPPRESS_VE 63 +#define EPT_E_SUPPRESS_VE RT_BIT_64(EPT_E_BIT_SUPPRESS_VE) /**< @see EPT_E_BIT_SUPPRESS_VE */ +/** @} */ + + +/**@name Bit fields for common EPT attributes. + @{ */ +/** Read access. */ +#define VMX_BF_EPT_PT_READ_SHIFT 0 +#define VMX_BF_EPT_PT_READ_MASK UINT64_C(0x0000000000000001) +/** Write access. */ +#define VMX_BF_EPT_PT_WRITE_SHIFT 1 +#define VMX_BF_EPT_PT_WRITE_MASK UINT64_C(0x0000000000000002) +/** Execute access or execute access for supervisor-mode linear-addresses. */ +#define VMX_BF_EPT_PT_EXECUTE_SHIFT 2 +#define VMX_BF_EPT_PT_EXECUTE_MASK UINT64_C(0x0000000000000004) +/** EPT memory type. */ +#define VMX_BF_EPT_PT_MEMTYPE_SHIFT 3 +#define VMX_BF_EPT_PT_MEMTYPE_MASK UINT64_C(0x0000000000000038) +/** Ignore PAT. */ +#define VMX_BF_EPT_PT_IGNORE_PAT_SHIFT 6 +#define VMX_BF_EPT_PT_IGNORE_PAT_MASK UINT64_C(0x0000000000000040) +/** Ignored (bit 7). */ +#define VMX_BF_EPT_PT_IGN_7_SHIFT 7 +#define VMX_BF_EPT_PT_IGN_7_MASK UINT64_C(0x0000000000000080) +/** Accessed flag. */ +#define VMX_BF_EPT_PT_ACCESSED_SHIFT 8 +#define VMX_BF_EPT_PT_ACCESSED_MASK UINT64_C(0x0000000000000100) +/** Dirty flag. */ +#define VMX_BF_EPT_PT_DIRTY_SHIFT 9 +#define VMX_BF_EPT_PT_DIRTY_MASK UINT64_C(0x0000000000000200) +/** Execute access for user-mode linear addresses. */ +#define VMX_BF_EPT_PT_EXECUTE_USER_SHIFT 10 +#define VMX_BF_EPT_PT_EXECUTE_USER_MASK UINT64_C(0x0000000000000400) +/** Ignored (bit 59:11). */ +#define VMX_BF_EPT_PT_IGN_59_11_SHIFT 11 +#define VMX_BF_EPT_PT_IGN_59_11_MASK UINT64_C(0x0ffffffffffff800) +/** Supervisor shadow stack. */ +#define VMX_BF_EPT_PT_SUPER_SHW_STACK_SHIFT 60 +#define VMX_BF_EPT_PT_SUPER_SHW_STACK_MASK UINT64_C(0x1000000000000000) +/** Ignored (bits 62:61). */ +#define VMX_BF_EPT_PT_IGN_62_61_SHIFT 61 +#define VMX_BF_EPT_PT_IGN_62_61_MASK UINT64_C(0x6000000000000000) +/** Suppress \#VE. */ +#define VMX_BF_EPT_PT_SUPPRESS_VE_SHIFT 63 +#define VMX_BF_EPT_PT_SUPPRESS_VE_MASK UINT64_C(0x8000000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EPT_PT_, UINT64_C(0), UINT64_MAX, + (READ, WRITE, EXECUTE, MEMTYPE, IGNORE_PAT, IGN_7, ACCESSED, DIRTY, EXECUTE_USER, IGN_59_11, + SUPER_SHW_STACK, IGN_62_61, SUPPRESS_VE)); +/** @} */ + + +/** @name VMX Extended Page Tables (EPT) Structures + * @{ + */ + +/** + * Number of page table entries in the EPT. (PDPTE/PDE/PTE) + */ +#define EPT_PG_ENTRIES X86_PG_PAE_ENTRIES + +/** + * EPT present mask. + * These are ONLY the common bits in all EPT page-table entries which does + * not rely on any CPU feature. It isn't necessarily the complete mask (e.g. when + * mode-based excute control is active). + */ +#define EPT_PRESENT_MASK (EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE) + +/** + * EPT Page Directory Pointer Entry. Bit view. + * In accordance with the VT-x spec. + * + * @todo uint64_t isn't safe for bitfields (gcc pedantic warnings, and IIRC, + * this did cause trouble with one compiler/version). + */ +typedef struct EPTPML4EBITS +{ + /** Present bit. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** Reserved (must be 0). */ + RT_GCC_EXTENSION uint64_t u5Reserved : 5; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u4Available : 4; + /** Physical address of the next level (PD). Restricted by maximum physical address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u40PhysAddr : 40; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPML4EBITS; +AssertCompileSize(EPTPML4EBITS, 8); + +/** Bits 12-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PML4E_PG_MASK X86_PML4E_PG_MASK +/** The page shift to get the PML4 index. */ +#define EPT_PML4_SHIFT X86_PML4_SHIFT +/** The PML4 index mask (apply to a shifted page address). */ +#define EPT_PML4_MASK X86_PML4_MASK +/** Bits - - EPT - PML4 MBZ mask. */ +#define EPT_PML4E_MBZ_MASK UINT64_C(0x00000000000000f8) +/** Mask of all possible EPT PML4E attribute bits. */ +#define EPT_PML4E_ATTR_MASK (EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_ACCESSED | EPT_E_USER_EXECUTE) + +/** + * EPT PML4E. + * In accordance with the VT-x spec. + */ +typedef union EPTPML4E +{ +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + EPTPML4EBITS n; +#endif + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPML4E; +AssertCompileSize(EPTPML4E, 8); +/** Pointer to a PML4 table entry. */ +typedef EPTPML4E *PEPTPML4E; +/** Pointer to a const PML4 table entry. */ +typedef const EPTPML4E *PCEPTPML4E; + +/** + * EPT PML4 Table. + * In accordance with the VT-x spec. + */ +typedef struct EPTPML4 +{ + EPTPML4E a[EPT_PG_ENTRIES]; +} EPTPML4; +AssertCompileSize(EPTPML4, 0x1000); +/** Pointer to an EPT PML4 Table. */ +typedef EPTPML4 *PEPTPML4; +/** Pointer to a const EPT PML4 Table. */ +typedef const EPTPML4 *PCEPTPML4; + + +/** + * EPT Page Directory Pointer Entry. Bit view. + * In accordance with the VT-x spec. + */ +typedef struct EPTPDPTEBITS +{ + /** Present bit. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** Reserved (must be 0). */ + RT_GCC_EXTENSION uint64_t u5Reserved : 5; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u4Available : 4; + /** Physical address of the next level (PD). Restricted by maximum physical address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u40PhysAddr : 40; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPDPTEBITS; +AssertCompileSize(EPTPDPTEBITS, 8); + +/** Bit 7 - - EPT - PDPTE maps a 1GB page. */ +#define EPT_PDPTE1G_SIZE_MASK RT_BIT_64(7) +/** Bits 12-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PDPTE_PG_MASK X86_PDPE_PG_MASK +/** Bits 30-51 - - EPT - Physical Page number of the 1G large page. */ +#define EPT_PDPTE1G_PG_MASK X86_PDPE1G_PG_MASK + +/** The page shift to get the PDPT index. */ +#define EPT_PDPT_SHIFT X86_PDPT_SHIFT +/** The PDPT index mask (apply to a shifted page address). */ +#define EPT_PDPT_MASK X86_PDPT_MASK_AMD64 +/** Bits 3-7 - - EPT - PDPTE MBZ Mask. */ +#define EPT_PDPTE_MBZ_MASK UINT64_C(0x00000000000000f8) +/** Bits 12-29 - - EPT - 1GB PDPTE MBZ Mask. */ +#define EPT_PDPTE1G_MBZ_MASK UINT64_C(0x000000003ffff000) +/** Mask of all possible EPT PDPTE (1GB) attribute bits. */ +#define EPT_PDPTE1G_ATTR_MASK ( EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_MEMTYPE_MASK | EPT_E_IGNORE_PAT \ + | EPT_E_ACCESSED | EPT_E_DIRTY | EPT_E_USER_EXECUTE) +/** Mask of all possible EPT PDPTE attribute bits. */ +#define EPT_PDPTE_ATTR_MASK (EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_ACCESSED | EPT_E_USER_EXECUTE) +/** */ + +/** + * EPT Page Directory Pointer. + * In accordance with the VT-x spec. + */ +typedef union EPTPDPTE +{ +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + EPTPDPTEBITS n; +#endif + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPDPTE; +AssertCompileSize(EPTPDPTE, 8); +/** Pointer to an EPT Page Directory Pointer Entry. */ +typedef EPTPDPTE *PEPTPDPTE; +/** Pointer to a const EPT Page Directory Pointer Entry. */ +typedef const EPTPDPTE *PCEPTPDPTE; + +/** + * EPT Page Directory Pointer Table. + * In accordance with the VT-x spec. + */ +typedef struct EPTPDPT +{ + EPTPDPTE a[EPT_PG_ENTRIES]; +} EPTPDPT; +AssertCompileSize(EPTPDPT, 0x1000); +/** Pointer to an EPT Page Directory Pointer Table. */ +typedef EPTPDPT *PEPTPDPT; +/** Pointer to a const EPT Page Directory Pointer Table. */ +typedef const EPTPDPT *PCEPTPDPT; + + +/** + * EPT Page Directory Table Entry. Bit view. + * In accordance with the VT-x spec. + */ +typedef struct EPTPDEBITS +{ + /** Present bit. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** Reserved (must be 0). */ + RT_GCC_EXTENSION uint64_t u4Reserved : 4; + /** Big page (must be 0 here). */ + RT_GCC_EXTENSION uint64_t u1Size : 1; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u4Available : 4; + /** Physical address of page table. Restricted by maximum physical address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u40PhysAddr : 40; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPDEBITS; +AssertCompileSize(EPTPDEBITS, 8); + +/** Bits 12-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PDE_PG_MASK X86_PDE_PAE_PG_MASK +/** The page shift to get the PD index. */ +#define EPT_PD_SHIFT X86_PD_PAE_SHIFT +/** The PD index mask (apply to a shifted page address). */ +#define EPT_PD_MASK X86_PD_PAE_MASK +/** Bits 3-7 - EPT - PDE MBZ Mask. */ +#define EPT_PDE_MBZ_MASK UINT64_C(0x00000000000000f8) +/** Mask of all possible EPT PDE (2M) attribute bits. */ +#define EPT_PDE2M_ATTR_MASK ( EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_MEMTYPE_MASK | EPT_E_IGNORE_PAT \ + | EPT_E_ACCESSED | EPT_E_DIRTY | EPT_E_USER_EXECUTE) +/** Mask of all possible EPT PDE attribute bits. */ +#define EPT_PDE_ATTR_MASK (EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_ACCESSED | EPT_E_USER_EXECUTE) + + +/** + * EPT 2MB Page Directory Table Entry. Bit view. + * In accordance with the VT-x spec. + */ +typedef struct EPTPDE2MBITS +{ + /** Present bit. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** EPT Table Memory Type. MBZ for non-leaf nodes. */ + RT_GCC_EXTENSION uint64_t u3EMT : 3; + /** Ignore PAT memory type */ + RT_GCC_EXTENSION uint64_t u1IgnorePAT : 1; + /** Big page (must be 1 here). */ + RT_GCC_EXTENSION uint64_t u1Size : 1; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u4Available : 4; + /** Reserved (must be 0). */ + RT_GCC_EXTENSION uint64_t u9Reserved : 9; + /** Physical address of the 2MB page. Restricted by maximum physical address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u31PhysAddr : 31; + /** Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPDE2MBITS; +AssertCompileSize(EPTPDE2MBITS, 8); + +/** Bits 21-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PDE2M_PG_MASK X86_PDE2M_PAE_PG_MASK +/** Bits 20-12 - - EPT - PDE 2M MBZ Mask. */ +#define EPT_PDE2M_MBZ_MASK UINT64_C(0x00000000001ff000) + + +/** + * EPT Page Directory Table Entry. + * In accordance with the VT-x spec. + */ +typedef union EPTPDE +{ +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + EPTPDEBITS n; + /** 2MB view (big). */ + EPTPDE2MBITS b; +#endif + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPDE; +AssertCompileSize(EPTPDE, 8); +/** Pointer to an EPT Page Directory Table Entry. */ +typedef EPTPDE *PEPTPDE; +/** Pointer to a const EPT Page Directory Table Entry. */ +typedef const EPTPDE *PCEPTPDE; + +/** + * EPT Page Directory Table. + * In accordance with the VT-x spec. + */ +typedef struct EPTPD +{ + EPTPDE a[EPT_PG_ENTRIES]; +} EPTPD; +AssertCompileSize(EPTPD, 0x1000); +/** Pointer to an EPT Page Directory Table. */ +typedef EPTPD *PEPTPD; +/** Pointer to a const EPT Page Directory Table. */ +typedef const EPTPD *PCEPTPD; + +/** + * EPT Page Table Entry. Bit view. + * In accordance with the VT-x spec. + */ +typedef struct EPTPTEBITS +{ + /** 0 - Present bit. + * @remarks This is a convenience "misnomer". The bit actually indicates read access + * and the CPU will consider an entry with any of the first three bits set + * as present. Since all our valid entries will have this bit set, it can + * be used as a present indicator and allow some code sharing. */ + RT_GCC_EXTENSION uint64_t u1Present : 1; + /** 1 - Writable bit. */ + RT_GCC_EXTENSION uint64_t u1Write : 1; + /** 2 - Executable bit. */ + RT_GCC_EXTENSION uint64_t u1Execute : 1; + /** 5:3 - EPT Memory Type. MBZ for non-leaf nodes. */ + RT_GCC_EXTENSION uint64_t u3EMT : 3; + /** 6 - Ignore PAT memory type */ + RT_GCC_EXTENSION uint64_t u1IgnorePAT : 1; + /** 11:7 - Available for software. */ + RT_GCC_EXTENSION uint64_t u5Available : 5; + /** 51:12 - Physical address of page. Restricted by maximum physical + * address width of the cpu. */ + RT_GCC_EXTENSION uint64_t u40PhysAddr : 40; + /** 63:52 - Available for software. */ + RT_GCC_EXTENSION uint64_t u12Available : 12; +} EPTPTEBITS; +AssertCompileSize(EPTPTEBITS, 8); + +/** Bits 12-51 - - EPT - Physical Page number of the next level. */ +#define EPT_PTE_PG_MASK X86_PTE_PAE_PG_MASK +/** The page shift to get the EPT PTE index. */ +#define EPT_PT_SHIFT X86_PT_PAE_SHIFT +/** The EPT PT index mask (apply to a shifted page address). */ +#define EPT_PT_MASK X86_PT_PAE_MASK +/** No bits - - EPT - PTE MBZ bits. */ +#define EPT_PTE_MBZ_MASK UINT64_C(0x0000000000000000) +/** Mask of all possible EPT PTE attribute bits. */ +#define EPT_PTE_ATTR_MASK ( EPT_E_READ | EPT_E_WRITE | EPT_E_EXECUTE | EPT_E_MEMTYPE_MASK | EPT_E_IGNORE_PAT \ + | EPT_E_ACCESSED | EPT_E_USER_EXECUTE) + + +/** + * EPT Page Table Entry. + * In accordance with the VT-x spec. + */ +typedef union EPTPTE +{ +#ifndef VBOX_WITHOUT_PAGING_BIT_FIELDS + /** Normal view. */ + EPTPTEBITS n; +#endif + /** Unsigned integer view. */ + X86PGPAEUINT u; + /** 64 bit unsigned integer view. */ + uint64_t au64[1]; + /** 32 bit unsigned integer view. */ + uint32_t au32[2]; +} EPTPTE; +AssertCompileSize(EPTPTE, 8); +/** Pointer to an EPT Page Directory Table Entry. */ +typedef EPTPTE *PEPTPTE; +/** Pointer to a const EPT Page Directory Table Entry. */ +typedef const EPTPTE *PCEPTPTE; + +/** + * EPT Page Table. + * In accordance with the VT-x spec. + */ +typedef struct EPTPT +{ + EPTPTE a[EPT_PG_ENTRIES]; +} EPTPT; +AssertCompileSize(EPTPT, 0x1000); +/** Pointer to an extended page table. */ +typedef EPTPT *PEPTPT; +/** Pointer to a const extended table. */ +typedef const EPTPT *PCEPTPT; + +/** EPTP page mask for the EPT PML4 table. */ +#define EPT_EPTP_PG_MASK X86_CR3_AMD64_PAGE_MASK +/** @} */ + +/** + * VMX VPID flush types. + * Valid enum members are in accordance with the VT-x spec. + */ +typedef enum +{ + /** Invalidate a specific page. */ + VMXTLBFLUSHVPID_INDIV_ADDR = 0, + /** Invalidate one context (specific VPID). */ + VMXTLBFLUSHVPID_SINGLE_CONTEXT = 1, + /** Invalidate all contexts (all VPIDs). */ + VMXTLBFLUSHVPID_ALL_CONTEXTS = 2, + /** Invalidate a single VPID context retaining global mappings. */ + VMXTLBFLUSHVPID_SINGLE_CONTEXT_RETAIN_GLOBALS = 3, + /** Unsupported by VirtualBox. */ + VMXTLBFLUSHVPID_NOT_SUPPORTED = 0xbad0, + /** Unsupported by CPU. */ + VMXTLBFLUSHVPID_NONE = 0xbad1 +} VMXTLBFLUSHVPID; +AssertCompileSize(VMXTLBFLUSHVPID, 4); +/** Mask of all valid INVVPID flush types. */ +#define VMX_INVVPID_VALID_MASK ( VMXTLBFLUSHVPID_INDIV_ADDR \ + | VMXTLBFLUSHVPID_SINGLE_CONTEXT \ + | VMXTLBFLUSHVPID_ALL_CONTEXTS \ + | VMXTLBFLUSHVPID_SINGLE_CONTEXT_RETAIN_GLOBALS) + +/** + * VMX EPT flush types. + * @note Valid enums values are in accordance with the VT-x spec. + */ +typedef enum +{ + /** Invalidate one context (specific EPT). */ + VMXTLBFLUSHEPT_SINGLE_CONTEXT = 1, + /* Invalidate all contexts (all EPTs) */ + VMXTLBFLUSHEPT_ALL_CONTEXTS = 2, + /** Unsupported by VirtualBox. */ + VMXTLBFLUSHEPT_NOT_SUPPORTED = 0xbad0, + /** Unsupported by CPU. */ + VMXTLBFLUSHEPT_NONE = 0xbad1 +} VMXTLBFLUSHEPT; +AssertCompileSize(VMXTLBFLUSHEPT, 4); +/** Mask of all valid INVEPT flush types. */ +#define VMX_INVEPT_VALID_MASK ( VMXTLBFLUSHEPT_SINGLE_CONTEXT \ + | VMXTLBFLUSHEPT_ALL_CONTEXTS) + +/** + * VMX Posted Interrupt Descriptor. + * In accordance with the VT-x spec. + */ +typedef struct VMXPOSTEDINTRDESC +{ + uint32_t aVectorBitmap[8]; + uint32_t fOutstandingNotification : 1; + uint32_t uReserved0 : 31; + uint8_t au8Reserved0[28]; +} VMXPOSTEDINTRDESC; +AssertCompileMemberSize(VMXPOSTEDINTRDESC, aVectorBitmap, 32); +AssertCompileSize(VMXPOSTEDINTRDESC, 64); +/** Pointer to a posted interrupt descriptor. */ +typedef VMXPOSTEDINTRDESC *PVMXPOSTEDINTRDESC; +/** Pointer to a const posted interrupt descriptor. */ +typedef const VMXPOSTEDINTRDESC *PCVMXPOSTEDINTRDESC; + +/** + * VMX VMCS revision identifier. + * In accordance with the VT-x spec. + */ +typedef union +{ + struct + { + /** Revision identifier. */ + uint32_t u31RevisionId : 31; + /** Whether this is a shadow VMCS. */ + uint32_t fIsShadowVmcs : 1; + } n; + /* The unsigned integer view. */ + uint32_t u; +} VMXVMCSREVID; +AssertCompileSize(VMXVMCSREVID, 4); +/** Pointer to the VMXVMCSREVID union. */ +typedef VMXVMCSREVID *PVMXVMCSREVID; +/** Pointer to a const VMXVMCSREVID union. */ +typedef const VMXVMCSREVID *PCVMXVMCSREVID; + +/** + * VMX VM-exit instruction information. + * In accordance with the VT-x spec. + */ +typedef union +{ + /** Plain unsigned int representation. */ + uint32_t u; + + /** INS and OUTS information. */ + struct + { + uint32_t u7Reserved0 : 7; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + uint32_t u5Reserved1 : 5; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + uint32_t uReserved2 : 14; + } StrIo; + + /** INVEPT, INVPCID, INVVPID information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u5Undef0 : 5; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Cleared to 0. */ + uint32_t u1Cleared0 : 1; + uint32_t u4Undef0 : 4; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Register 2 (X86_GREG_XXX). */ + uint32_t iReg2 : 4; + } Inv; + + /** VMCLEAR, VMPTRLD, VMPTRST, VMXON, XRSTORS, XSAVES information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u5Reserved0 : 5; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Cleared to 0. */ + uint32_t u1Cleared0 : 1; + uint32_t u4Reserved0 : 4; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Register 2 (X86_GREG_XXX). */ + uint32_t iReg2 : 4; + } VmxXsave; + + /** LIDT, LGDT, SIDT, SGDT information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u5Undef0 : 5; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Always cleared to 0. */ + uint32_t u1Cleared0 : 1; + /** Operand size; 0=16-bit, 1=32-bit, undefined for 64-bit. */ + uint32_t uOperandSize : 1; + uint32_t u3Undef0 : 3; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Instruction identity (VMX_INSTR_ID_XXX). */ + uint32_t u2InstrId : 2; + uint32_t u2Undef0 : 2; + } GdtIdt; + + /** LLDT, LTR, SLDT, STR information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u1Undef0 : 1; + /** Register 1 (X86_GREG_XXX). */ + uint32_t iReg1 : 4; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Memory/Register - Always cleared to 0 to indicate memory operand. */ + uint32_t fIsRegOperand : 1; + uint32_t u4Undef0 : 4; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Instruction identity (VMX_INSTR_ID_XXX). */ + uint32_t u2InstrId : 2; + uint32_t u2Undef0 : 2; + } LdtTr; + + /** RDRAND, RDSEED information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Undef0 : 2; + /** Destination register (X86_GREG_XXX). */ + uint32_t iReg1 : 4; + uint32_t u4Undef0 : 4; + /** Operand size; 0=16-bit, 1=32-bit, 2=64-bit, 3=unused. */ + uint32_t u2OperandSize : 2; + uint32_t u19Def0 : 20; + } RdrandRdseed; + + /** VMREAD, VMWRITE information. */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u1Undef0 : 1; + /** Register 1 (X86_GREG_XXX). */ + uint32_t iReg1 : 4; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Memory or register operand. */ + uint32_t fIsRegOperand : 1; + /** Operand size; 0=16-bit, 1=32-bit, 2=64-bit, 3=unused. */ + uint32_t u4Undef0 : 4; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Register 2 (X86_GREG_XXX). */ + uint32_t iReg2 : 4; + } VmreadVmwrite; + + struct + { + uint32_t u2Undef0 : 3; + /** First XMM register operand. */ + uint32_t u4XmmReg1 : 4; + uint32_t u23Undef1 : 21; + /** Second XMM register operand. */ + uint32_t u4XmmReg2 : 4; + } LoadIwkey; + + /** This is a combination field of all instruction information. Note! Not all field + * combinations are valid (e.g., iReg1 is undefined for memory operands) and + * specialized fields are overwritten by their generic counterparts (e.g. no + * instruction identity field). */ + struct + { + /** Scaling; 0=no scaling, 1=scale-by-2, 2=scale-by-4, 3=scale-by-8. */ + uint32_t u2Scaling : 2; + uint32_t u1Undef0 : 1; + /** Register 1 (X86_GREG_XXX). */ + uint32_t iReg1 : 4; + /** The address size; 0=16-bit, 1=32-bit, 2=64-bit, rest undefined. */ + uint32_t u3AddrSize : 3; + /** Memory/Register - Always cleared to 0 to indicate memory operand. */ + uint32_t fIsRegOperand : 1; + /** Operand size; 0=16-bit, 1=32-bit, 2=64-bit, 3=unused. */ + uint32_t uOperandSize : 2; + uint32_t u2Undef0 : 2; + /** The segment register (X86_SREG_XXX). */ + uint32_t iSegReg : 3; + /** The index register (X86_GREG_XXX). */ + uint32_t iIdxReg : 4; + /** Set if index register is invalid. */ + uint32_t fIdxRegInvalid : 1; + /** The base register (X86_GREG_XXX). */ + uint32_t iBaseReg : 4; + /** Set if base register is invalid. */ + uint32_t fBaseRegInvalid : 1; + /** Register 2 (X86_GREG_XXX) or instruction identity. */ + uint32_t iReg2 : 4; + } All; +} VMXEXITINSTRINFO; +AssertCompileSize(VMXEXITINSTRINFO, 4); +/** Pointer to a VMX VM-exit instruction info. struct. */ +typedef VMXEXITINSTRINFO *PVMXEXITINSTRINFO; +/** Pointer to a const VMX VM-exit instruction info. struct. */ +typedef const VMXEXITINSTRINFO *PCVMXEXITINSTRINFO; + + +/** @name VM-entry failure reported in Exit qualification. + * See Intel spec. 26.7 "VM-entry failures during or after loading guest-state". + * @{ + */ +/** No errors during VM-entry. */ +#define VMX_ENTRY_FAIL_QUAL_NO_ERROR (0) +/** Not used. */ +#define VMX_ENTRY_FAIL_QUAL_NOT_USED (1) +/** Error while loading PDPTEs. */ +#define VMX_ENTRY_FAIL_QUAL_PDPTE (2) +/** NMI injection when blocking-by-STI is set. */ +#define VMX_ENTRY_FAIL_QUAL_NMI_INJECT (3) +/** Invalid VMCS link pointer. */ +#define VMX_ENTRY_FAIL_QUAL_VMCS_LINK_PTR (4) +/** @} */ + + +/** @name VMXMSRPM_XXX - VMX MSR-bitmap permissions. + * These are -not- specified by Intel but used internally by VirtualBox. + * @{ */ +/** Guest software reads of this MSR must not cause a VM-exit. */ +#define VMXMSRPM_ALLOW_RD RT_BIT(0) +/** Guest software reads of this MSR must cause a VM-exit. */ +#define VMXMSRPM_EXIT_RD RT_BIT(1) +/** Guest software writes to this MSR must not cause a VM-exit. */ +#define VMXMSRPM_ALLOW_WR RT_BIT(2) +/** Guest software writes to this MSR must cause a VM-exit. */ +#define VMXMSRPM_EXIT_WR RT_BIT(3) +/** Guest software reads or writes of this MSR must not cause a VM-exit. */ +#define VMXMSRPM_ALLOW_RD_WR (VMXMSRPM_ALLOW_RD | VMXMSRPM_ALLOW_WR) +/** Guest software reads or writes of this MSR must cause a VM-exit. */ +#define VMXMSRPM_EXIT_RD_WR (VMXMSRPM_EXIT_RD | VMXMSRPM_EXIT_WR) +/** Mask of valid MSR read permissions. */ +#define VMXMSRPM_RD_MASK (VMXMSRPM_ALLOW_RD | VMXMSRPM_EXIT_RD) +/** Mask of valid MSR write permissions. */ +#define VMXMSRPM_WR_MASK (VMXMSRPM_ALLOW_WR | VMXMSRPM_EXIT_WR) +/** Mask of valid MSR permissions. */ +#define VMXMSRPM_MASK (VMXMSRPM_RD_MASK | VMXMSRPM_WR_MASK) +/** */ +/** Gets whether the MSR permission is valid or not. */ +#define VMXMSRPM_IS_FLAG_VALID(a_Msrpm) ( (a_Msrpm) != 0 \ + && ((a_Msrpm) & ~VMXMSRPM_MASK) == 0 \ + && ((a_Msrpm) & VMXMSRPM_RD_MASK) != VMXMSRPM_RD_MASK \ + && ((a_Msrpm) & VMXMSRPM_WR_MASK) != VMXMSRPM_WR_MASK) +/** @} */ + +/** + * VMX MSR autoload/store slot. + * In accordance with the VT-x spec. + */ +typedef struct VMXAUTOMSR +{ + /** The MSR Id. */ + uint32_t u32Msr; + /** Reserved (MBZ). */ + uint32_t u32Reserved; + /** The MSR value. */ + uint64_t u64Value; +} VMXAUTOMSR; +AssertCompileSize(VMXAUTOMSR, 16); +/** Pointer to an MSR load/store element. */ +typedef VMXAUTOMSR *PVMXAUTOMSR; +/** Pointer to a const MSR load/store element. */ +typedef const VMXAUTOMSR *PCVMXAUTOMSR; + +/** VMX auto load-store MSR (VMXAUTOMSR) offset mask. */ +#define VMX_AUTOMSR_OFFSET_MASK 0xf + +/** + * VMX tagged-TLB flush types. + */ +typedef enum +{ + VMXTLBFLUSHTYPE_EPT, + VMXTLBFLUSHTYPE_VPID, + VMXTLBFLUSHTYPE_EPT_VPID, + VMXTLBFLUSHTYPE_NONE +} VMXTLBFLUSHTYPE; +/** Pointer to a VMXTLBFLUSHTYPE enum. */ +typedef VMXTLBFLUSHTYPE *PVMXTLBFLUSHTYPE; +/** Pointer to a const VMXTLBFLUSHTYPE enum. */ +typedef const VMXTLBFLUSHTYPE *PCVMXTLBFLUSHTYPE; + +/** + * VMX controls MSR. + * In accordance with the VT-x spec. + */ +typedef union +{ + struct + { + /** Bits set here -must- be set in the corresponding VM-execution controls. */ + uint32_t allowed0; + /** Bits cleared here -must- be cleared in the corresponding VM-execution + * controls. */ + uint32_t allowed1; + } n; + uint64_t u; +} VMXCTLSMSR; +AssertCompileSize(VMXCTLSMSR, 8); +/** Pointer to a VMXCTLSMSR union. */ +typedef VMXCTLSMSR *PVMXCTLSMSR; +/** Pointer to a const VMXCTLSMSR union. */ +typedef const VMXCTLSMSR *PCVMXCTLSMSR; + +/** + * VMX MSRs. + */ +typedef struct VMXMSRS +{ + /** Basic information. */ + uint64_t u64Basic; + /** Pin-based VM-execution controls. */ + VMXCTLSMSR PinCtls; + /** Processor-based VM-execution controls. */ + VMXCTLSMSR ProcCtls; + /** Secondary processor-based VM-execution controls. */ + VMXCTLSMSR ProcCtls2; + /** VM-exit controls. */ + VMXCTLSMSR ExitCtls; + /** VM-entry controls. */ + VMXCTLSMSR EntryCtls; + /** True pin-based VM-execution controls. */ + VMXCTLSMSR TruePinCtls; + /** True processor-based VM-execution controls. */ + VMXCTLSMSR TrueProcCtls; + /** True VM-entry controls. */ + VMXCTLSMSR TrueEntryCtls; + /** True VM-exit controls. */ + VMXCTLSMSR TrueExitCtls; + /** Miscellaneous data. */ + uint64_t u64Misc; + /** CR0 fixed-0 - bits set here must be set in VMX operation. */ + uint64_t u64Cr0Fixed0; + /** CR0 fixed-1 - bits clear here must be clear in VMX operation. */ + uint64_t u64Cr0Fixed1; + /** CR4 fixed-0 - bits set here must be set in VMX operation. */ + uint64_t u64Cr4Fixed0; + /** CR4 fixed-1 - bits clear here must be clear in VMX operation. */ + uint64_t u64Cr4Fixed1; + /** VMCS enumeration. */ + uint64_t u64VmcsEnum; + /** VM Functions. */ + uint64_t u64VmFunc; + /** EPT, VPID capabilities. */ + uint64_t u64EptVpidCaps; + /** Tertiary processor-based VM-execution controls. */ + uint64_t u64ProcCtls3; + /** Secondary VM-exit controls. */ + uint64_t u64ExitCtls2; + /** Reserved for future. */ + uint64_t a_u64Reserved[8]; +} VMXMSRS; +AssertCompileSizeAlignment(VMXMSRS, 8); +AssertCompileSize(VMXMSRS, 224); +/** Pointer to a VMXMSRS struct. */ +typedef VMXMSRS *PVMXMSRS; +/** Pointer to a const VMXMSRS struct. */ +typedef const VMXMSRS *PCVMXMSRS; + + +/** + * LBR MSRs. + */ +typedef struct LBRMSRS +{ + /** List of LastBranch-From-IP MSRs. */ + uint64_t au64BranchFromIpMsr[32]; + /** List of LastBranch-To-IP MSRs. */ + uint64_t au64BranchToIpMsr[32]; + /** The MSR containing the index to the most recent branch record. */ + uint64_t uBranchTosMsr; +} LBRMSRS; +AssertCompileSizeAlignment(LBRMSRS, 8); +/** Pointer to a VMXMSRS struct. */ +typedef LBRMSRS *PLBRMSRS; +/** Pointer to a const VMXMSRS struct. */ +typedef const LBRMSRS *PCLBRMSRS; + + +/** @name VMX Basic Exit Reasons. + * In accordance with the VT-x spec. + * Update g_aVMExitHandlers if new VM-exit reasons are added. + * @{ + */ +/** Invalid exit code */ +#define VMX_EXIT_INVALID (-1) +/** Exception or non-maskable interrupt (NMI). */ +#define VMX_EXIT_XCPT_OR_NMI 0 +/** External interrupt. */ +#define VMX_EXIT_EXT_INT 1 +/** Triple fault. */ +#define VMX_EXIT_TRIPLE_FAULT 2 +/** INIT signal. */ +#define VMX_EXIT_INIT_SIGNAL 3 +/** Start-up IPI (SIPI). */ +#define VMX_EXIT_SIPI 4 +/** I/O system-management interrupt (SMI). */ +#define VMX_EXIT_IO_SMI 5 +/** Other SMI. */ +#define VMX_EXIT_SMI 6 +/** Interrupt window exiting. */ +#define VMX_EXIT_INT_WINDOW 7 +/** NMI window exiting. */ +#define VMX_EXIT_NMI_WINDOW 8 +/** Task switch. */ +#define VMX_EXIT_TASK_SWITCH 9 +/** CPUID. */ +#define VMX_EXIT_CPUID 10 +/** GETSEC. */ +#define VMX_EXIT_GETSEC 11 +/** HLT. */ +#define VMX_EXIT_HLT 12 +/** INVD. */ +#define VMX_EXIT_INVD 13 +/** INVLPG. */ +#define VMX_EXIT_INVLPG 14 +/** RDPMC. */ +#define VMX_EXIT_RDPMC 15 +/** RDTSC. */ +#define VMX_EXIT_RDTSC 16 +/** RSM in SMM. */ +#define VMX_EXIT_RSM 17 +/** VMCALL. */ +#define VMX_EXIT_VMCALL 18 +/** VMCLEAR. */ +#define VMX_EXIT_VMCLEAR 19 +/** VMLAUNCH. */ +#define VMX_EXIT_VMLAUNCH 20 +/** VMPTRLD. */ +#define VMX_EXIT_VMPTRLD 21 +/** VMPTRST. */ +#define VMX_EXIT_VMPTRST 22 +/** VMREAD. */ +#define VMX_EXIT_VMREAD 23 +/** VMRESUME. */ +#define VMX_EXIT_VMRESUME 24 +/** VMWRITE. */ +#define VMX_EXIT_VMWRITE 25 +/** VMXOFF. */ +#define VMX_EXIT_VMXOFF 26 +/** VMXON. */ +#define VMX_EXIT_VMXON 27 +/** Control-register accesses. */ +#define VMX_EXIT_MOV_CRX 28 +/** Debug-register accesses. */ +#define VMX_EXIT_MOV_DRX 29 +/** I/O instruction. */ +#define VMX_EXIT_IO_INSTR 30 +/** RDMSR. */ +#define VMX_EXIT_RDMSR 31 +/** WRMSR. */ +#define VMX_EXIT_WRMSR 32 +/** VM-entry failure due to invalid guest state. */ +#define VMX_EXIT_ERR_INVALID_GUEST_STATE 33 +/** VM-entry failure due to MSR loading. */ +#define VMX_EXIT_ERR_MSR_LOAD 34 +/** MWAIT. */ +#define VMX_EXIT_MWAIT 36 +/** VM-exit due to monitor trap flag. */ +#define VMX_EXIT_MTF 37 +/** MONITOR. */ +#define VMX_EXIT_MONITOR 39 +/** PAUSE. */ +#define VMX_EXIT_PAUSE 40 +/** VM-entry failure due to machine-check. */ +#define VMX_EXIT_ERR_MACHINE_CHECK 41 +/** TPR below threshold. Guest software executed MOV to CR8. */ +#define VMX_EXIT_TPR_BELOW_THRESHOLD 43 +/** VM-exit due to guest accessing physical address in the APIC-access page. */ +#define VMX_EXIT_APIC_ACCESS 44 +/** VM-exit due to EOI virtualization. */ +#define VMX_EXIT_VIRTUALIZED_EOI 45 +/** Access to GDTR/IDTR using LGDT, LIDT, SGDT or SIDT. */ +#define VMX_EXIT_GDTR_IDTR_ACCESS 46 +/** Access to LDTR/TR due to LLDT, LTR, SLDT, or STR. */ +#define VMX_EXIT_LDTR_TR_ACCESS 47 +/** EPT violation. */ +#define VMX_EXIT_EPT_VIOLATION 48 +/** EPT misconfiguration. */ +#define VMX_EXIT_EPT_MISCONFIG 49 +/** INVEPT. */ +#define VMX_EXIT_INVEPT 50 +/** RDTSCP. */ +#define VMX_EXIT_RDTSCP 51 +/** VMX-preemption timer expired. */ +#define VMX_EXIT_PREEMPT_TIMER 52 +/** INVVPID. */ +#define VMX_EXIT_INVVPID 53 +/** WBINVD. */ +#define VMX_EXIT_WBINVD 54 +/** XSETBV. */ +#define VMX_EXIT_XSETBV 55 +/** Guest completed write to virtual-APIC. */ +#define VMX_EXIT_APIC_WRITE 56 +/** RDRAND. */ +#define VMX_EXIT_RDRAND 57 +/** INVPCID. */ +#define VMX_EXIT_INVPCID 58 +/** VMFUNC. */ +#define VMX_EXIT_VMFUNC 59 +/** ENCLS. */ +#define VMX_EXIT_ENCLS 60 +/** RDSEED. */ +#define VMX_EXIT_RDSEED 61 +/** Page-modification log full. */ +#define VMX_EXIT_PML_FULL 62 +/** XSAVES. */ +#define VMX_EXIT_XSAVES 63 +/** XRSTORS. */ +#define VMX_EXIT_XRSTORS 64 +/** SPP-related event (SPP miss or misconfiguration). */ +#define VMX_EXIT_SPP_EVENT 66 +/* UMWAIT. */ +#define VMX_EXIT_UMWAIT 67 +/** TPAUSE. */ +#define VMX_EXIT_TPAUSE 68 +/** LOADIWKEY. */ +#define VMX_EXIT_LOADIWKEY 69 +/** The maximum VM-exit value (inclusive). */ +#define VMX_EXIT_MAX (VMX_EXIT_LOADIWKEY) +/** @} */ + + +/** @name VM Instruction Errors. + * In accordance with the VT-x spec. + * See Intel spec. "30.4 VM Instruction Error Numbers" + * @{ + */ +typedef enum +{ + /** VMCALL executed in VMX root operation. */ + VMXINSTRERR_VMCALL_VMXROOTMODE = 1, + /** VMCLEAR with invalid physical address. */ + VMXINSTRERR_VMCLEAR_INVALID_PHYSADDR = 2, + /** VMCLEAR with VMXON pointer. */ + VMXINSTRERR_VMCLEAR_VMXON_PTR = 3, + /** VMLAUNCH with non-clear VMCS. */ + VMXINSTRERR_VMLAUNCH_NON_CLEAR_VMCS = 4, + /** VMRESUME with non-launched VMCS. */ + VMXINSTRERR_VMRESUME_NON_LAUNCHED_VMCS = 5, + /** VMRESUME after VMXOFF (VMXOFF and VMXON between VMLAUNCH and VMRESUME). */ + VMXINSTRERR_VMRESUME_AFTER_VMXOFF = 6, + /** VM-entry with invalid control field(s). */ + VMXINSTRERR_VMENTRY_INVALID_CTLS = 7, + /** VM-entry with invalid host-state field(s). */ + VMXINSTRERR_VMENTRY_INVALID_HOST_STATE = 8, + /** VMPTRLD with invalid physical address. */ + VMXINSTRERR_VMPTRLD_INVALID_PHYSADDR = 9, + /** VMPTRLD with VMXON pointer. */ + VMXINSTRERR_VMPTRLD_VMXON_PTR = 10, + /** VMPTRLD with incorrect VMCS revision identifier. */ + VMXINSTRERR_VMPTRLD_INCORRECT_VMCS_REV = 11, + /** VMREAD from unsupported VMCS component. */ + VMXINSTRERR_VMREAD_INVALID_COMPONENT = 12, + /** VMWRITE to unsupported VMCS component. */ + VMXINSTRERR_VMWRITE_INVALID_COMPONENT = 12, + /** VMWRITE to read-only VMCS component. */ + VMXINSTRERR_VMWRITE_RO_COMPONENT = 13, + /** VMXON executed in VMX root operation. */ + VMXINSTRERR_VMXON_IN_VMXROOTMODE = 15, + /** VM-entry with invalid executive-VMCS pointer. */ + VMXINSTRERR_VMENTRY_EXEC_VMCS_INVALID_PTR = 16, + /** VM-entry with non-launched executive VMCS. */ + VMXINSTRERR_VMENTRY_EXEC_VMCS_NON_LAUNCHED = 17, + /** VM-entry with executive-VMCS pointer not VMXON pointer. */ + VMXINSTRERR_VMENTRY_EXEC_VMCS_PTR = 18, + /** VMCALL with non-clear VMCS. */ + VMXINSTRERR_VMCALL_NON_CLEAR_VMCS = 19, + /** VMCALL with invalid VM-exit control fields. */ + VMXINSTRERR_VMCALL_INVALID_EXITCTLS = 20, + /** VMCALL with incorrect MSEG revision identifier. */ + VMXINSTRERR_VMCALL_INVALID_MSEG_ID = 22, + /** VMXOFF under dual-monitor treatment of SMIs and SMM. */ + VMXINSTRERR_VMXOFF_DUAL_MON = 23, + /** VMCALL with invalid SMM-monitor features. */ + VMXINSTRERR_VMCALL_INVALID_SMMCTLS = 24, + /** VM-entry with invalid VM-execution control fields in executive VMCS. */ + VMXINSTRERR_VMENTRY_EXEC_VMCS_INVALID_CTLS = 25, + /** VM-entry with events blocked by MOV SS. */ + VMXINSTRERR_VMENTRY_BLOCK_MOVSS = 26, + /** Invalid operand to INVEPT/INVVPID. */ + VMXINSTRERR_INVEPT_INVVPID_INVALID_OPERAND = 28 +} VMXINSTRERR; +/** @} */ + + +/** @name VMX abort reasons. + * In accordance with the VT-x spec. + * See Intel spec. "27.7 VMX Aborts". + * Update HMGetVmxAbortDesc() if new reasons are added. + * @{ + */ +typedef enum +{ + /** None - don't use this / uninitialized value. */ + VMXABORT_NONE = 0, + /** VMX abort caused during saving of guest MSRs. */ + VMXABORT_SAVE_GUEST_MSRS = 1, + /** VMX abort caused during host PDPTE checks. */ + VMXBOART_HOST_PDPTE = 2, + /** VMX abort caused due to current VMCS being corrupted. */ + VMXABORT_CURRENT_VMCS_CORRUPT = 3, + /** VMX abort caused during loading of host MSRs. */ + VMXABORT_LOAD_HOST_MSR = 4, + /** VMX abort caused due to a machine-check exception during VM-exit. */ + VMXABORT_MACHINE_CHECK_XCPT = 5, + /** VMX abort caused due to invalid return from long mode. */ + VMXABORT_HOST_NOT_IN_LONG_MODE = 6, + /* Type size hack. */ + VMXABORT_32BIT_HACK = 0x7fffffff +} VMXABORT; +AssertCompileSize(VMXABORT, 4); +/** @} */ + + +/** @name VMX MSR - Basic VMX information. + * @{ + */ +/** VMCS (and related regions) memory type - Uncacheable. */ +#define VMX_BASIC_MEM_TYPE_UC 0 +/** VMCS (and related regions) memory type - Write back. */ +#define VMX_BASIC_MEM_TYPE_WB 6 +/** Width of physical addresses used for VMCS and associated memory regions + * (1=32-bit, 0=processor's physical address width). */ +#define VMX_BASIC_PHYSADDR_WIDTH_32BIT RT_BIT_64(48) + +/** Bit fields for MSR_IA32_VMX_BASIC. */ +/** VMCS revision identifier used by the processor. */ +#define VMX_BF_BASIC_VMCS_ID_SHIFT 0 +#define VMX_BF_BASIC_VMCS_ID_MASK UINT64_C(0x000000007fffffff) +/** Bit 31 is reserved and RAZ. */ +#define VMX_BF_BASIC_RSVD_32_SHIFT 31 +#define VMX_BF_BASIC_RSVD_32_MASK UINT64_C(0x0000000080000000) +/** VMCS size in bytes. */ +#define VMX_BF_BASIC_VMCS_SIZE_SHIFT 32 +#define VMX_BF_BASIC_VMCS_SIZE_MASK UINT64_C(0x00001fff00000000) +/** Bits 45:47 are reserved. */ +#define VMX_BF_BASIC_RSVD_45_47_SHIFT 45 +#define VMX_BF_BASIC_RSVD_45_47_MASK UINT64_C(0x0000e00000000000) +/** Width of physical addresses used for the VMCS and associated memory regions + * (always 0 on CPUs that support Intel 64 architecture). */ +#define VMX_BF_BASIC_PHYSADDR_WIDTH_SHIFT 48 +#define VMX_BF_BASIC_PHYSADDR_WIDTH_MASK UINT64_C(0x0001000000000000) +/** Dual-monitor treatment of SMI and SMM supported. */ +#define VMX_BF_BASIC_DUAL_MON_SHIFT 49 +#define VMX_BF_BASIC_DUAL_MON_MASK UINT64_C(0x0002000000000000) +/** Memory type that must be used for the VMCS and associated memory regions. */ +#define VMX_BF_BASIC_VMCS_MEM_TYPE_SHIFT 50 +#define VMX_BF_BASIC_VMCS_MEM_TYPE_MASK UINT64_C(0x003c000000000000) +/** VM-exit instruction information for INS/OUTS. */ +#define VMX_BF_BASIC_VMCS_INS_OUTS_SHIFT 54 +#define VMX_BF_BASIC_VMCS_INS_OUTS_MASK UINT64_C(0x0040000000000000) +/** Whether 'true' VMX controls MSRs are supported for handling of default1 class + * bits in VMX control MSRs. */ +#define VMX_BF_BASIC_TRUE_CTLS_SHIFT 55 +#define VMX_BF_BASIC_TRUE_CTLS_MASK UINT64_C(0x0080000000000000) +/** Whether VM-entry can delivery error code for all hardware exception vectors. */ +#define VMX_BF_BASIC_XCPT_ERRCODE_SHIFT 56 +#define VMX_BF_BASIC_XCPT_ERRCODE_MASK UINT64_C(0x0100000000000000) +/** Bits 57:63 are reserved and RAZ. */ +#define VMX_BF_BASIC_RSVD_56_63_SHIFT 57 +#define VMX_BF_BASIC_RSVD_56_63_MASK UINT64_C(0xfe00000000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_BASIC_, UINT64_C(0), UINT64_MAX, + (VMCS_ID, RSVD_32, VMCS_SIZE, RSVD_45_47, PHYSADDR_WIDTH, DUAL_MON, VMCS_MEM_TYPE, + VMCS_INS_OUTS, TRUE_CTLS, XCPT_ERRCODE, RSVD_56_63)); +/** @} */ + + +/** @name VMX MSR - Miscellaneous data. + * @{ + */ +/** Whether VM-exit stores EFER.LMA into the "IA32e mode guest" field. */ +#define VMX_MISC_EXIT_SAVE_EFER_LMA RT_BIT(5) +/** Whether Intel PT is supported in VMX operation. */ +#define VMX_MISC_INTEL_PT RT_BIT(14) +/** Whether VMWRITE to any valid VMCS field incl. read-only fields, otherwise + * VMWRITE cannot modify read-only VM-exit information fields. */ +#define VMX_MISC_VMWRITE_ALL RT_BIT(29) +/** Whether VM-entry can inject software interrupts, INT1 (ICEBP) with 0-length + * instructions. */ +#define VMX_MISC_ENTRY_INJECT_SOFT_INT RT_BIT(30) +/** Maximum number of MSRs in the auto-load/store MSR areas, (n+1) * 512. */ +#define VMX_MISC_MAX_MSRS(a_MiscMsr) (512 * (RT_BF_GET((a_MiscMsr), VMX_BF_MISC_MAX_MSRS) + 1)) +/** Maximum CR3-target count supported by the CPU. */ +#define VMX_MISC_CR3_TARGET_COUNT(a_MiscMsr) (((a) >> 16) & 0xff) + +/** Bit fields for MSR_IA32_VMX_MISC. */ +/** Relationship between the preemption timer and tsc. */ +#define VMX_BF_MISC_PREEMPT_TIMER_TSC_SHIFT 0 +#define VMX_BF_MISC_PREEMPT_TIMER_TSC_MASK UINT64_C(0x000000000000001f) +/** Whether VM-exit stores EFER.LMA into the "IA32e mode guest" field. */ +#define VMX_BF_MISC_EXIT_SAVE_EFER_LMA_SHIFT 5 +#define VMX_BF_MISC_EXIT_SAVE_EFER_LMA_MASK UINT64_C(0x0000000000000020) +/** Activity states supported by the implementation. */ +#define VMX_BF_MISC_ACTIVITY_STATES_SHIFT 6 +#define VMX_BF_MISC_ACTIVITY_STATES_MASK UINT64_C(0x00000000000001c0) +/** Bits 9:13 is reserved and RAZ. */ +#define VMX_BF_MISC_RSVD_9_13_SHIFT 9 +#define VMX_BF_MISC_RSVD_9_13_MASK UINT64_C(0x0000000000003e00) +/** Whether Intel PT (Processor Trace) can be used in VMX operation. */ +#define VMX_BF_MISC_INTEL_PT_SHIFT 14 +#define VMX_BF_MISC_INTEL_PT_MASK UINT64_C(0x0000000000004000) +/** Whether RDMSR can be used to read IA32_SMBASE MSR in SMM. */ +#define VMX_BF_MISC_SMM_READ_SMBASE_MSR_SHIFT 15 +#define VMX_BF_MISC_SMM_READ_SMBASE_MSR_MASK UINT64_C(0x0000000000008000) +/** Number of CR3 target values supported by the processor. (0-256) */ +#define VMX_BF_MISC_CR3_TARGET_SHIFT 16 +#define VMX_BF_MISC_CR3_TARGET_MASK UINT64_C(0x0000000001ff0000) +/** Maximum number of MSRs in the VMCS. */ +#define VMX_BF_MISC_MAX_MSRS_SHIFT 25 +#define VMX_BF_MISC_MAX_MSRS_MASK UINT64_C(0x000000000e000000) +/** Whether IA32_SMM_MONITOR_CTL MSR can be modified to allow VMXOFF to block + * SMIs. */ +#define VMX_BF_MISC_VMXOFF_BLOCK_SMI_SHIFT 28 +#define VMX_BF_MISC_VMXOFF_BLOCK_SMI_MASK UINT64_C(0x0000000010000000) +/** Whether VMWRITE to any valid VMCS field incl. read-only fields, otherwise + * VMWRITE cannot modify read-only VM-exit information fields. */ +#define VMX_BF_MISC_VMWRITE_ALL_SHIFT 29 +#define VMX_BF_MISC_VMWRITE_ALL_MASK UINT64_C(0x0000000020000000) +/** Whether VM-entry can inject software interrupts, INT1 (ICEBP) with 0-length + * instructions. */ +#define VMX_BF_MISC_ENTRY_INJECT_SOFT_INT_SHIFT 30 +#define VMX_BF_MISC_ENTRY_INJECT_SOFT_INT_MASK UINT64_C(0x0000000040000000) +/** Bit 31 is reserved and RAZ. */ +#define VMX_BF_MISC_RSVD_31_SHIFT 31 +#define VMX_BF_MISC_RSVD_31_MASK UINT64_C(0x0000000080000000) +/** 32-bit MSEG revision ID used by the processor. */ +#define VMX_BF_MISC_MSEG_ID_SHIFT 32 +#define VMX_BF_MISC_MSEG_ID_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_MISC_, UINT64_C(0), UINT64_MAX, + (PREEMPT_TIMER_TSC, EXIT_SAVE_EFER_LMA, ACTIVITY_STATES, RSVD_9_13, INTEL_PT, SMM_READ_SMBASE_MSR, + CR3_TARGET, MAX_MSRS, VMXOFF_BLOCK_SMI, VMWRITE_ALL, ENTRY_INJECT_SOFT_INT, RSVD_31, MSEG_ID)); +/** @} */ + +/** @name VMX MSR - VMCS enumeration. + * Bit fields for MSR_IA32_VMX_VMCS_ENUM. + * @{ + */ +/** Bit 0 is reserved and RAZ. */ +#define VMX_BF_VMCS_ENUM_RSVD_0_SHIFT 0 +#define VMX_BF_VMCS_ENUM_RSVD_0_MASK UINT64_C(0x0000000000000001) +/** Highest index value used in VMCS field encoding. */ +#define VMX_BF_VMCS_ENUM_HIGHEST_IDX_SHIFT 1 +#define VMX_BF_VMCS_ENUM_HIGHEST_IDX_MASK UINT64_C(0x00000000000003fe) +/** Bit 10:63 is reserved and RAZ. */ +#define VMX_BF_VMCS_ENUM_RSVD_10_63_SHIFT 10 +#define VMX_BF_VMCS_ENUM_RSVD_10_63_MASK UINT64_C(0xfffffffffffffc00) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_VMCS_ENUM_, UINT64_C(0), UINT64_MAX, + (RSVD_0, HIGHEST_IDX, RSVD_10_63)); +/** @} */ + + +/** @name VMX MSR - VM Functions. + * Bit fields for MSR_IA32_VMX_VMFUNC. + * @{ + */ +/** EPTP-switching function changes the value of the EPTP to one chosen from the EPTP list. */ +#define VMX_BF_VMFUNC_EPTP_SWITCHING_SHIFT 0 +#define VMX_BF_VMFUNC_EPTP_SWITCHING_MASK UINT64_C(0x0000000000000001) +/** Bits 1:63 are reserved and RAZ. */ +#define VMX_BF_VMFUNC_RSVD_1_63_SHIFT 1 +#define VMX_BF_VMFUNC_RSVD_1_63_MASK UINT64_C(0xfffffffffffffffe) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_VMFUNC_, UINT64_C(0), UINT64_MAX, + (EPTP_SWITCHING, RSVD_1_63)); +/** @} */ + + +/** @name VMX MSR - EPT/VPID capabilities. + * @{ + */ +/** Supports execute-only translations by EPT. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_RWX_X_ONLY RT_BIT_64(0) +/** Supports page-walk length of 4. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_4 RT_BIT_64(6) +/** Supports page-walk length of 5. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_PAGE_WALK_LENGTH_5 RT_BIT_64(7) +/** Supports EPT paging-structure memory type to be uncacheable. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_MEMTYPE_UC RT_BIT_64(8) +/** Supports EPT paging structure memory type to be write-back. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_MEMTYPE_WB RT_BIT_64(14) +/** Supports EPT PDE to map a 2 MB page. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_PDE_2M RT_BIT_64(16) +/** Supports EPT PDPTE to map a 1 GB page. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_PDPTE_1G RT_BIT_64(17) +/** Supports INVEPT instruction. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVEPT RT_BIT_64(20) +/** Supports accessed and dirty flags for EPT. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_ACCESS_DIRTY RT_BIT_64(21) +/** Supports advanced VM-exit info. for EPT violations. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_ADVEXITINFO_EPT_VIOLATION RT_BIT_64(22) +/** Supports supervisor shadow-stack control. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_SUPER_SHW_STACK RT_BIT_64(23) +/** Supports single-context INVEPT type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_SINGLE_CONTEXT RT_BIT_64(25) +/** Supports all-context INVEPT type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVEPT_ALL_CONTEXTS RT_BIT_64(26) +/** Supports INVVPID instruction. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID RT_BIT_64(32) +/** Supports individual-address INVVPID type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_INDIV_ADDR RT_BIT_64(40) +/** Supports single-context INVVPID type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT RT_BIT_64(41) +/** Supports all-context INVVPID type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_ALL_CONTEXTS RT_BIT_64(42) +/** Supports singe-context-retaining-globals INVVPID type. */ +#define MSR_IA32_VMX_EPT_VPID_CAP_INVVPID_SINGLE_CONTEXT_RETAIN_GLOBALS RT_BIT_64(43) + +/** Bit fields for MSR_IA32_VMX_EPT_VPID_CAP. */ +#define VMX_BF_EPT_VPID_CAP_EXEC_ONLY_SHIFT 0 +#define VMX_BF_EPT_VPID_CAP_EXEC_ONLY_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_EPT_VPID_CAP_RSVD_1_5_SHIFT 1 +#define VMX_BF_EPT_VPID_CAP_RSVD_1_5_MASK UINT64_C(0x000000000000003e) +#define VMX_BF_EPT_VPID_CAP_PAGE_WALK_LENGTH_4_SHIFT 6 +#define VMX_BF_EPT_VPID_CAP_PAGE_WALK_LENGTH_4_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EPT_VPID_CAP_RSVD_7_SHIFT 7 +#define VMX_BF_EPT_VPID_CAP_RSVD_7_MASK UINT64_C(0x0000000000000080) +#define VMX_BF_EPT_VPID_CAP_MEMTYPE_UC_SHIFT 8 +#define VMX_BF_EPT_VPID_CAP_MEMTYPE_UC_MASK UINT64_C(0x0000000000000100) +#define VMX_BF_EPT_VPID_CAP_RSVD_9_13_SHIFT 9 +#define VMX_BF_EPT_VPID_CAP_RSVD_9_13_MASK UINT64_C(0x0000000000003e00) +#define VMX_BF_EPT_VPID_CAP_MEMTYPE_WB_SHIFT 14 +#define VMX_BF_EPT_VPID_CAP_MEMTYPE_WB_MASK UINT64_C(0x0000000000004000) +#define VMX_BF_EPT_VPID_CAP_RSVD_15_SHIFT 15 +#define VMX_BF_EPT_VPID_CAP_RSVD_15_MASK UINT64_C(0x0000000000008000) +#define VMX_BF_EPT_VPID_CAP_PDE_2M_SHIFT 16 +#define VMX_BF_EPT_VPID_CAP_PDE_2M_MASK UINT64_C(0x0000000000010000) +#define VMX_BF_EPT_VPID_CAP_PDPTE_1G_SHIFT 17 +#define VMX_BF_EPT_VPID_CAP_PDPTE_1G_MASK UINT64_C(0x0000000000020000) +#define VMX_BF_EPT_VPID_CAP_RSVD_18_19_SHIFT 18 +#define VMX_BF_EPT_VPID_CAP_RSVD_18_19_MASK UINT64_C(0x00000000000c0000) +#define VMX_BF_EPT_VPID_CAP_INVEPT_SHIFT 20 +#define VMX_BF_EPT_VPID_CAP_INVEPT_MASK UINT64_C(0x0000000000100000) +#define VMX_BF_EPT_VPID_CAP_ACCESS_DIRTY_SHIFT 21 +#define VMX_BF_EPT_VPID_CAP_ACCESS_DIRTY_MASK UINT64_C(0x0000000000200000) +#define VMX_BF_EPT_VPID_CAP_ADVEXITINFO_EPT_VIOLATION_SHIFT 22 +#define VMX_BF_EPT_VPID_CAP_ADVEXITINFO_EPT_VIOLATION_MASK UINT64_C(0x0000000000400000) +#define VMX_BF_EPT_VPID_CAP_SUPER_SHW_STACK_SHIFT 23 +#define VMX_BF_EPT_VPID_CAP_SUPER_SHW_STACK_MASK UINT64_C(0x0000000000800000) +#define VMX_BF_EPT_VPID_CAP_RSVD_24_SHIFT 24 +#define VMX_BF_EPT_VPID_CAP_RSVD_24_MASK UINT64_C(0x0000000001000000) +#define VMX_BF_EPT_VPID_CAP_INVEPT_SINGLE_CTX_SHIFT 25 +#define VMX_BF_EPT_VPID_CAP_INVEPT_SINGLE_CTX_MASK UINT64_C(0x0000000002000000) +#define VMX_BF_EPT_VPID_CAP_INVEPT_ALL_CTX_SHIFT 26 +#define VMX_BF_EPT_VPID_CAP_INVEPT_ALL_CTX_MASK UINT64_C(0x0000000004000000) +#define VMX_BF_EPT_VPID_CAP_RSVD_27_31_SHIFT 27 +#define VMX_BF_EPT_VPID_CAP_RSVD_27_31_MASK UINT64_C(0x00000000f8000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_SHIFT 32 +#define VMX_BF_EPT_VPID_CAP_INVVPID_MASK UINT64_C(0x0000000100000000) +#define VMX_BF_EPT_VPID_CAP_RSVD_33_39_SHIFT 33 +#define VMX_BF_EPT_VPID_CAP_RSVD_33_39_MASK UINT64_C(0x000000fe00000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_INDIV_ADDR_SHIFT 40 +#define VMX_BF_EPT_VPID_CAP_INVVPID_INDIV_ADDR_MASK UINT64_C(0x0000010000000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_SHIFT 41 +#define VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_MASK UINT64_C(0x0000020000000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_ALL_CTX_SHIFT 42 +#define VMX_BF_EPT_VPID_CAP_INVVPID_ALL_CTX_MASK UINT64_C(0x0000040000000000) +#define VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_RETAIN_GLOBALS_SHIFT 43 +#define VMX_BF_EPT_VPID_CAP_INVVPID_SINGLE_CTX_RETAIN_GLOBALS_MASK UINT64_C(0x0000080000000000) +#define VMX_BF_EPT_VPID_CAP_RSVD_44_63_SHIFT 44 +#define VMX_BF_EPT_VPID_CAP_RSVD_44_63_MASK UINT64_C(0xfffff00000000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EPT_VPID_CAP_, UINT64_C(0), UINT64_MAX, + (EXEC_ONLY, RSVD_1_5, PAGE_WALK_LENGTH_4, RSVD_7, MEMTYPE_UC, RSVD_9_13, MEMTYPE_WB, RSVD_15, PDE_2M, + PDPTE_1G, RSVD_18_19, INVEPT, ACCESS_DIRTY, ADVEXITINFO_EPT_VIOLATION, SUPER_SHW_STACK, RSVD_24, + INVEPT_SINGLE_CTX, INVEPT_ALL_CTX, RSVD_27_31, INVVPID, RSVD_33_39, INVVPID_INDIV_ADDR, + INVVPID_SINGLE_CTX, INVVPID_ALL_CTX, INVVPID_SINGLE_CTX_RETAIN_GLOBALS, RSVD_44_63)); +/** @} */ + + +/** @name Extended Page Table Pointer (EPTP) + * In accordance with the VT-x spec. + * See Intel spec. 23.6.11 "Extended-Page-Table Pointer (EPTP)". + * @{ + */ +/** EPTP memory type: Uncachable. */ +#define VMX_EPTP_MEMTYPE_UC 0 +/** EPTP memory type: Write Back. */ +#define VMX_EPTP_MEMTYPE_WB 6 +/** Page-walk length for PML4 (4-level paging). */ +#define VMX_EPTP_PAGE_WALK_LENGTH_4 3 + +/** Bit fields for EPTP. */ +#define VMX_BF_EPTP_MEMTYPE_SHIFT 0 +#define VMX_BF_EPTP_MEMTYPE_MASK UINT64_C(0x0000000000000007) +#define VMX_BF_EPTP_PAGE_WALK_LENGTH_SHIFT 3 +#define VMX_BF_EPTP_PAGE_WALK_LENGTH_MASK UINT64_C(0x0000000000000038) +#define VMX_BF_EPTP_ACCESS_DIRTY_SHIFT 6 +#define VMX_BF_EPTP_ACCESS_DIRTY_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EPTP_SUPER_SHW_STACK_SHIFT 7 +#define VMX_BF_EPTP_SUPER_SHW_STACK_MASK UINT64_C(0x0000000000000080) +#define VMX_BF_EPTP_RSVD_8_11_SHIFT 8 +#define VMX_BF_EPTP_RSVD_8_11_MASK UINT64_C(0x0000000000000f00) +#define VMX_BF_EPTP_PML4_TABLE_ADDR_SHIFT 12 +#define VMX_BF_EPTP_PML4_TABLE_ADDR_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EPTP_, UINT64_C(0), UINT64_MAX, + (MEMTYPE, PAGE_WALK_LENGTH, ACCESS_DIRTY, SUPER_SHW_STACK, RSVD_8_11, PML4_TABLE_ADDR)); + +/* Mask of valid EPTP bits sans physically non-addressable bits. */ +#define VMX_EPTP_VALID_MASK ( VMX_BF_EPTP_MEMTYPE_MASK \ + | VMX_BF_EPTP_PAGE_WALK_LENGTH_MASK \ + | VMX_BF_EPTP_ACCESS_DIRTY_MASK \ + | VMX_BF_EPTP_SUPER_SHW_STACK_MASK \ + | VMX_BF_EPTP_PML4_TABLE_ADDR_MASK) +/** @} */ + + +/** @name VMCS fields and encoding. + * + * When adding a new field: + * - Always add it to g_aVmcsFields. + * - Consider if it needs to be added to VMXVVMCS. + * @{ + */ +/** 16-bit control fields. */ +#define VMX_VMCS16_VPID 0x0000 +#define VMX_VMCS16_POSTED_INT_NOTIFY_VECTOR 0x0002 +#define VMX_VMCS16_EPTP_INDEX 0x0004 +#define VMX_VMCS16_HLAT_PREFIX_SIZE 0x0006 + +/** 16-bit guest-state fields. */ +#define VMX_VMCS16_GUEST_ES_SEL 0x0800 +#define VMX_VMCS16_GUEST_CS_SEL 0x0802 +#define VMX_VMCS16_GUEST_SS_SEL 0x0804 +#define VMX_VMCS16_GUEST_DS_SEL 0x0806 +#define VMX_VMCS16_GUEST_FS_SEL 0x0808 +#define VMX_VMCS16_GUEST_GS_SEL 0x080a +#define VMX_VMCS16_GUEST_LDTR_SEL 0x080c +#define VMX_VMCS16_GUEST_TR_SEL 0x080e +#define VMX_VMCS16_GUEST_INTR_STATUS 0x0810 +#define VMX_VMCS16_GUEST_PML_INDEX 0x0812 + +/** 16-bits host-state fields. */ +#define VMX_VMCS16_HOST_ES_SEL 0x0c00 +#define VMX_VMCS16_HOST_CS_SEL 0x0c02 +#define VMX_VMCS16_HOST_SS_SEL 0x0c04 +#define VMX_VMCS16_HOST_DS_SEL 0x0c06 +#define VMX_VMCS16_HOST_FS_SEL 0x0c08 +#define VMX_VMCS16_HOST_GS_SEL 0x0c0a +#define VMX_VMCS16_HOST_TR_SEL 0x0c0c + +/** 64-bit control fields. */ +#define VMX_VMCS64_CTRL_IO_BITMAP_A_FULL 0x2000 +#define VMX_VMCS64_CTRL_IO_BITMAP_A_HIGH 0x2001 +#define VMX_VMCS64_CTRL_IO_BITMAP_B_FULL 0x2002 +#define VMX_VMCS64_CTRL_IO_BITMAP_B_HIGH 0x2003 +#define VMX_VMCS64_CTRL_MSR_BITMAP_FULL 0x2004 +#define VMX_VMCS64_CTRL_MSR_BITMAP_HIGH 0x2005 +#define VMX_VMCS64_CTRL_EXIT_MSR_STORE_FULL 0x2006 +#define VMX_VMCS64_CTRL_EXIT_MSR_STORE_HIGH 0x2007 +#define VMX_VMCS64_CTRL_EXIT_MSR_LOAD_FULL 0x2008 +#define VMX_VMCS64_CTRL_EXIT_MSR_LOAD_HIGH 0x2009 +#define VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_FULL 0x200a +#define VMX_VMCS64_CTRL_ENTRY_MSR_LOAD_HIGH 0x200b +#define VMX_VMCS64_CTRL_EXEC_VMCS_PTR_FULL 0x200c +#define VMX_VMCS64_CTRL_EXEC_VMCS_PTR_HIGH 0x200d +#define VMX_VMCS64_CTRL_EXEC_PML_ADDR_FULL 0x200e +#define VMX_VMCS64_CTRL_EXEC_PML_ADDR_HIGH 0x200f +#define VMX_VMCS64_CTRL_TSC_OFFSET_FULL 0x2010 +#define VMX_VMCS64_CTRL_TSC_OFFSET_HIGH 0x2011 +#define VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_FULL 0x2012 +#define VMX_VMCS64_CTRL_VIRT_APIC_PAGEADDR_HIGH 0x2013 +#define VMX_VMCS64_CTRL_APIC_ACCESSADDR_FULL 0x2014 +#define VMX_VMCS64_CTRL_APIC_ACCESSADDR_HIGH 0x2015 +#define VMX_VMCS64_CTRL_POSTED_INTR_DESC_FULL 0x2016 +#define VMX_VMCS64_CTRL_POSTED_INTR_DESC_HIGH 0x2017 +#define VMX_VMCS64_CTRL_VMFUNC_CTRLS_FULL 0x2018 +#define VMX_VMCS64_CTRL_VMFUNC_CTRLS_HIGH 0x2019 +#define VMX_VMCS64_CTRL_EPTP_FULL 0x201a +#define VMX_VMCS64_CTRL_EPTP_HIGH 0x201b +#define VMX_VMCS64_CTRL_EOI_BITMAP_0_FULL 0x201c +#define VMX_VMCS64_CTRL_EOI_BITMAP_0_HIGH 0x201d +#define VMX_VMCS64_CTRL_EOI_BITMAP_1_FULL 0x201e +#define VMX_VMCS64_CTRL_EOI_BITMAP_1_HIGH 0x201f +#define VMX_VMCS64_CTRL_EOI_BITMAP_2_FULL 0x2020 +#define VMX_VMCS64_CTRL_EOI_BITMAP_2_HIGH 0x2021 +#define VMX_VMCS64_CTRL_EOI_BITMAP_3_FULL 0x2022 +#define VMX_VMCS64_CTRL_EOI_BITMAP_3_HIGH 0x2023 +#define VMX_VMCS64_CTRL_EPTP_LIST_FULL 0x2024 +#define VMX_VMCS64_CTRL_EPTP_LIST_HIGH 0x2025 +#define VMX_VMCS64_CTRL_VMREAD_BITMAP_FULL 0x2026 +#define VMX_VMCS64_CTRL_VMREAD_BITMAP_HIGH 0x2027 +#define VMX_VMCS64_CTRL_VMWRITE_BITMAP_FULL 0x2028 +#define VMX_VMCS64_CTRL_VMWRITE_BITMAP_HIGH 0x2029 +#define VMX_VMCS64_CTRL_VE_XCPT_INFO_ADDR_FULL 0x202a +#define VMX_VMCS64_CTRL_VE_XCPT_INFO_ADDR_HIGH 0x202b +#define VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_FULL 0x202c +#define VMX_VMCS64_CTRL_XSS_EXITING_BITMAP_HIGH 0x202d +#define VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_FULL 0x202e +#define VMX_VMCS64_CTRL_ENCLS_EXITING_BITMAP_HIGH 0x202f +#define VMX_VMCS64_CTRL_SPPTP_FULL 0x2030 +#define VMX_VMCS64_CTRL_SPPTP_HIGH 0x2031 +#define VMX_VMCS64_CTRL_TSC_MULTIPLIER_FULL 0x2032 +#define VMX_VMCS64_CTRL_TSC_MULTIPLIER_HIGH 0x2033 +#define VMX_VMCS64_CTRL_PROC_EXEC3_FULL 0x2034 +#define VMX_VMCS64_CTRL_PROC_EXEC3_HIGH 0x2035 +#define VMX_VMCS64_CTRL_ENCLV_EXITING_BITMAP_FULL 0x2036 +#define VMX_VMCS64_CTRL_ENCLV_EXITING_BITMAP_HIGH 0x2037 +#define VMX_VMCS64_CTRL_PCONFIG_EXITING_BITMAP_FULL 0x203e +#define VMX_VMCS64_CTRL_PCONFIG_EXITING_BITMAP_HIGH 0x203f +#define VMX_VMCS64_CTRL_HLAT_PTR_FULL 0x2040 +#define VMX_VMCS64_CTRL_HLAT_PTR_HIGH 0x2041 +#define VMX_VMCS64_CTRL_EXIT2_FULL 0x2044 +#define VMX_VMCS64_CTRL_EXIT2_HIGH 0x2045 + +/** 64-bit read-only data fields. */ +#define VMX_VMCS64_RO_GUEST_PHYS_ADDR_FULL 0x2400 +#define VMX_VMCS64_RO_GUEST_PHYS_ADDR_HIGH 0x2401 + +/** 64-bit guest-state fields. */ +#define VMX_VMCS64_GUEST_VMCS_LINK_PTR_FULL 0x2800 +#define VMX_VMCS64_GUEST_VMCS_LINK_PTR_HIGH 0x2801 +#define VMX_VMCS64_GUEST_DEBUGCTL_FULL 0x2802 +#define VMX_VMCS64_GUEST_DEBUGCTL_HIGH 0x2803 +#define VMX_VMCS64_GUEST_PAT_FULL 0x2804 +#define VMX_VMCS64_GUEST_PAT_HIGH 0x2805 +#define VMX_VMCS64_GUEST_EFER_FULL 0x2806 +#define VMX_VMCS64_GUEST_EFER_HIGH 0x2807 +#define VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_FULL 0x2808 +#define VMX_VMCS64_GUEST_PERF_GLOBAL_CTRL_HIGH 0x2809 +#define VMX_VMCS64_GUEST_PDPTE0_FULL 0x280a +#define VMX_VMCS64_GUEST_PDPTE0_HIGH 0x280b +#define VMX_VMCS64_GUEST_PDPTE1_FULL 0x280c +#define VMX_VMCS64_GUEST_PDPTE1_HIGH 0x280d +#define VMX_VMCS64_GUEST_PDPTE2_FULL 0x280e +#define VMX_VMCS64_GUEST_PDPTE2_HIGH 0x280f +#define VMX_VMCS64_GUEST_PDPTE3_FULL 0x2810 +#define VMX_VMCS64_GUEST_PDPTE3_HIGH 0x2811 +#define VMX_VMCS64_GUEST_BNDCFGS_FULL 0x2812 +#define VMX_VMCS64_GUEST_BNDCFGS_HIGH 0x2813 +#define VMX_VMCS64_GUEST_RTIT_CTL_FULL 0x2814 +#define VMX_VMCS64_GUEST_RTIT_CTL_HIGH 0x2815 +#define VMX_VMCS64_GUEST_PKRS_FULL 0x2818 +#define VMX_VMCS64_GUEST_PKRS_HIGH 0x2819 + +/** 64-bit host-state fields. */ +#define VMX_VMCS64_HOST_PAT_FULL 0x2c00 +#define VMX_VMCS64_HOST_PAT_HIGH 0x2c01 +#define VMX_VMCS64_HOST_EFER_FULL 0x2c02 +#define VMX_VMCS64_HOST_EFER_HIGH 0x2c03 +#define VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_FULL 0x2c04 +#define VMX_VMCS64_HOST_PERF_GLOBAL_CTRL_HIGH 0x2c05 +#define VMX_VMCS64_HOST_PKRS_FULL 0x2c06 +#define VMX_VMCS64_HOST_PKRS_HIGH 0x2c07 + +/** 32-bit control fields. */ +#define VMX_VMCS32_CTRL_PIN_EXEC 0x4000 +#define VMX_VMCS32_CTRL_PROC_EXEC 0x4002 +#define VMX_VMCS32_CTRL_EXCEPTION_BITMAP 0x4004 +#define VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MASK 0x4006 +#define VMX_VMCS32_CTRL_PAGEFAULT_ERROR_MATCH 0x4008 +#define VMX_VMCS32_CTRL_CR3_TARGET_COUNT 0x400a +#define VMX_VMCS32_CTRL_EXIT 0x400c +#define VMX_VMCS32_CTRL_EXIT_MSR_STORE_COUNT 0x400e +#define VMX_VMCS32_CTRL_EXIT_MSR_LOAD_COUNT 0x4010 +#define VMX_VMCS32_CTRL_ENTRY 0x4012 +#define VMX_VMCS32_CTRL_ENTRY_MSR_LOAD_COUNT 0x4014 +#define VMX_VMCS32_CTRL_ENTRY_INTERRUPTION_INFO 0x4016 +#define VMX_VMCS32_CTRL_ENTRY_EXCEPTION_ERRCODE 0x4018 +#define VMX_VMCS32_CTRL_ENTRY_INSTR_LENGTH 0x401a +#define VMX_VMCS32_CTRL_TPR_THRESHOLD 0x401c +#define VMX_VMCS32_CTRL_PROC_EXEC2 0x401e +#define VMX_VMCS32_CTRL_PLE_GAP 0x4020 +#define VMX_VMCS32_CTRL_PLE_WINDOW 0x4022 + +/** 32-bits read-only fields. */ +#define VMX_VMCS32_RO_VM_INSTR_ERROR 0x4400 +#define VMX_VMCS32_RO_EXIT_REASON 0x4402 +#define VMX_VMCS32_RO_EXIT_INTERRUPTION_INFO 0x4404 +#define VMX_VMCS32_RO_EXIT_INTERRUPTION_ERROR_CODE 0x4406 +#define VMX_VMCS32_RO_IDT_VECTORING_INFO 0x4408 +#define VMX_VMCS32_RO_IDT_VECTORING_ERROR_CODE 0x440a +#define VMX_VMCS32_RO_EXIT_INSTR_LENGTH 0x440c +#define VMX_VMCS32_RO_EXIT_INSTR_INFO 0x440e + +/** 32-bit guest-state fields. */ +#define VMX_VMCS32_GUEST_ES_LIMIT 0x4800 +#define VMX_VMCS32_GUEST_CS_LIMIT 0x4802 +#define VMX_VMCS32_GUEST_SS_LIMIT 0x4804 +#define VMX_VMCS32_GUEST_DS_LIMIT 0x4806 +#define VMX_VMCS32_GUEST_FS_LIMIT 0x4808 +#define VMX_VMCS32_GUEST_GS_LIMIT 0x480a +#define VMX_VMCS32_GUEST_LDTR_LIMIT 0x480c +#define VMX_VMCS32_GUEST_TR_LIMIT 0x480e +#define VMX_VMCS32_GUEST_GDTR_LIMIT 0x4810 +#define VMX_VMCS32_GUEST_IDTR_LIMIT 0x4812 +#define VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS 0x4814 +#define VMX_VMCS32_GUEST_CS_ACCESS_RIGHTS 0x4816 +#define VMX_VMCS32_GUEST_SS_ACCESS_RIGHTS 0x4818 +#define VMX_VMCS32_GUEST_DS_ACCESS_RIGHTS 0x481a +#define VMX_VMCS32_GUEST_FS_ACCESS_RIGHTS 0x481c +#define VMX_VMCS32_GUEST_GS_ACCESS_RIGHTS 0x481e +#define VMX_VMCS32_GUEST_LDTR_ACCESS_RIGHTS 0x4820 +#define VMX_VMCS32_GUEST_TR_ACCESS_RIGHTS 0x4822 +#define VMX_VMCS32_GUEST_INT_STATE 0x4824 +#define VMX_VMCS32_GUEST_ACTIVITY_STATE 0x4826 +#define VMX_VMCS32_GUEST_SMBASE 0x4828 +#define VMX_VMCS32_GUEST_SYSENTER_CS 0x482a +#define VMX_VMCS32_PREEMPT_TIMER_VALUE 0x482e + +/** 32-bit host-state fields. */ +#define VMX_VMCS32_HOST_SYSENTER_CS 0x4C00 + +/** Natural-width control fields. */ +#define VMX_VMCS_CTRL_CR0_MASK 0x6000 +#define VMX_VMCS_CTRL_CR4_MASK 0x6002 +#define VMX_VMCS_CTRL_CR0_READ_SHADOW 0x6004 +#define VMX_VMCS_CTRL_CR4_READ_SHADOW 0x6006 +#define VMX_VMCS_CTRL_CR3_TARGET_VAL0 0x6008 +#define VMX_VMCS_CTRL_CR3_TARGET_VAL1 0x600a +#define VMX_VMCS_CTRL_CR3_TARGET_VAL2 0x600c +#define VMX_VMCS_CTRL_CR3_TARGET_VAL3 0x600e + +/** Natural-width read-only data fields. */ +#define VMX_VMCS_RO_EXIT_QUALIFICATION 0x6400 +#define VMX_VMCS_RO_IO_RCX 0x6402 +#define VMX_VMCS_RO_IO_RSI 0x6404 +#define VMX_VMCS_RO_IO_RDI 0x6406 +#define VMX_VMCS_RO_IO_RIP 0x6408 +#define VMX_VMCS_RO_GUEST_LINEAR_ADDR 0x640a + +/** Natural-width guest-state fields. */ +#define VMX_VMCS_GUEST_CR0 0x6800 +#define VMX_VMCS_GUEST_CR3 0x6802 +#define VMX_VMCS_GUEST_CR4 0x6804 +#define VMX_VMCS_GUEST_ES_BASE 0x6806 +#define VMX_VMCS_GUEST_CS_BASE 0x6808 +#define VMX_VMCS_GUEST_SS_BASE 0x680a +#define VMX_VMCS_GUEST_DS_BASE 0x680c +#define VMX_VMCS_GUEST_FS_BASE 0x680e +#define VMX_VMCS_GUEST_GS_BASE 0x6810 +#define VMX_VMCS_GUEST_LDTR_BASE 0x6812 +#define VMX_VMCS_GUEST_TR_BASE 0x6814 +#define VMX_VMCS_GUEST_GDTR_BASE 0x6816 +#define VMX_VMCS_GUEST_IDTR_BASE 0x6818 +#define VMX_VMCS_GUEST_DR7 0x681a +#define VMX_VMCS_GUEST_RSP 0x681c +#define VMX_VMCS_GUEST_RIP 0x681e +#define VMX_VMCS_GUEST_RFLAGS 0x6820 +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPTS 0x6822 +#define VMX_VMCS_GUEST_SYSENTER_ESP 0x6824 +#define VMX_VMCS_GUEST_SYSENTER_EIP 0x6826 +#define VMX_VMCS_GUEST_S_CET 0x6828 +#define VMX_VMCS_GUEST_SSP 0x682a +#define VMX_VMCS_GUEST_INTR_SSP_TABLE_ADDR 0x682c + +/** Natural-width host-state fields. */ +#define VMX_VMCS_HOST_CR0 0x6c00 +#define VMX_VMCS_HOST_CR3 0x6c02 +#define VMX_VMCS_HOST_CR4 0x6c04 +#define VMX_VMCS_HOST_FS_BASE 0x6c06 +#define VMX_VMCS_HOST_GS_BASE 0x6c08 +#define VMX_VMCS_HOST_TR_BASE 0x6c0a +#define VMX_VMCS_HOST_GDTR_BASE 0x6c0c +#define VMX_VMCS_HOST_IDTR_BASE 0x6c0e +#define VMX_VMCS_HOST_SYSENTER_ESP 0x6c10 +#define VMX_VMCS_HOST_SYSENTER_EIP 0x6c12 +#define VMX_VMCS_HOST_RSP 0x6c14 +#define VMX_VMCS_HOST_RIP 0x6c16 +#define VMX_VMCS_HOST_S_CET 0x6c18 +#define VMX_VMCS_HOST_SSP 0x6c1a +#define VMX_VMCS_HOST_INTR_SSP_TABLE_ADDR 0x6c1c + +#define VMX_VMCS16_GUEST_SEG_SEL(a_iSegReg) (VMX_VMCS16_GUEST_ES_SEL + (a_iSegReg) * 2) +#define VMX_VMCS_GUEST_SEG_BASE(a_iSegReg) (VMX_VMCS_GUEST_ES_BASE + (a_iSegReg) * 2) +#define VMX_VMCS32_GUEST_SEG_LIMIT(a_iSegReg) (VMX_VMCS32_GUEST_ES_LIMIT + (a_iSegReg) * 2) +#define VMX_VMCS32_GUEST_SEG_ACCESS_RIGHTS(a_iSegReg) (VMX_VMCS32_GUEST_ES_ACCESS_RIGHTS + (a_iSegReg) * 2) + +/** + * VMCS field. + * In accordance with the VT-x spec. + */ +typedef union +{ + struct + { + /** The access type; 0=full, 1=high of 64-bit fields. */ + uint32_t fAccessType : 1; + /** The index. */ + uint32_t u8Index : 8; + /** The type; 0=control, 1=VM-exit info, 2=guest-state, 3=host-state. */ + uint32_t u2Type : 2; + /** Reserved (MBZ). */ + uint32_t u1Reserved0 : 1; + /** The width; 0=16-bit, 1=64-bit, 2=32-bit, 3=natural-width. */ + uint32_t u2Width : 2; + /** Reserved (MBZ). */ + uint32_t u18Reserved0 : 18; + } n; + + /* The unsigned integer view. */ + uint32_t u; +} VMXVMCSFIELD; +AssertCompileSize(VMXVMCSFIELD, 4); +/** Pointer to a VMCS field. */ +typedef VMXVMCSFIELD *PVMXVMCSFIELD; +/** Pointer to a const VMCS field. */ +typedef const VMXVMCSFIELD *PCVMXVMCSFIELD; + +/** VMCS field: Mask of reserved bits (bits 63:15 MBZ), bit 12 is not included! */ +#define VMX_VMCSFIELD_RSVD_MASK UINT64_C(0xffffffffffff8000) + +/** Bits fields for a VMCS field. */ +#define VMX_BF_VMCSFIELD_ACCESS_TYPE_SHIFT 0 +#define VMX_BF_VMCSFIELD_ACCESS_TYPE_MASK UINT32_C(0x00000001) +#define VMX_BF_VMCSFIELD_INDEX_SHIFT 1 +#define VMX_BF_VMCSFIELD_INDEX_MASK UINT32_C(0x000003fe) +#define VMX_BF_VMCSFIELD_TYPE_SHIFT 10 +#define VMX_BF_VMCSFIELD_TYPE_MASK UINT32_C(0x00000c00) +#define VMX_BF_VMCSFIELD_RSVD_12_SHIFT 12 +#define VMX_BF_VMCSFIELD_RSVD_12_MASK UINT32_C(0x00001000) +#define VMX_BF_VMCSFIELD_WIDTH_SHIFT 13 +#define VMX_BF_VMCSFIELD_WIDTH_MASK UINT32_C(0x00006000) +#define VMX_BF_VMCSFIELD_RSVD_15_31_SHIFT 15 +#define VMX_BF_VMCSFIELD_RSVD_15_31_MASK UINT32_C(0xffff8000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_VMCSFIELD_, UINT32_C(0), UINT32_MAX, + (ACCESS_TYPE, INDEX, TYPE, RSVD_12, WIDTH, RSVD_15_31)); + +/** + * VMCS field encoding: Access type. + * In accordance with the VT-x spec. + */ +typedef enum +{ + VMXVMCSFIELDACCESS_FULL = 0, + VMXVMCSFIELDACCESS_HIGH +} VMXVMCSFIELDACCESS; +AssertCompileSize(VMXVMCSFIELDACCESS, 4); +/** VMCS field encoding type: Full. */ +#define VMX_VMCSFIELD_ACCESS_FULL 0 +/** VMCS field encoding type: High. */ +#define VMX_VMCSFIELD_ACCESS_HIGH 1 + +/** + * VMCS field encoding: Type. + * In accordance with the VT-x spec. + */ +typedef enum +{ + VMXVMCSFIELDTYPE_CONTROL = 0, + VMXVMCSFIELDTYPE_VMEXIT_INFO, + VMXVMCSFIELDTYPE_GUEST_STATE, + VMXVMCSFIELDTYPE_HOST_STATE +} VMXVMCSFIELDTYPE; +AssertCompileSize(VMXVMCSFIELDTYPE, 4); +/** VMCS field encoding type: Control. */ +#define VMX_VMCSFIELD_TYPE_CONTROL 0 +/** VMCS field encoding type: VM-exit information / read-only fields. */ +#define VMX_VMCSFIELD_TYPE_VMEXIT_INFO 1 +/** VMCS field encoding type: Guest-state. */ +#define VMX_VMCSFIELD_TYPE_GUEST_STATE 2 +/** VMCS field encoding type: Host-state. */ +#define VMX_VMCSFIELD_TYPE_HOST_STATE 3 + +/** + * VMCS field encoding: Width. + * In accordance with the VT-x spec. + */ +typedef enum +{ + VMXVMCSFIELDWIDTH_16BIT = 0, + VMXVMCSFIELDWIDTH_64BIT, + VMXVMCSFIELDWIDTH_32BIT, + VMXVMCSFIELDWIDTH_NATURAL +} VMXVMCSFIELDWIDTH; +AssertCompileSize(VMXVMCSFIELDWIDTH, 4); +/** VMCS field encoding width: 16-bit. */ +#define VMX_VMCSFIELD_WIDTH_16BIT 0 +/** VMCS field encoding width: 64-bit. */ +#define VMX_VMCSFIELD_WIDTH_64BIT 1 +/** VMCS field encoding width: 32-bit. */ +#define VMX_VMCSFIELD_WIDTH_32BIT 2 +/** VMCS field encoding width: Natural width. */ +#define VMX_VMCSFIELD_WIDTH_NATURAL 3 +/** @} */ + + +/** @name VM-entry instruction length. + * @{ */ +/** The maximum valid value for VM-entry instruction length while injecting a + * software interrupt, software exception or privileged software exception. */ +#define VMX_ENTRY_INSTR_LEN_MAX 15 +/** @} */ + + +/** @name VM-entry register masks. + * @{ */ +/** CR0 bits ignored on VM-entry while loading guest CR0 (ET, CD, NW, bits 6:15, + * bit 17 and bits 19:28). */ +#define VMX_ENTRY_GUEST_CR0_IGNORE_MASK UINT64_C(0x7ffaffd0) +/** DR7 bits set here are always cleared on VM-entry while loading guest DR7 (bit + * 12, bits 14:15). */ +#define VMX_ENTRY_GUEST_DR7_MBZ_MASK UINT64_C(0xd000) +/** DR7 bits set here are always set on VM-entry while loading guest DR7 (bit + * 10). */ +#define VMX_ENTRY_GUEST_DR7_MB1_MASK UINT64_C(0x400) +/** @} */ + + +/** @name VM-exit register masks. + * @{ */ +/** CR0 bits ignored on VM-exit while loading host CR0 (ET, CD, NW, bits 6:15, + * bit 17, bits 19:28 and bits 32:63). */ +#define VMX_EXIT_HOST_CR0_IGNORE_MASK UINT64_C(0xffffffff7ffaffd0) +/** @} */ + + +/** @name Pin-based VM-execution controls. + * @{ + */ +/** External interrupt exiting. */ +#define VMX_PIN_CTLS_EXT_INT_EXIT RT_BIT(0) +/** NMI exiting. */ +#define VMX_PIN_CTLS_NMI_EXIT RT_BIT(3) +/** Virtual NMIs. */ +#define VMX_PIN_CTLS_VIRT_NMI RT_BIT(5) +/** Activate VMX preemption timer. */ +#define VMX_PIN_CTLS_PREEMPT_TIMER RT_BIT(6) +/** Process interrupts with the posted-interrupt notification vector. */ +#define VMX_PIN_CTLS_POSTED_INT RT_BIT(7) +/** Default1 class when true capability MSRs are not supported. */ +#define VMX_PIN_CTLS_DEFAULT1 UINT32_C(0x00000016) + +/** Bit fields for MSR_IA32_VMX_PINBASED_CTLS and Pin-based VM-execution + * controls field in the VMCS. */ +#define VMX_BF_PIN_CTLS_EXT_INT_EXIT_SHIFT 0 +#define VMX_BF_PIN_CTLS_EXT_INT_EXIT_MASK UINT32_C(0x00000001) +#define VMX_BF_PIN_CTLS_RSVD_1_2_SHIFT 1 +#define VMX_BF_PIN_CTLS_RSVD_1_2_MASK UINT32_C(0x00000006) +#define VMX_BF_PIN_CTLS_NMI_EXIT_SHIFT 3 +#define VMX_BF_PIN_CTLS_NMI_EXIT_MASK UINT32_C(0x00000008) +#define VMX_BF_PIN_CTLS_RSVD_4_SHIFT 4 +#define VMX_BF_PIN_CTLS_RSVD_4_MASK UINT32_C(0x00000010) +#define VMX_BF_PIN_CTLS_VIRT_NMI_SHIFT 5 +#define VMX_BF_PIN_CTLS_VIRT_NMI_MASK UINT32_C(0x00000020) +#define VMX_BF_PIN_CTLS_PREEMPT_TIMER_SHIFT 6 +#define VMX_BF_PIN_CTLS_PREEMPT_TIMER_MASK UINT32_C(0x00000040) +#define VMX_BF_PIN_CTLS_POSTED_INT_SHIFT 7 +#define VMX_BF_PIN_CTLS_POSTED_INT_MASK UINT32_C(0x00000080) +#define VMX_BF_PIN_CTLS_RSVD_8_31_SHIFT 8 +#define VMX_BF_PIN_CTLS_RSVD_8_31_MASK UINT32_C(0xffffff00) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_PIN_CTLS_, UINT32_C(0), UINT32_MAX, + (EXT_INT_EXIT, RSVD_1_2, NMI_EXIT, RSVD_4, VIRT_NMI, PREEMPT_TIMER, POSTED_INT, RSVD_8_31)); +/** @} */ + + +/** @name Processor-based VM-execution controls. + * @{ + */ +/** VM-exit as soon as RFLAGS.IF=1 and no blocking is active. */ +#define VMX_PROC_CTLS_INT_WINDOW_EXIT RT_BIT(2) +/** Use timestamp counter offset. */ +#define VMX_PROC_CTLS_USE_TSC_OFFSETTING RT_BIT(3) +/** VM-exit when executing the HLT instruction. */ +#define VMX_PROC_CTLS_HLT_EXIT RT_BIT(7) +/** VM-exit when executing the INVLPG instruction. */ +#define VMX_PROC_CTLS_INVLPG_EXIT RT_BIT(9) +/** VM-exit when executing the MWAIT instruction. */ +#define VMX_PROC_CTLS_MWAIT_EXIT RT_BIT(10) +/** VM-exit when executing the RDPMC instruction. */ +#define VMX_PROC_CTLS_RDPMC_EXIT RT_BIT(11) +/** VM-exit when executing the RDTSC/RDTSCP instruction. */ +#define VMX_PROC_CTLS_RDTSC_EXIT RT_BIT(12) +/** VM-exit when executing the MOV to CR3 instruction. (forced to 1 on the + * 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */ +#define VMX_PROC_CTLS_CR3_LOAD_EXIT RT_BIT(15) +/** VM-exit when executing the MOV from CR3 instruction. (forced to 1 on the + * 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */ +#define VMX_PROC_CTLS_CR3_STORE_EXIT RT_BIT(16) +/** Whether the secondary processor based VM-execution controls are used. */ +#define VMX_PROC_CTLS_USE_TERTIARY_CTLS RT_BIT(17) +/** VM-exit on CR8 loads. */ +#define VMX_PROC_CTLS_CR8_LOAD_EXIT RT_BIT(19) +/** VM-exit on CR8 stores. */ +#define VMX_PROC_CTLS_CR8_STORE_EXIT RT_BIT(20) +/** Use TPR shadow. */ +#define VMX_PROC_CTLS_USE_TPR_SHADOW RT_BIT(21) +/** VM-exit when virtual NMI blocking is disabled. */ +#define VMX_PROC_CTLS_NMI_WINDOW_EXIT RT_BIT(22) +/** VM-exit when executing a MOV DRx instruction. */ +#define VMX_PROC_CTLS_MOV_DR_EXIT RT_BIT(23) +/** VM-exit when executing IO instructions. */ +#define VMX_PROC_CTLS_UNCOND_IO_EXIT RT_BIT(24) +/** Use IO bitmaps. */ +#define VMX_PROC_CTLS_USE_IO_BITMAPS RT_BIT(25) +/** Monitor trap flag. */ +#define VMX_PROC_CTLS_MONITOR_TRAP_FLAG RT_BIT(27) +/** Use MSR bitmaps. */ +#define VMX_PROC_CTLS_USE_MSR_BITMAPS RT_BIT(28) +/** VM-exit when executing the MONITOR instruction. */ +#define VMX_PROC_CTLS_MONITOR_EXIT RT_BIT(29) +/** VM-exit when executing the PAUSE instruction. */ +#define VMX_PROC_CTLS_PAUSE_EXIT RT_BIT(30) +/** Whether the secondary processor based VM-execution controls are used. */ +#define VMX_PROC_CTLS_USE_SECONDARY_CTLS RT_BIT(31) +/** Default1 class when true-capability MSRs are not supported. */ +#define VMX_PROC_CTLS_DEFAULT1 UINT32_C(0x0401e172) + +/** Bit fields for MSR_IA32_VMX_PROCBASED_CTLS and Processor-based VM-execution + * controls field in the VMCS. */ +#define VMX_BF_PROC_CTLS_RSVD_0_1_SHIFT 0 +#define VMX_BF_PROC_CTLS_RSVD_0_1_MASK UINT32_C(0x00000003) +#define VMX_BF_PROC_CTLS_INT_WINDOW_EXIT_SHIFT 2 +#define VMX_BF_PROC_CTLS_INT_WINDOW_EXIT_MASK UINT32_C(0x00000004) +#define VMX_BF_PROC_CTLS_USE_TSC_OFFSETTING_SHIFT 3 +#define VMX_BF_PROC_CTLS_USE_TSC_OFFSETTING_MASK UINT32_C(0x00000008) +#define VMX_BF_PROC_CTLS_RSVD_4_6_SHIFT 4 +#define VMX_BF_PROC_CTLS_RSVD_4_6_MASK UINT32_C(0x00000070) +#define VMX_BF_PROC_CTLS_HLT_EXIT_SHIFT 7 +#define VMX_BF_PROC_CTLS_HLT_EXIT_MASK UINT32_C(0x00000080) +#define VMX_BF_PROC_CTLS_RSVD_8_SHIFT 8 +#define VMX_BF_PROC_CTLS_RSVD_8_MASK UINT32_C(0x00000100) +#define VMX_BF_PROC_CTLS_INVLPG_EXIT_SHIFT 9 +#define VMX_BF_PROC_CTLS_INVLPG_EXIT_MASK UINT32_C(0x00000200) +#define VMX_BF_PROC_CTLS_MWAIT_EXIT_SHIFT 10 +#define VMX_BF_PROC_CTLS_MWAIT_EXIT_MASK UINT32_C(0x00000400) +#define VMX_BF_PROC_CTLS_RDPMC_EXIT_SHIFT 11 +#define VMX_BF_PROC_CTLS_RDPMC_EXIT_MASK UINT32_C(0x00000800) +#define VMX_BF_PROC_CTLS_RDTSC_EXIT_SHIFT 12 +#define VMX_BF_PROC_CTLS_RDTSC_EXIT_MASK UINT32_C(0x00001000) +#define VMX_BF_PROC_CTLS_RSVD_13_14_SHIFT 13 +#define VMX_BF_PROC_CTLS_RSVD_13_14_MASK UINT32_C(0x00006000) +#define VMX_BF_PROC_CTLS_CR3_LOAD_EXIT_SHIFT 15 +#define VMX_BF_PROC_CTLS_CR3_LOAD_EXIT_MASK UINT32_C(0x00008000) +#define VMX_BF_PROC_CTLS_CR3_STORE_EXIT_SHIFT 16 +#define VMX_BF_PROC_CTLS_CR3_STORE_EXIT_MASK UINT32_C(0x00010000) +#define VMX_BF_PROC_CTLS_USE_TERTIARY_CTLS_SHIFT 17 +#define VMX_BF_PROC_CTLS_USE_TERTIARY_CTLS_MASK UINT32_C(0x00020000) +#define VMX_BF_PROC_CTLS_RSVD_18_SHIFT 18 +#define VMX_BF_PROC_CTLS_RSVD_18_MASK UINT32_C(0x00040000) +#define VMX_BF_PROC_CTLS_CR8_LOAD_EXIT_SHIFT 19 +#define VMX_BF_PROC_CTLS_CR8_LOAD_EXIT_MASK UINT32_C(0x00080000) +#define VMX_BF_PROC_CTLS_CR8_STORE_EXIT_SHIFT 20 +#define VMX_BF_PROC_CTLS_CR8_STORE_EXIT_MASK UINT32_C(0x00100000) +#define VMX_BF_PROC_CTLS_USE_TPR_SHADOW_SHIFT 21 +#define VMX_BF_PROC_CTLS_USE_TPR_SHADOW_MASK UINT32_C(0x00200000) +#define VMX_BF_PROC_CTLS_NMI_WINDOW_EXIT_SHIFT 22 +#define VMX_BF_PROC_CTLS_NMI_WINDOW_EXIT_MASK UINT32_C(0x00400000) +#define VMX_BF_PROC_CTLS_MOV_DR_EXIT_SHIFT 23 +#define VMX_BF_PROC_CTLS_MOV_DR_EXIT_MASK UINT32_C(0x00800000) +#define VMX_BF_PROC_CTLS_UNCOND_IO_EXIT_SHIFT 24 +#define VMX_BF_PROC_CTLS_UNCOND_IO_EXIT_MASK UINT32_C(0x01000000) +#define VMX_BF_PROC_CTLS_USE_IO_BITMAPS_SHIFT 25 +#define VMX_BF_PROC_CTLS_USE_IO_BITMAPS_MASK UINT32_C(0x02000000) +#define VMX_BF_PROC_CTLS_RSVD_26_SHIFT 26 +#define VMX_BF_PROC_CTLS_RSVD_26_MASK UINT32_C(0x4000000) +#define VMX_BF_PROC_CTLS_MONITOR_TRAP_FLAG_SHIFT 27 +#define VMX_BF_PROC_CTLS_MONITOR_TRAP_FLAG_MASK UINT32_C(0x08000000) +#define VMX_BF_PROC_CTLS_USE_MSR_BITMAPS_SHIFT 28 +#define VMX_BF_PROC_CTLS_USE_MSR_BITMAPS_MASK UINT32_C(0x10000000) +#define VMX_BF_PROC_CTLS_MONITOR_EXIT_SHIFT 29 +#define VMX_BF_PROC_CTLS_MONITOR_EXIT_MASK UINT32_C(0x20000000) +#define VMX_BF_PROC_CTLS_PAUSE_EXIT_SHIFT 30 +#define VMX_BF_PROC_CTLS_PAUSE_EXIT_MASK UINT32_C(0x40000000) +#define VMX_BF_PROC_CTLS_USE_SECONDARY_CTLS_SHIFT 31 +#define VMX_BF_PROC_CTLS_USE_SECONDARY_CTLS_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_PROC_CTLS_, UINT32_C(0), UINT32_MAX, + (RSVD_0_1, INT_WINDOW_EXIT, USE_TSC_OFFSETTING, RSVD_4_6, HLT_EXIT, RSVD_8, INVLPG_EXIT, + MWAIT_EXIT, RDPMC_EXIT, RDTSC_EXIT, RSVD_13_14, CR3_LOAD_EXIT, CR3_STORE_EXIT, USE_TERTIARY_CTLS, + RSVD_18, CR8_LOAD_EXIT, CR8_STORE_EXIT, USE_TPR_SHADOW, NMI_WINDOW_EXIT, MOV_DR_EXIT, UNCOND_IO_EXIT, + USE_IO_BITMAPS, RSVD_26, MONITOR_TRAP_FLAG, USE_MSR_BITMAPS, MONITOR_EXIT, PAUSE_EXIT, + USE_SECONDARY_CTLS)); +/** @} */ + + +/** @name Secondary Processor-based VM-execution controls. + * @{ + */ +/** Virtualize APIC accesses. */ +#define VMX_PROC_CTLS2_VIRT_APIC_ACCESS RT_BIT(0) +/** EPT supported/enabled. */ +#define VMX_PROC_CTLS2_EPT RT_BIT(1) +/** Descriptor table instructions cause VM-exits. */ +#define VMX_PROC_CTLS2_DESC_TABLE_EXIT RT_BIT(2) +/** RDTSCP supported/enabled. */ +#define VMX_PROC_CTLS2_RDTSCP RT_BIT(3) +/** Virtualize x2APIC mode. */ +#define VMX_PROC_CTLS2_VIRT_X2APIC_MODE RT_BIT(4) +/** VPID supported/enabled. */ +#define VMX_PROC_CTLS2_VPID RT_BIT(5) +/** VM-exit when executing the WBINVD instruction. */ +#define VMX_PROC_CTLS2_WBINVD_EXIT RT_BIT(6) +/** Unrestricted guest execution. */ +#define VMX_PROC_CTLS2_UNRESTRICTED_GUEST RT_BIT(7) +/** APIC register virtualization. */ +#define VMX_PROC_CTLS2_APIC_REG_VIRT RT_BIT(8) +/** Virtual-interrupt delivery. */ +#define VMX_PROC_CTLS2_VIRT_INT_DELIVERY RT_BIT(9) +/** A specified number of pause loops cause a VM-exit. */ +#define VMX_PROC_CTLS2_PAUSE_LOOP_EXIT RT_BIT(10) +/** VM-exit when executing RDRAND instructions. */ +#define VMX_PROC_CTLS2_RDRAND_EXIT RT_BIT(11) +/** Enables INVPCID instructions. */ +#define VMX_PROC_CTLS2_INVPCID RT_BIT(12) +/** Enables VMFUNC instructions. */ +#define VMX_PROC_CTLS2_VMFUNC RT_BIT(13) +/** Enables VMCS shadowing. */ +#define VMX_PROC_CTLS2_VMCS_SHADOWING RT_BIT(14) +/** Enables ENCLS VM-exits. */ +#define VMX_PROC_CTLS2_ENCLS_EXIT RT_BIT(15) +/** VM-exit when executing RDSEED. */ +#define VMX_PROC_CTLS2_RDSEED_EXIT RT_BIT(16) +/** Enables page-modification logging. */ +#define VMX_PROC_CTLS2_PML RT_BIT(17) +/** Controls whether EPT-violations may cause \#VE instead of exits. */ +#define VMX_PROC_CTLS2_EPT_XCPT_VE RT_BIT(18) +/** Conceal VMX non-root operation from Intel processor trace (PT). */ +#define VMX_PROC_CTLS2_CONCEAL_VMX_FROM_PT RT_BIT(19) +/** Enables XSAVES/XRSTORS instructions. */ +#define VMX_PROC_CTLS2_XSAVES_XRSTORS RT_BIT(20) +/** Enables supervisor/user mode based EPT execute permission for linear + * addresses. */ +#define VMX_PROC_CTLS2_MODE_BASED_EPT_PERM RT_BIT(22) +/** Enables EPT write permissions to be specified at granularity of 128 bytes. */ +#define VMX_PROC_CTLS2_SPP_EPT RT_BIT(23) +/** Intel PT output addresses are treated as guest-physical addresses and + * translated using EPT. */ +#define VMX_PROC_CTLS2_PT_EPT RT_BIT(24) +/** Use TSC scaling. */ +#define VMX_PROC_CTLS2_TSC_SCALING RT_BIT(25) +/** Enables TPAUSE, UMONITOR and UMWAIT instructions. */ +#define VMX_PROC_CTLS2_USER_WAIT_PAUSE RT_BIT(26) +/** Enables consulting ENCLV-exiting bitmap when executing ENCLV. */ +#define VMX_PROC_CTLS2_ENCLV_EXIT RT_BIT(28) + +/** Bit fields for MSR_IA32_VMX_PROCBASED_CTLS2 and Secondary processor-based + * VM-execution controls field in the VMCS. */ +#define VMX_BF_PROC_CTLS2_VIRT_APIC_ACCESS_SHIFT 0 +#define VMX_BF_PROC_CTLS2_VIRT_APIC_ACCESS_MASK UINT32_C(0x00000001) +#define VMX_BF_PROC_CTLS2_EPT_SHIFT 1 +#define VMX_BF_PROC_CTLS2_EPT_MASK UINT32_C(0x00000002) +#define VMX_BF_PROC_CTLS2_DESC_TABLE_EXIT_SHIFT 2 +#define VMX_BF_PROC_CTLS2_DESC_TABLE_EXIT_MASK UINT32_C(0x00000004) +#define VMX_BF_PROC_CTLS2_RDTSCP_SHIFT 3 +#define VMX_BF_PROC_CTLS2_RDTSCP_MASK UINT32_C(0x00000008) +#define VMX_BF_PROC_CTLS2_VIRT_X2APIC_MODE_SHIFT 4 +#define VMX_BF_PROC_CTLS2_VIRT_X2APIC_MODE_MASK UINT32_C(0x00000010) +#define VMX_BF_PROC_CTLS2_VPID_SHIFT 5 +#define VMX_BF_PROC_CTLS2_VPID_MASK UINT32_C(0x00000020) +#define VMX_BF_PROC_CTLS2_WBINVD_EXIT_SHIFT 6 +#define VMX_BF_PROC_CTLS2_WBINVD_EXIT_MASK UINT32_C(0x00000040) +#define VMX_BF_PROC_CTLS2_UNRESTRICTED_GUEST_SHIFT 7 +#define VMX_BF_PROC_CTLS2_UNRESTRICTED_GUEST_MASK UINT32_C(0x00000080) +#define VMX_BF_PROC_CTLS2_APIC_REG_VIRT_SHIFT 8 +#define VMX_BF_PROC_CTLS2_APIC_REG_VIRT_MASK UINT32_C(0x00000100) +#define VMX_BF_PROC_CTLS2_VIRT_INT_DELIVERY_SHIFT 9 +#define VMX_BF_PROC_CTLS2_VIRT_INT_DELIVERY_MASK UINT32_C(0x00000200) +#define VMX_BF_PROC_CTLS2_PAUSE_LOOP_EXIT_SHIFT 10 +#define VMX_BF_PROC_CTLS2_PAUSE_LOOP_EXIT_MASK UINT32_C(0x00000400) +#define VMX_BF_PROC_CTLS2_RDRAND_EXIT_SHIFT 11 +#define VMX_BF_PROC_CTLS2_RDRAND_EXIT_MASK UINT32_C(0x00000800) +#define VMX_BF_PROC_CTLS2_INVPCID_SHIFT 12 +#define VMX_BF_PROC_CTLS2_INVPCID_MASK UINT32_C(0x00001000) +#define VMX_BF_PROC_CTLS2_VMFUNC_SHIFT 13 +#define VMX_BF_PROC_CTLS2_VMFUNC_MASK UINT32_C(0x00002000) +#define VMX_BF_PROC_CTLS2_VMCS_SHADOWING_SHIFT 14 +#define VMX_BF_PROC_CTLS2_VMCS_SHADOWING_MASK UINT32_C(0x00004000) +#define VMX_BF_PROC_CTLS2_ENCLS_EXIT_SHIFT 15 +#define VMX_BF_PROC_CTLS2_ENCLS_EXIT_MASK UINT32_C(0x00008000) +#define VMX_BF_PROC_CTLS2_RDSEED_EXIT_SHIFT 16 +#define VMX_BF_PROC_CTLS2_RDSEED_EXIT_MASK UINT32_C(0x00010000) +#define VMX_BF_PROC_CTLS2_PML_SHIFT 17 +#define VMX_BF_PROC_CTLS2_PML_MASK UINT32_C(0x00020000) +#define VMX_BF_PROC_CTLS2_EPT_VE_SHIFT 18 +#define VMX_BF_PROC_CTLS2_EPT_VE_MASK UINT32_C(0x00040000) +#define VMX_BF_PROC_CTLS2_CONCEAL_VMX_FROM_PT_SHIFT 19 +#define VMX_BF_PROC_CTLS2_CONCEAL_VMX_FROM_PT_MASK UINT32_C(0x00080000) +#define VMX_BF_PROC_CTLS2_XSAVES_XRSTORS_SHIFT 20 +#define VMX_BF_PROC_CTLS2_XSAVES_XRSTORS_MASK UINT32_C(0x00100000) +#define VMX_BF_PROC_CTLS2_RSVD_21_SHIFT 21 +#define VMX_BF_PROC_CTLS2_RSVD_21_MASK UINT32_C(0x00200000) +#define VMX_BF_PROC_CTLS2_MODE_BASED_EPT_PERM_SHIFT 22 +#define VMX_BF_PROC_CTLS2_MODE_BASED_EPT_PERM_MASK UINT32_C(0x00400000) +#define VMX_BF_PROC_CTLS2_SPP_EPT_SHIFT 23 +#define VMX_BF_PROC_CTLS2_SPP_EPT_MASK UINT32_C(0x00800000) +#define VMX_BF_PROC_CTLS2_PT_EPT_SHIFT 24 +#define VMX_BF_PROC_CTLS2_PT_EPT_MASK UINT32_C(0x01000000) +#define VMX_BF_PROC_CTLS2_TSC_SCALING_SHIFT 25 +#define VMX_BF_PROC_CTLS2_TSC_SCALING_MASK UINT32_C(0x02000000) +#define VMX_BF_PROC_CTLS2_USER_WAIT_PAUSE_SHIFT 26 +#define VMX_BF_PROC_CTLS2_USER_WAIT_PAUSE_MASK UINT32_C(0x04000000) +#define VMX_BF_PROC_CTLS2_RSVD_27_SHIFT 27 +#define VMX_BF_PROC_CTLS2_RSVD_27_MASK UINT32_C(0x08000000) +#define VMX_BF_PROC_CTLS2_ENCLV_EXIT_SHIFT 28 +#define VMX_BF_PROC_CTLS2_ENCLV_EXIT_MASK UINT32_C(0x10000000) +#define VMX_BF_PROC_CTLS2_RSVD_29_31_SHIFT 29 +#define VMX_BF_PROC_CTLS2_RSVD_29_31_MASK UINT32_C(0xe0000000) + +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_PROC_CTLS2_, UINT32_C(0), UINT32_MAX, + (VIRT_APIC_ACCESS, EPT, DESC_TABLE_EXIT, RDTSCP, VIRT_X2APIC_MODE, VPID, WBINVD_EXIT, + UNRESTRICTED_GUEST, APIC_REG_VIRT, VIRT_INT_DELIVERY, PAUSE_LOOP_EXIT, RDRAND_EXIT, INVPCID, VMFUNC, + VMCS_SHADOWING, ENCLS_EXIT, RDSEED_EXIT, PML, EPT_VE, CONCEAL_VMX_FROM_PT, XSAVES_XRSTORS, RSVD_21, + MODE_BASED_EPT_PERM, SPP_EPT, PT_EPT, TSC_SCALING, USER_WAIT_PAUSE, RSVD_27, ENCLV_EXIT, + RSVD_29_31)); +/** @} */ + + +/** @name Tertiary Processor-based VM-execution controls. + * @{ + */ +/** VM-exit when executing LOADIWKEY. */ +#define VMX_PROC_CTLS3_LOADIWKEY_EXIT RT_BIT_64(0) + +/** Bit fields for Tertiary processor-based VM-execution controls field in the VMCS. */ +#define VMX_BF_PROC_CTLS3_LOADIWKEY_EXIT_SHIFT 0 +#define VMX_BF_PROC_CTLS3_LOADIWKEY_EXIT_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_PROC_CTLS3_RSVD_1_63_SHIFT 1 +#define VMX_BF_PROC_CTLS3_RSVD_1_63_MASK UINT64_C(0xfffffffffffffffe) + +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_PROC_CTLS3_, UINT64_C(0), UINT64_MAX, + (LOADIWKEY_EXIT, RSVD_1_63)); +/** @} */ + + +/** @name VM-entry controls. + * @{ + */ +/** Load guest debug controls (dr7 & IA32_DEBUGCTL_MSR) (forced to 1 on the + * 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */ +#define VMX_ENTRY_CTLS_LOAD_DEBUG RT_BIT(2) +/** 64-bit guest mode. Must be 0 for CPUs that don't support AMD64. */ +#define VMX_ENTRY_CTLS_IA32E_MODE_GUEST RT_BIT(9) +/** In SMM mode after VM-entry. */ +#define VMX_ENTRY_CTLS_ENTRY_TO_SMM RT_BIT(10) +/** Disable dual treatment of SMI and SMM; must be zero for VM-entry outside of SMM. */ +#define VMX_ENTRY_CTLS_DEACTIVATE_DUAL_MON RT_BIT(11) +/** Whether the guest IA32_PERF_GLOBAL_CTRL MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_PERF_MSR RT_BIT(13) +/** Whether the guest IA32_PAT MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_PAT_MSR RT_BIT(14) +/** Whether the guest IA32_EFER MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_EFER_MSR RT_BIT(15) +/** Whether the guest IA32_BNDCFGS MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_BNDCFGS_MSR RT_BIT(16) +/** Whether to conceal VMX from Intel PT (Processor Trace). */ +#define VMX_ENTRY_CTLS_CONCEAL_VMX_FROM_PT RT_BIT(17) +/** Whether the guest IA32_RTIT MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_RTIT_CTL_MSR RT_BIT(18) +/** Whether the guest CET-related MSRs and SPP are loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_CET_STATE RT_BIT(20) +/** Whether the guest IA32_PKRS MSR is loaded on VM-entry. */ +#define VMX_ENTRY_CTLS_LOAD_PKRS_MSR RT_BIT(22) +/** Default1 class when true-capability MSRs are not supported. */ +#define VMX_ENTRY_CTLS_DEFAULT1 UINT32_C(0x000011ff) + +/** Bit fields for MSR_IA32_VMX_ENTRY_CTLS and VM-entry controls field in the + * VMCS. */ +#define VMX_BF_ENTRY_CTLS_RSVD_0_1_SHIFT 0 +#define VMX_BF_ENTRY_CTLS_RSVD_0_1_MASK UINT32_C(0x00000003) +#define VMX_BF_ENTRY_CTLS_LOAD_DEBUG_SHIFT 2 +#define VMX_BF_ENTRY_CTLS_LOAD_DEBUG_MASK UINT32_C(0x00000004) +#define VMX_BF_ENTRY_CTLS_RSVD_3_8_SHIFT 3 +#define VMX_BF_ENTRY_CTLS_RSVD_3_8_MASK UINT32_C(0x000001f8) +#define VMX_BF_ENTRY_CTLS_IA32E_MODE_GUEST_SHIFT 9 +#define VMX_BF_ENTRY_CTLS_IA32E_MODE_GUEST_MASK UINT32_C(0x00000200) +#define VMX_BF_ENTRY_CTLS_ENTRY_SMM_SHIFT 10 +#define VMX_BF_ENTRY_CTLS_ENTRY_SMM_MASK UINT32_C(0x00000400) +#define VMX_BF_ENTRY_CTLS_DEACTIVATE_DUAL_MON_SHIFT 11 +#define VMX_BF_ENTRY_CTLS_DEACTIVATE_DUAL_MON_MASK UINT32_C(0x00000800) +#define VMX_BF_ENTRY_CTLS_RSVD_12_SHIFT 12 +#define VMX_BF_ENTRY_CTLS_RSVD_12_MASK UINT32_C(0x00001000) +#define VMX_BF_ENTRY_CTLS_LOAD_PERF_MSR_SHIFT 13 +#define VMX_BF_ENTRY_CTLS_LOAD_PERF_MSR_MASK UINT32_C(0x00002000) +#define VMX_BF_ENTRY_CTLS_LOAD_PAT_MSR_SHIFT 14 +#define VMX_BF_ENTRY_CTLS_LOAD_PAT_MSR_MASK UINT32_C(0x00004000) +#define VMX_BF_ENTRY_CTLS_LOAD_EFER_MSR_SHIFT 15 +#define VMX_BF_ENTRY_CTLS_LOAD_EFER_MSR_MASK UINT32_C(0x00008000) +#define VMX_BF_ENTRY_CTLS_LOAD_BNDCFGS_MSR_SHIFT 16 +#define VMX_BF_ENTRY_CTLS_LOAD_BNDCFGS_MSR_MASK UINT32_C(0x00010000) +#define VMX_BF_ENTRY_CTLS_CONCEAL_VMX_FROM_PT_SHIFT 17 +#define VMX_BF_ENTRY_CTLS_CONCEAL_VMX_FROM_PT_MASK UINT32_C(0x00020000) +#define VMX_BF_ENTRY_CTLS_LOAD_RTIT_CTL_MSR_SHIFT 18 +#define VMX_BF_ENTRY_CTLS_LOAD_RTIT_CTL_MSR_MASK UINT32_C(0x00040000) +#define VMX_BF_ENTRY_CTLS_RSVD_19_SHIFT 19 +#define VMX_BF_ENTRY_CTLS_RSVD_19_MASK UINT32_C(0x00080000) +#define VMX_BF_ENTRY_CTLS_LOAD_CET_SHIFT 20 +#define VMX_BF_ENTRY_CTLS_LOAD_CET_MASK UINT32_C(0x00100000) +#define VMX_BF_ENTRY_CTLS_RSVD_21_SHIFT 21 +#define VMX_BF_ENTRY_CTLS_RSVD_21_MASK UINT32_C(0x00200000) +#define VMX_BF_ENTRY_CTLS_LOAD_PKRS_MSR_SHIFT 22 +#define VMX_BF_ENTRY_CTLS_LOAD_PKRS_MSR_MASK UINT32_C(0x00400000) +#define VMX_BF_ENTRY_CTLS_RSVD_23_31_SHIFT 23 +#define VMX_BF_ENTRY_CTLS_RSVD_23_31_MASK UINT32_C(0xff800000) + +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_ENTRY_CTLS_, UINT32_C(0), UINT32_MAX, + (RSVD_0_1, LOAD_DEBUG, RSVD_3_8, IA32E_MODE_GUEST, ENTRY_SMM, DEACTIVATE_DUAL_MON, RSVD_12, + LOAD_PERF_MSR, LOAD_PAT_MSR, LOAD_EFER_MSR, LOAD_BNDCFGS_MSR, CONCEAL_VMX_FROM_PT, + LOAD_RTIT_CTL_MSR, RSVD_19, LOAD_CET, RSVD_21, LOAD_PKRS_MSR, RSVD_23_31)); +/** @} */ + + +/** @name VM-exit controls. + * @{ + */ +/** Save guest debug controls (dr7 & IA32_DEBUGCTL_MSR) (forced to 1 on the + * 'first' VT-x capable CPUs; this actually includes the newest Nehalem CPUs) */ +#define VMX_EXIT_CTLS_SAVE_DEBUG RT_BIT(2) +/** Return to long mode after a VM-exit. */ +#define VMX_EXIT_CTLS_HOST_ADDR_SPACE_SIZE RT_BIT(9) +/** Whether the host IA32_PERF_GLOBAL_CTRL MSR is loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_PERF_MSR RT_BIT(12) +/** Acknowledge external interrupts with the irq controller if one caused a VM-exit. */ +#define VMX_EXIT_CTLS_ACK_EXT_INT RT_BIT(15) +/** Whether the guest IA32_PAT MSR is saved on VM-exit. */ +#define VMX_EXIT_CTLS_SAVE_PAT_MSR RT_BIT(18) +/** Whether the host IA32_PAT MSR is loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_PAT_MSR RT_BIT(19) +/** Whether the guest IA32_EFER MSR is saved on VM-exit. */ +#define VMX_EXIT_CTLS_SAVE_EFER_MSR RT_BIT(20) +/** Whether the host IA32_EFER MSR is loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_EFER_MSR RT_BIT(21) +/** Whether the value of the VMX preemption timer is saved on every VM-exit. */ +#define VMX_EXIT_CTLS_SAVE_PREEMPT_TIMER RT_BIT(22) +/** Whether IA32_BNDCFGS MSR is cleared on VM-exit. */ +#define VMX_EXIT_CTLS_CLEAR_BNDCFGS_MSR RT_BIT(23) +/** Whether to conceal VMX from Intel PT. */ +#define VMX_EXIT_CTLS_CONCEAL_VMX_FROM_PT RT_BIT(24) +/** Whether IA32_RTIT_CTL MSR is cleared on VM-exit. */ +#define VMX_EXIT_CTLS_CLEAR_RTIT_CTL_MSR RT_BIT(25) +/** Whether CET-related MSRs and SPP are loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_CET_STATE RT_BIT(28) +/** Whether the host IA32_PKRS MSR is loaded on VM-exit. */ +#define VMX_EXIT_CTLS_LOAD_PKRS_MSR RT_BIT(29) +/** Whether the host IA32_PERF_GLOBAL_CTRL MSR is saved on VM-exit. */ +#define VMX_EXIT_CTLS_SAVE_PERF_MSR RT_BIT(30) +/** Whether secondary VM-exit controls are used. */ +#define VMX_EXIT_CTLS_USE_SECONDARY_CTLS RT_BIT(31) +/** Default1 class when true-capability MSRs are not supported. */ +#define VMX_EXIT_CTLS_DEFAULT1 UINT32_C(0x00036dff) + +/** Bit fields for MSR_IA32_VMX_EXIT_CTLS and VM-exit controls field in the + * VMCS. */ +#define VMX_BF_EXIT_CTLS_RSVD_0_1_SHIFT 0 +#define VMX_BF_EXIT_CTLS_RSVD_0_1_MASK UINT32_C(0x00000003) +#define VMX_BF_EXIT_CTLS_SAVE_DEBUG_SHIFT 2 +#define VMX_BF_EXIT_CTLS_SAVE_DEBUG_MASK UINT32_C(0x00000004) +#define VMX_BF_EXIT_CTLS_RSVD_3_8_SHIFT 3 +#define VMX_BF_EXIT_CTLS_RSVD_3_8_MASK UINT32_C(0x000001f8) +#define VMX_BF_EXIT_CTLS_HOST_ADDR_SPACE_SIZE_SHIFT 9 +#define VMX_BF_EXIT_CTLS_HOST_ADDR_SPACE_SIZE_MASK UINT32_C(0x00000200) +#define VMX_BF_EXIT_CTLS_RSVD_10_11_SHIFT 10 +#define VMX_BF_EXIT_CTLS_RSVD_10_11_MASK UINT32_C(0x00000c00) +#define VMX_BF_EXIT_CTLS_LOAD_PERF_MSR_SHIFT 12 +#define VMX_BF_EXIT_CTLS_LOAD_PERF_MSR_MASK UINT32_C(0x00001000) +#define VMX_BF_EXIT_CTLS_RSVD_13_14_SHIFT 13 +#define VMX_BF_EXIT_CTLS_RSVD_13_14_MASK UINT32_C(0x00006000) +#define VMX_BF_EXIT_CTLS_ACK_EXT_INT_SHIFT 15 +#define VMX_BF_EXIT_CTLS_ACK_EXT_INT_MASK UINT32_C(0x00008000) +#define VMX_BF_EXIT_CTLS_RSVD_16_17_SHIFT 16 +#define VMX_BF_EXIT_CTLS_RSVD_16_17_MASK UINT32_C(0x00030000) +#define VMX_BF_EXIT_CTLS_SAVE_PAT_MSR_SHIFT 18 +#define VMX_BF_EXIT_CTLS_SAVE_PAT_MSR_MASK UINT32_C(0x00040000) +#define VMX_BF_EXIT_CTLS_LOAD_PAT_MSR_SHIFT 19 +#define VMX_BF_EXIT_CTLS_LOAD_PAT_MSR_MASK UINT32_C(0x00080000) +#define VMX_BF_EXIT_CTLS_SAVE_EFER_MSR_SHIFT 20 +#define VMX_BF_EXIT_CTLS_SAVE_EFER_MSR_MASK UINT32_C(0x00100000) +#define VMX_BF_EXIT_CTLS_LOAD_EFER_MSR_SHIFT 21 +#define VMX_BF_EXIT_CTLS_LOAD_EFER_MSR_MASK UINT32_C(0x00200000) +#define VMX_BF_EXIT_CTLS_SAVE_PREEMPT_TIMER_SHIFT 22 +#define VMX_BF_EXIT_CTLS_SAVE_PREEMPT_TIMER_MASK UINT32_C(0x00400000) +#define VMX_BF_EXIT_CTLS_CLEAR_BNDCFGS_MSR_SHIFT 23 +#define VMX_BF_EXIT_CTLS_CLEAR_BNDCFGS_MSR_MASK UINT32_C(0x00800000) +#define VMX_BF_EXIT_CTLS_CONCEAL_VMX_FROM_PT_SHIFT 24 +#define VMX_BF_EXIT_CTLS_CONCEAL_VMX_FROM_PT_MASK UINT32_C(0x01000000) +#define VMX_BF_EXIT_CTLS_CLEAR_RTIT_CTL_MSR_SHIFT 25 +#define VMX_BF_EXIT_CTLS_CLEAR_RTIT_CTL_MSR_MASK UINT32_C(0x02000000) +#define VMX_BF_EXIT_CTLS_RSVD_26_27_SHIFT 26 +#define VMX_BF_EXIT_CTLS_RSVD_26_27_MASK UINT32_C(0x0c000000) +#define VMX_BF_EXIT_CTLS_LOAD_CET_SHIFT 28 +#define VMX_BF_EXIT_CTLS_LOAD_CET_MASK UINT32_C(0x10000000) +#define VMX_BF_EXIT_CTLS_LOAD_PKRS_MSR_SHIFT 29 +#define VMX_BF_EXIT_CTLS_LOAD_PKRS_MSR_MASK UINT32_C(0x20000000) +#define VMX_BF_EXIT_CTLS_SAVE_PERF_MSR_SHIFT 30 +#define VMX_BF_EXIT_CTLS_SAVE_PERF_MSR_MASK UINT32_C(0x40000000) +#define VMX_BF_EXIT_CTLS_USE_SECONDARY_CTLS_SHIFT 31 +#define VMX_BF_EXIT_CTLS_USE_SECONDARY_CTLS_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_CTLS_, UINT32_C(0), UINT32_MAX, + (RSVD_0_1, SAVE_DEBUG, RSVD_3_8, HOST_ADDR_SPACE_SIZE, RSVD_10_11, LOAD_PERF_MSR, RSVD_13_14, + ACK_EXT_INT, RSVD_16_17, SAVE_PAT_MSR, LOAD_PAT_MSR, SAVE_EFER_MSR, LOAD_EFER_MSR, + SAVE_PREEMPT_TIMER, CLEAR_BNDCFGS_MSR, CONCEAL_VMX_FROM_PT, CLEAR_RTIT_CTL_MSR, RSVD_26_27, + LOAD_CET, LOAD_PKRS_MSR, SAVE_PERF_MSR, USE_SECONDARY_CTLS)); +/** @} */ + + +/** @name VM-exit reason. + * @{ + */ +#define VMX_EXIT_REASON_BASIC(a) ((a) & 0xffff) +#define VMX_EXIT_REASON_HAS_ENTRY_FAILED(a) (((a) >> 31) & 1) +#define VMX_EXIT_REASON_ENTRY_FAILED RT_BIT(31) + +/** Bit fields for VM-exit reason. */ +/** The exit reason. */ +#define VMX_BF_EXIT_REASON_BASIC_SHIFT 0 +#define VMX_BF_EXIT_REASON_BASIC_MASK UINT32_C(0x0000ffff) +/** Bits 16:26 are reseved and MBZ. */ +#define VMX_BF_EXIT_REASON_RSVD_16_26_SHIFT 16 +#define VMX_BF_EXIT_REASON_RSVD_16_26_MASK UINT32_C(0x07ff0000) +/** Whether the VM-exit was incident to enclave mode. */ +#define VMX_BF_EXIT_REASON_ENCLAVE_MODE_SHIFT 27 +#define VMX_BF_EXIT_REASON_ENCLAVE_MODE_MASK UINT32_C(0x08000000) +/** Pending MTF (Monitor Trap Flag) during VM-exit (only applicable in SMM mode). */ +#define VMX_BF_EXIT_REASON_SMM_PENDING_MTF_SHIFT 28 +#define VMX_BF_EXIT_REASON_SMM_PENDING_MTF_MASK UINT32_C(0x10000000) +/** VM-exit from VMX root operation (only possible with SMM). */ +#define VMX_BF_EXIT_REASON_VMX_ROOT_MODE_SHIFT 29 +#define VMX_BF_EXIT_REASON_VMX_ROOT_MODE_MASK UINT32_C(0x20000000) +/** Bit 30 is reserved and MBZ. */ +#define VMX_BF_EXIT_REASON_RSVD_30_SHIFT 30 +#define VMX_BF_EXIT_REASON_RSVD_30_MASK UINT32_C(0x40000000) +/** Whether VM-entry failed (currently only happens during loading guest-state + * or MSRs or machine check exceptions). */ +#define VMX_BF_EXIT_REASON_ENTRY_FAILED_SHIFT 31 +#define VMX_BF_EXIT_REASON_ENTRY_FAILED_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_REASON_, UINT32_C(0), UINT32_MAX, + (BASIC, RSVD_16_26, ENCLAVE_MODE, SMM_PENDING_MTF, VMX_ROOT_MODE, RSVD_30, ENTRY_FAILED)); +/** @} */ + + +/** @name VM-entry interruption information. + * @{ + */ +#define VMX_ENTRY_INT_INFO_IS_VALID(a) (((a) >> 31) & 1) +#define VMX_ENTRY_INT_INFO_VECTOR(a) ((a) & 0xff) +#define VMX_ENTRY_INT_INFO_TYPE_SHIFT 8 +#define VMX_ENTRY_INT_INFO_TYPE(a) (((a) >> 8) & 7) +#define VMX_ENTRY_INT_INFO_ERROR_CODE_VALID RT_BIT(11) +#define VMX_ENTRY_INT_INFO_IS_ERROR_CODE_VALID(a) (((a) >> 11) & 1) +#define VMX_ENTRY_INT_INFO_NMI_UNBLOCK_IRET 12 +#define VMX_ENTRY_INT_INFO_IS_NMI_UNBLOCK_IRET(a) (((a) >> 12) & 1) +#define VMX_ENTRY_INT_INFO_VALID RT_BIT(31) +#define VMX_ENTRY_INT_INFO_IS_VALID(a) (((a) >> 31) & 1) +/** Construct an VM-entry interruption information field from a VM-exit interruption + * info value (same except that bit 12 is reserved). */ +#define VMX_ENTRY_INT_INFO_FROM_EXIT_INT_INFO(a) ((a) & ~RT_BIT(12)) +/** Construct a VM-entry interruption information field from an IDT-vectoring + * information field (same except that bit 12 is reserved). */ +#define VMX_ENTRY_INT_INFO_FROM_EXIT_IDT_INFO(a) ((a) & ~RT_BIT(12)) +/** If the VM-entry interruption information field indicates a page-fault. */ +#define VMX_ENTRY_INT_INFO_IS_XCPT_PF(a) (((a) & ( VMX_BF_ENTRY_INT_INFO_VALID_MASK \ + | VMX_BF_ENTRY_INT_INFO_TYPE_MASK \ + | VMX_BF_ENTRY_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_HW_XCPT) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_PF))) +/** If the VM-entry interruption information field indicates an external + * interrupt. */ +#define VMX_ENTRY_INT_INFO_IS_EXT_INT(a) (((a) & ( VMX_BF_ENTRY_INT_INFO_VALID_MASK \ + | VMX_BF_ENTRY_INT_INFO_TYPE_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_EXT_INT))) +/** If the VM-entry interruption information field indicates an NMI. */ +#define VMX_ENTRY_INT_INFO_IS_XCPT_NMI(a) (((a) & ( VMX_BF_ENTRY_INT_INFO_VALID_MASK \ + | VMX_BF_ENTRY_INT_INFO_TYPE_MASK \ + | VMX_BF_ENTRY_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_TYPE, VMX_ENTRY_INT_INFO_TYPE_NMI) \ + | RT_BF_MAKE(VMX_BF_ENTRY_INT_INFO_VECTOR, X86_XCPT_NMI))) + +/** Bit fields for VM-entry interruption information. */ +/** The VM-entry interruption vector. */ +#define VMX_BF_ENTRY_INT_INFO_VECTOR_SHIFT 0 +#define VMX_BF_ENTRY_INT_INFO_VECTOR_MASK UINT32_C(0x000000ff) +/** The VM-entry interruption type (see VMX_ENTRY_INT_INFO_TYPE_XXX). */ +#define VMX_BF_ENTRY_INT_INFO_TYPE_SHIFT 8 +#define VMX_BF_ENTRY_INT_INFO_TYPE_MASK UINT32_C(0x00000700) +/** Whether this event has an error code. */ +#define VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID_SHIFT 11 +#define VMX_BF_ENTRY_INT_INFO_ERR_CODE_VALID_MASK UINT32_C(0x00000800) +/** Bits 12:30 are reserved and MBZ. */ +#define VMX_BF_ENTRY_INT_INFO_RSVD_12_30_SHIFT 12 +#define VMX_BF_ENTRY_INT_INFO_RSVD_12_30_MASK UINT32_C(0x7ffff000) +/** Whether this VM-entry interruption info is valid. */ +#define VMX_BF_ENTRY_INT_INFO_VALID_SHIFT 31 +#define VMX_BF_ENTRY_INT_INFO_VALID_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_ENTRY_INT_INFO_, UINT32_C(0), UINT32_MAX, + (VECTOR, TYPE, ERR_CODE_VALID, RSVD_12_30, VALID)); +/** @} */ + + +/** @name VM-entry exception error code. + * @{ */ +/** Error code valid mask. */ +/** @todo r=ramshankar: Intel spec. 26.2.1.3 "VM-Entry Control Fields" states that + * bits 31:15 MBZ. However, Intel spec. 6.13 "Error Code" states "To keep the + * stack aligned for doubleword pushes, the upper half of the error code is + * reserved" which implies bits 31:16 MBZ (and not 31:15) which is what we + * use below. */ +#define VMX_ENTRY_INT_XCPT_ERR_CODE_VALID_MASK UINT32_C(0xffff) +/** @} */ + +/** @name VM-entry interruption information types. + * @{ + */ +#define VMX_ENTRY_INT_INFO_TYPE_EXT_INT 0 +#define VMX_ENTRY_INT_INFO_TYPE_RSVD 1 +#define VMX_ENTRY_INT_INFO_TYPE_NMI 2 +#define VMX_ENTRY_INT_INFO_TYPE_HW_XCPT 3 +#define VMX_ENTRY_INT_INFO_TYPE_SW_INT 4 +#define VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT 5 +#define VMX_ENTRY_INT_INFO_TYPE_SW_XCPT 6 +#define VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT 7 +/** @} */ + + +/** @name VM-entry interruption information vector types for + * VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT. + * @{ */ +#define VMX_ENTRY_INT_INFO_VECTOR_MTF 0 +/** @} */ + + +/** @name VM-exit interruption information. + * @{ + */ +#define VMX_EXIT_INT_INFO_VECTOR(a) ((a) & 0xff) +#define VMX_EXIT_INT_INFO_TYPE_SHIFT 8 +#define VMX_EXIT_INT_INFO_TYPE(a) (((a) >> 8) & 7) +#define VMX_EXIT_INT_INFO_ERROR_CODE_VALID RT_BIT(11) +#define VMX_EXIT_INT_INFO_IS_ERROR_CODE_VALID(a) (((a) >> 11) & 1) +#define VMX_EXIT_INT_INFO_NMI_UNBLOCK_IRET 12 +#define VMX_EXIT_INT_INFO_IS_NMI_UNBLOCK_IRET(a) (((a) >> 12) & 1) +#define VMX_EXIT_INT_INFO_VALID RT_BIT(31) +#define VMX_EXIT_INT_INFO_IS_VALID(a) (((a) >> 31) & 1) + +/** If the VM-exit interruption information field indicates an page-fault. */ +#define VMX_EXIT_INT_INFO_IS_XCPT_PF(a) (((a) & ( VMX_BF_EXIT_INT_INFO_VALID_MASK \ + | VMX_BF_EXIT_INT_INFO_TYPE_MASK \ + | VMX_BF_EXIT_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, X86_XCPT_PF))) +/** If the VM-exit interruption information field indicates an double-fault. */ +#define VMX_EXIT_INT_INFO_IS_XCPT_DF(a) (((a) & ( VMX_BF_EXIT_INT_INFO_VALID_MASK \ + | VMX_BF_EXIT_INT_INFO_TYPE_MASK \ + | VMX_BF_EXIT_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_HW_XCPT) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, X86_XCPT_DF))) +/** If the VM-exit interruption information field indicates an NMI. */ +#define VMX_EXIT_INT_INFO_IS_XCPT_NMI(a) (((a) & ( VMX_BF_EXIT_INT_INFO_VALID_MASK \ + | VMX_BF_EXIT_INT_INFO_TYPE_MASK \ + | VMX_BF_EXIT_INT_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_TYPE, VMX_EXIT_INT_INFO_TYPE_NMI) \ + | RT_BF_MAKE(VMX_BF_EXIT_INT_INFO_VECTOR, X86_XCPT_NMI))) + + +/** Bit fields for VM-exit interruption infomration. */ +/** The VM-exit interruption vector. */ +#define VMX_BF_EXIT_INT_INFO_VECTOR_SHIFT 0 +#define VMX_BF_EXIT_INT_INFO_VECTOR_MASK UINT32_C(0x000000ff) +/** The VM-exit interruption type (see VMX_EXIT_INT_INFO_TYPE_XXX). */ +#define VMX_BF_EXIT_INT_INFO_TYPE_SHIFT 8 +#define VMX_BF_EXIT_INT_INFO_TYPE_MASK UINT32_C(0x00000700) +/** Whether this event has an error code. */ +#define VMX_BF_EXIT_INT_INFO_ERR_CODE_VALID_SHIFT 11 +#define VMX_BF_EXIT_INT_INFO_ERR_CODE_VALID_MASK UINT32_C(0x00000800) +/** Whether NMI-unblocking due to IRET is active. */ +#define VMX_BF_EXIT_INT_INFO_NMI_UNBLOCK_IRET_SHIFT 12 +#define VMX_BF_EXIT_INT_INFO_NMI_UNBLOCK_IRET_MASK UINT32_C(0x00001000) +/** Bits 13:30 is reserved (MBZ). */ +#define VMX_BF_EXIT_INT_INFO_RSVD_13_30_SHIFT 13 +#define VMX_BF_EXIT_INT_INFO_RSVD_13_30_MASK UINT32_C(0x7fffe000) +/** Whether this VM-exit interruption info is valid. */ +#define VMX_BF_EXIT_INT_INFO_VALID_SHIFT 31 +#define VMX_BF_EXIT_INT_INFO_VALID_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_INT_INFO_, UINT32_C(0), UINT32_MAX, + (VECTOR, TYPE, ERR_CODE_VALID, NMI_UNBLOCK_IRET, RSVD_13_30, VALID)); +/** @} */ + + +/** @name VM-exit interruption information types. + * @{ + */ +#define VMX_EXIT_INT_INFO_TYPE_EXT_INT 0 +#define VMX_EXIT_INT_INFO_TYPE_NMI 2 +#define VMX_EXIT_INT_INFO_TYPE_HW_XCPT 3 +#define VMX_EXIT_INT_INFO_TYPE_SW_INT 4 +#define VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT 5 +#define VMX_EXIT_INT_INFO_TYPE_SW_XCPT 6 +#define VMX_EXIT_INT_INFO_TYPE_UNUSED 7 +/** @} */ + + +/** @name VM-exit instruction identity. + * + * These are found in VM-exit instruction information fields for certain + * instructions. + * @{ */ +typedef uint32_t VMXINSTRID; +/** Whether the instruction ID field is valid. */ +#define VMXINSTRID_VALID RT_BIT_32(31) +/** Whether the instruction's primary operand in the Mod R/M byte (bits 0:3) is a + * read or write. */ +#define VMXINSTRID_MODRM_PRIMARY_OP_W RT_BIT_32(30) +/** Gets whether the instruction ID is valid or not. */ +#define VMXINSTRID_IS_VALID(a) (((a) >> 31) & 1) +#define VMXINSTRID_IS_MODRM_PRIMARY_OP_W(a) (((a) >> 30) & 1) +/** Gets the instruction ID. */ +#define VMXINSTRID_GET_ID(a) ((a) & ~(VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W)) +/** No instruction ID info. */ +#define VMXINSTRID_NONE 0 + +/** The OR'd rvalues are from the VT-x spec (valid bit is VBox specific): */ +#define VMXINSTRID_SGDT (0x0 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_SIDT (0x1 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_LGDT (0x2 | VMXINSTRID_VALID) +#define VMXINSTRID_LIDT (0x3 | VMXINSTRID_VALID) + +#define VMXINSTRID_SLDT (0x0 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_STR (0x1 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_LLDT (0x2 | VMXINSTRID_VALID) +#define VMXINSTRID_LTR (0x3 | VMXINSTRID_VALID) + +/** The following IDs are used internally (some for logging, others for conveying + * the ModR/M primary operand write bit): */ +#define VMXINSTRID_VMLAUNCH (0x10 | VMXINSTRID_VALID) +#define VMXINSTRID_VMRESUME (0x11 | VMXINSTRID_VALID) +#define VMXINSTRID_VMREAD (0x12 | VMXINSTRID_VALID) +#define VMXINSTRID_VMWRITE (0x13 | VMXINSTRID_VALID | VMXINSTRID_MODRM_PRIMARY_OP_W) +#define VMXINSTRID_IO_IN (0x14 | VMXINSTRID_VALID) +#define VMXINSTRID_IO_INS (0x15 | VMXINSTRID_VALID) +#define VMXINSTRID_IO_OUT (0x16 | VMXINSTRID_VALID) +#define VMXINSTRID_IO_OUTS (0x17 | VMXINSTRID_VALID) +#define VMXINSTRID_MOV_TO_DRX (0x18 | VMXINSTRID_VALID) +#define VMXINSTRID_MOV_FROM_DRX (0x19 | VMXINSTRID_VALID) +/** @} */ + + +/** @name IDT-vectoring information. + * @{ + */ +#define VMX_IDT_VECTORING_INFO_VECTOR(a) ((a) & 0xff) +#define VMX_IDT_VECTORING_INFO_TYPE_SHIFT 8 +#define VMX_IDT_VECTORING_INFO_TYPE(a) (((a) >> 8) & 7) +#define VMX_IDT_VECTORING_INFO_ERROR_CODE_VALID RT_BIT(11) +#define VMX_IDT_VECTORING_INFO_IS_ERROR_CODE_VALID(a) (((a) >> 11) & 1) +#define VMX_IDT_VECTORING_INFO_IS_VALID(a) (((a) >> 31) & 1) +#define VMX_IDT_VECTORING_INFO_VALID RT_BIT(31) + +/** Construct an IDT-vectoring information field from an VM-entry interruption + * information field (same except that bit 12 is reserved). */ +#define VMX_IDT_VECTORING_INFO_FROM_ENTRY_INT_INFO(a) ((a) & ~RT_BIT(12)) +/** If the IDT-vectoring information field indicates a page-fault. */ +#define VMX_IDT_VECTORING_INFO_IS_XCPT_PF(a) (((a) & ( VMX_BF_IDT_VECTORING_INFO_VALID_MASK \ + | VMX_BF_IDT_VECTORING_INFO_TYPE_MASK \ + | VMX_BF_IDT_VECTORING_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_TYPE, VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT) \ + | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VECTOR, X86_XCPT_PF))) +/** If the IDT-vectoring information field indicates an NMI. */ +#define VMX_IDT_VECTORING_INFO_IS_XCPT_NMI(a) (((a) & ( VMX_BF_IDT_VECTORING_INFO_VALID_MASK \ + | VMX_BF_IDT_VECTORING_INFO_TYPE_MASK \ + | VMX_BF_IDT_VECTORING_INFO_VECTOR_MASK)) \ + == ( RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VALID, 1) \ + | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_TYPE, VMX_IDT_VECTORING_INFO_TYPE_NMI) \ + | RT_BF_MAKE(VMX_BF_IDT_VECTORING_INFO_VECTOR, X86_XCPT_NMI))) + + +/** Bit fields for IDT-vectoring information. */ +/** The IDT-vectoring info vector. */ +#define VMX_BF_IDT_VECTORING_INFO_VECTOR_SHIFT 0 +#define VMX_BF_IDT_VECTORING_INFO_VECTOR_MASK UINT32_C(0x000000ff) +/** The IDT-vectoring info type (see VMX_IDT_VECTORING_INFO_TYPE_XXX). */ +#define VMX_BF_IDT_VECTORING_INFO_TYPE_SHIFT 8 +#define VMX_BF_IDT_VECTORING_INFO_TYPE_MASK UINT32_C(0x00000700) +/** Whether the event has an error code. */ +#define VMX_BF_IDT_VECTORING_INFO_ERR_CODE_VALID_SHIFT 11 +#define VMX_BF_IDT_VECTORING_INFO_ERR_CODE_VALID_MASK UINT32_C(0x00000800) +/** Bit 12 is undefined. */ +#define VMX_BF_IDT_VECTORING_INFO_UNDEF_12_SHIFT 12 +#define VMX_BF_IDT_VECTORING_INFO_UNDEF_12_MASK UINT32_C(0x00001000) +/** Bits 13:30 is reserved (MBZ). */ +#define VMX_BF_IDT_VECTORING_INFO_RSVD_13_30_SHIFT 13 +#define VMX_BF_IDT_VECTORING_INFO_RSVD_13_30_MASK UINT32_C(0x7fffe000) +/** Whether this IDT-vectoring info is valid. */ +#define VMX_BF_IDT_VECTORING_INFO_VALID_SHIFT 31 +#define VMX_BF_IDT_VECTORING_INFO_VALID_MASK UINT32_C(0x80000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_IDT_VECTORING_INFO_, UINT32_C(0), UINT32_MAX, + (VECTOR, TYPE, ERR_CODE_VALID, UNDEF_12, RSVD_13_30, VALID)); +/** @} */ + + +/** @name IDT-vectoring information vector types. + * @{ + */ +#define VMX_IDT_VECTORING_INFO_TYPE_EXT_INT 0 +#define VMX_IDT_VECTORING_INFO_TYPE_NMI 2 +#define VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT 3 +#define VMX_IDT_VECTORING_INFO_TYPE_SW_INT 4 +#define VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT 5 +#define VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT 6 +#define VMX_IDT_VECTORING_INFO_TYPE_UNUSED 7 +/** @} */ + + +/** @name TPR threshold. + * @{ */ +/** Mask of the TPR threshold field (bits 31:4 MBZ). */ +#define VMX_TPR_THRESHOLD_MASK UINT32_C(0xf) + +/** Bit fields for TPR threshold. */ +#define VMX_BF_TPR_THRESHOLD_TPR_SHIFT 0 +#define VMX_BF_TPR_THRESHOLD_TPR_MASK UINT32_C(0x0000000f) +#define VMX_BF_TPR_THRESHOLD_RSVD_4_31_SHIFT 4 +#define VMX_BF_TPR_THRESHOLD_RSVD_4_31_MASK UINT32_C(0xfffffff0) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_TPR_THRESHOLD_, UINT32_C(0), UINT32_MAX, + (TPR, RSVD_4_31)); +/** @} */ + + +/** @name Guest-activity states. + * @{ + */ +/** The logical processor is active. */ +#define VMX_VMCS_GUEST_ACTIVITY_ACTIVE 0x0 +/** The logical processor is inactive, because it executed a HLT instruction. */ +#define VMX_VMCS_GUEST_ACTIVITY_HLT 0x1 +/** The logical processor is inactive, because of a triple fault or other serious error. */ +#define VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN 0x2 +/** The logical processor is inactive, because it's waiting for a startup-IPI */ +#define VMX_VMCS_GUEST_ACTIVITY_SIPI_WAIT 0x3 +/** @} */ + + +/** @name Guest-interruptibility states. + * @{ + */ +#define VMX_VMCS_GUEST_INT_STATE_BLOCK_STI RT_BIT(0) +#define VMX_VMCS_GUEST_INT_STATE_BLOCK_MOVSS RT_BIT(1) +#define VMX_VMCS_GUEST_INT_STATE_BLOCK_SMI RT_BIT(2) +#define VMX_VMCS_GUEST_INT_STATE_BLOCK_NMI RT_BIT(3) +#define VMX_VMCS_GUEST_INT_STATE_ENCLAVE RT_BIT(4) + +/** Mask of the guest-interruptibility state field (bits 31:5 MBZ). */ +#define VMX_VMCS_GUEST_INT_STATE_MASK UINT32_C(0x1f) +/** @} */ + + +/** @name Exit qualification for debug exceptions. + * @{ + */ +/** Hardware breakpoint 0 was met. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP0 RT_BIT_64(0) +/** Hardware breakpoint 1 was met. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP1 RT_BIT_64(1) +/** Hardware breakpoint 2 was met. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP2 RT_BIT_64(2) +/** Hardware breakpoint 3 was met. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP3 RT_BIT_64(3) +/** Debug register access detected. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BD RT_BIT_64(13) +/** A debug exception would have been triggered by single-step execution mode. */ +#define VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BS RT_BIT_64(14) +/** Mask of all valid bits. */ +#define VMX_VMCS_EXIT_QUAL_VALID_MASK ( VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP0 \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP1 \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP2 \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BP3 \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BD \ + | VMX_VMCS_EXIT_QUAL_DEBUG_XCPT_BS) + +/** Bit fields for Exit qualifications due to debug exceptions. */ +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP0_SHIFT 0 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP0_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP1_SHIFT 1 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP1_MASK UINT64_C(0x0000000000000002) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP2_SHIFT 2 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP2_MASK UINT64_C(0x0000000000000004) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP3_SHIFT 3 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BP3_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_RSVD_4_12_SHIFT 4 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_RSVD_4_12_MASK UINT64_C(0x0000000000001ff0) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BD_SHIFT 13 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BD_MASK UINT64_C(0x0000000000002000) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BS_SHIFT 14 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_BS_MASK UINT64_C(0x0000000000004000) +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_RSVD_15_63_SHIFT 15 +#define VMX_BF_EXIT_QUAL_DEBUG_XCPT_RSVD_15_63_MASK UINT64_C(0xffffffffffff8000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_DEBUG_XCPT_, UINT64_C(0), UINT64_MAX, + (BP0, BP1, BP2, BP3, RSVD_4_12, BD, BS, RSVD_15_63)); +/** @} */ + +/** @name Exit qualification for Mov DRx. + * @{ + */ +/** 0-2: Debug register number */ +#define VMX_EXIT_QUAL_DRX_REGISTER(a) ((a) & 7) +/** 3: Reserved; cleared to 0. */ +#define VMX_EXIT_QUAL_DRX_RES1(a) (((a) >> 3) & 1) +/** 4: Direction of move (0 = write, 1 = read) */ +#define VMX_EXIT_QUAL_DRX_DIRECTION(a) (((a) >> 4) & 1) +/** 5-7: Reserved; cleared to 0. */ +#define VMX_EXIT_QUAL_DRX_RES2(a) (((a) >> 5) & 7) +/** 8-11: General purpose register number. */ +#define VMX_EXIT_QUAL_DRX_GENREG(a) (((a) >> 8) & 0xf) + +/** Bit fields for Exit qualification due to Mov DRx. */ +#define VMX_BF_EXIT_QUAL_DRX_REGISTER_SHIFT 0 +#define VMX_BF_EXIT_QUAL_DRX_REGISTER_MASK UINT64_C(0x0000000000000007) +#define VMX_BF_EXIT_QUAL_DRX_RSVD_1_SHIFT 3 +#define VMX_BF_EXIT_QUAL_DRX_RSVD_1_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_EXIT_QUAL_DRX_DIRECTION_SHIFT 4 +#define VMX_BF_EXIT_QUAL_DRX_DIRECTION_MASK UINT64_C(0x0000000000000010) +#define VMX_BF_EXIT_QUAL_DRX_RSVD_5_7_SHIFT 5 +#define VMX_BF_EXIT_QUAL_DRX_RSVD_5_7_MASK UINT64_C(0x00000000000000e0) +#define VMX_BF_EXIT_QUAL_DRX_GENREG_SHIFT 8 +#define VMX_BF_EXIT_QUAL_DRX_GENREG_MASK UINT64_C(0x0000000000000f00) +#define VMX_BF_EXIT_QUAL_DRX_RSVD_12_63_SHIFT 12 +#define VMX_BF_EXIT_QUAL_DRX_RSVD_12_63_MASK UINT64_C(0xfffffffffffff000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_DRX_, UINT64_C(0), UINT64_MAX, + (REGISTER, RSVD_1, DIRECTION, RSVD_5_7, GENREG, RSVD_12_63)); +/** @} */ + + +/** @name Exit qualification for debug exceptions types. + * @{ + */ +#define VMX_EXIT_QUAL_DRX_DIRECTION_WRITE 0 +#define VMX_EXIT_QUAL_DRX_DIRECTION_READ 1 +/** @} */ + + +/** @name Exit qualification for control-register accesses. + * @{ + */ +/** 0-3: Control register number (0 for CLTS & LMSW) */ +#define VMX_EXIT_QUAL_CRX_REGISTER(a) ((a) & 0xf) +/** 4-5: Access type. */ +#define VMX_EXIT_QUAL_CRX_ACCESS(a) (((a) >> 4) & 3) +/** 6: LMSW operand type memory (1 for memory, 0 for register). */ +#define VMX_EXIT_QUAL_CRX_LMSW_OP_MEM(a) (((a) >> 6) & 1) +/** 7: Reserved; cleared to 0. */ +#define VMX_EXIT_QUAL_CRX_RES1(a) (((a) >> 7) & 1) +/** 8-11: General purpose register number (0 for CLTS & LMSW). */ +#define VMX_EXIT_QUAL_CRX_GENREG(a) (((a) >> 8) & 0xf) +/** 12-15: Reserved; cleared to 0. */ +#define VMX_EXIT_QUAL_CRX_RES2(a) (((a) >> 12) & 0xf) +/** 16-31: LMSW source data (else 0). */ +#define VMX_EXIT_QUAL_CRX_LMSW_DATA(a) (((a) >> 16) & 0xffff) + +/** Bit fields for Exit qualification for control-register accesses. */ +#define VMX_BF_EXIT_QUAL_CRX_REGISTER_SHIFT 0 +#define VMX_BF_EXIT_QUAL_CRX_REGISTER_MASK UINT64_C(0x000000000000000f) +#define VMX_BF_EXIT_QUAL_CRX_ACCESS_SHIFT 4 +#define VMX_BF_EXIT_QUAL_CRX_ACCESS_MASK UINT64_C(0x0000000000000030) +#define VMX_BF_EXIT_QUAL_CRX_LMSW_OP_SHIFT 6 +#define VMX_BF_EXIT_QUAL_CRX_LMSW_OP_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EXIT_QUAL_CRX_RSVD_7_SHIFT 7 +#define VMX_BF_EXIT_QUAL_CRX_RSVD_7_MASK UINT64_C(0x0000000000000080) +#define VMX_BF_EXIT_QUAL_CRX_GENREG_SHIFT 8 +#define VMX_BF_EXIT_QUAL_CRX_GENREG_MASK UINT64_C(0x0000000000000f00) +#define VMX_BF_EXIT_QUAL_CRX_RSVD_12_15_SHIFT 12 +#define VMX_BF_EXIT_QUAL_CRX_RSVD_12_15_MASK UINT64_C(0x000000000000f000) +#define VMX_BF_EXIT_QUAL_CRX_LMSW_DATA_SHIFT 16 +#define VMX_BF_EXIT_QUAL_CRX_LMSW_DATA_MASK UINT64_C(0x00000000ffff0000) +#define VMX_BF_EXIT_QUAL_CRX_RSVD_32_63_SHIFT 32 +#define VMX_BF_EXIT_QUAL_CRX_RSVD_32_63_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_CRX_, UINT64_C(0), UINT64_MAX, + (REGISTER, ACCESS, LMSW_OP, RSVD_7, GENREG, RSVD_12_15, LMSW_DATA, RSVD_32_63)); +/** @} */ + + +/** @name Exit qualification for control-register access types. + * @{ + */ +#define VMX_EXIT_QUAL_CRX_ACCESS_WRITE 0 +#define VMX_EXIT_QUAL_CRX_ACCESS_READ 1 +#define VMX_EXIT_QUAL_CRX_ACCESS_CLTS 2 +#define VMX_EXIT_QUAL_CRX_ACCESS_LMSW 3 +/** @} */ + + +/** @name Exit qualification for task switch. + * @{ + */ +#define VMX_EXIT_QUAL_TASK_SWITCH_SELECTOR(a) ((a) & 0xffff) +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE(a) (((a) >> 30) & 0x3) +/** Task switch caused by a call instruction. */ +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE_CALL 0 +/** Task switch caused by an iret instruction. */ +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IRET 1 +/** Task switch caused by a jmp instruction. */ +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE_JMP 2 +/** Task switch caused by an interrupt gate. */ +#define VMX_EXIT_QUAL_TASK_SWITCH_TYPE_IDT 3 + +/** Bit fields for Exit qualification for task switches. */ +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_NEW_TSS_SHIFT 0 +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_NEW_TSS_MASK UINT64_C(0x000000000000ffff) +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_16_29_SHIFT 16 +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_16_29_MASK UINT64_C(0x000000003fff0000) +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_SOURCE_SHIFT 30 +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_SOURCE_MASK UINT64_C(0x00000000c0000000) +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_32_63_SHIFT 32 +#define VMX_BF_EXIT_QUAL_TASK_SWITCH_RSVD_32_63_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_TASK_SWITCH_, UINT64_C(0), UINT64_MAX, + (NEW_TSS, RSVD_16_29, SOURCE, RSVD_32_63)); +/** @} */ + + +/** @name Exit qualification for EPT violations. + * @{ + */ +/** Set if acess causing the violation was a data read. */ +#define VMX_EXIT_QUAL_EPT_ACCESS_READ RT_BIT_64(0) +/** Set if acess causing the violation was a data write. */ +#define VMX_EXIT_QUAL_EPT_ACCESS_WRITE RT_BIT_64(1) +/** Set if the violation was caused by an instruction fetch. */ +#define VMX_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH RT_BIT_64(2) +/** AND of the read bit of all EPT structures. */ +#define VMX_EXIT_QUAL_EPT_ENTRY_READ RT_BIT_64(3) +/** AND of the write bit of all EPT structures. */ +#define VMX_EXIT_QUAL_EPT_ENTRY_WRITE RT_BIT_64(4) +/** AND of the execute bit of all EPT structures. */ +#define VMX_EXIT_QUAL_EPT_ENTRY_EXECUTE RT_BIT_64(5) +/** And of the execute bit of all EPT structures for user-mode addresses + * (requires mode-based execute control). */ +#define VMX_EXIT_QUAL_EPT_ENTRY_EXECUTE_USER RT_BIT_64(6) +/** Set if the guest linear address field is valid. */ +#define VMX_EXIT_QUAL_EPT_LINEAR_ADDR_VALID RT_BIT_64(7) +/** If bit 7 is one: (reserved otherwise) + * 1 - violation due to physical address access. + * 0 - violation caused by page walk or access/dirty bit updates. + */ +#define VMX_EXIT_QUAL_EPT_LINEAR_TO_PHYS_ADDR RT_BIT_64(8) +/** If bit 7, 8 and advanced VM-exit info. for EPT is one: (reserved otherwise) + * 1 - linear address is user-mode address. + * 0 - linear address is supervisor-mode address. + */ +#define VMX_EXIT_QUAL_EPT_LINEAR_ADDR_USER RT_BIT_64(9) +/** If bit 7, 8 and advanced VM-exit info. for EPT is one: (reserved otherwise) + * 1 - linear address translates to read-only page. + * 0 - linear address translates to read-write page. + */ +#define VMX_EXIT_QUAL_EPT_LINEAR_ADDR_RO RT_BIT_64(10) +/** If bit 7, 8 and advanced VM-exit info. for EPT is one: (reserved otherwise) + * 1 - linear address translates to executable-disabled page. + * 0 - linear address translates to executable page. + */ +#define VMX_EXIT_QUAL_EPT_LINEAR_ADDR_XD RT_BIT_64(11) +/** NMI unblocking due to IRET. */ +#define VMX_EXIT_QUAL_EPT_NMI_UNBLOCK_IRET RT_BIT_64(12) +/** Set if acess causing the violation was a shadow-stack access. */ +#define VMX_EXIT_QUAL_EPT_ACCESS_SHW_STACK RT_BIT_64(13) +/** If supervisor-shadow stack is enabled: (reserved otherwise) + * 1 - supervisor shadow-stack access allowed. + * 0 - supervisor shadow-stack access disallowed. + */ +#define VMX_EXIT_QUAL_EPT_ENTRY_SHW_STACK_SUPER RT_BIT_64(14) +/** Set if access is related to trace output by Intel PT (reserved otherwise). */ +#define VMX_EXIT_QUAL_EPT_ACCESS_PT_TRACE RT_BIT_64(16) + +/** Checks whether NMI unblocking due to IRET. */ +#define VMX_EXIT_QUAL_EPT_IS_NMI_UNBLOCK_IRET(a) (((a) >> 12) & 1) + +/** Bit fields for Exit qualification for EPT violations. */ +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_READ_SHIFT 0 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_READ_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_WRITE_SHIFT 1 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_WRITE_MASK UINT64_C(0x0000000000000002) +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH_SHIFT 2 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_INSTR_FETCH_MASK UINT64_C(0x0000000000000004) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_READ_SHIFT 3 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_READ_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_WRITE_SHIFT 4 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_WRITE_MASK UINT64_C(0x0000000000000010) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_EXECUTE_SHIFT 5 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_EXECUTE_MASK UINT64_C(0x0000000000000020) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_EXECUTE_USER_SHIFT 6 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_EXECUTE_USER_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_VALID_SHIFT 7 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_VALID_MASK UINT64_C(0x0000000000000080) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_TO_PHYS_ADDR_SHIFT 8 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_TO_PHYS_ADDR_MASK UINT64_C(0x0000000000000100) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_USER_SHIFT 9 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_USER_MASK UINT64_C(0x0000000000000200) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_RO_SHIFT 10 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_RO_MASK UINT64_C(0x0000000000000400) +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_XD_SHIFT 11 +#define VMX_BF_EXIT_QUAL_EPT_LINEAR_ADDR_XD_MASK UINT64_C(0x0000000000000800) +#define VMX_BF_EXIT_QUAL_EPT_NMI_UNBLOCK_IRET_SHIFT 12 +#define VMX_BF_EXIT_QUAL_EPT_NMI_UNBLOCK_IRET_MASK UINT64_C(0x0000000000001000) +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_SHW_STACK_SHIFT 13 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_SHW_STACK_MASK UINT64_C(0x0000000000002000) +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_SHW_STACK_SUPER_SHIFT 14 +#define VMX_BF_EXIT_QUAL_EPT_ENTRY_SHW_STACK_SUPER_MASK UINT64_C(0x0000000000004000) +#define VMX_BF_EXIT_QUAL_EPT_RSVD_15_SHIFT 15 +#define VMX_BF_EXIT_QUAL_EPT_RSVD_15_MASK UINT64_C(0x0000000000008000) +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_PT_TRACE_SHIFT 16 +#define VMX_BF_EXIT_QUAL_EPT_ACCESS_PT_TRACE_MASK UINT64_C(0x0000000000010000) +#define VMX_BF_EXIT_QUAL_EPT_RSVD_17_63_SHIFT 17 +#define VMX_BF_EXIT_QUAL_EPT_RSVD_17_63_MASK UINT64_C(0xfffffffffffe0000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_EPT_, UINT64_C(0), UINT64_MAX, + (ACCESS_READ, ACCESS_WRITE, ACCESS_INSTR_FETCH, ENTRY_READ, ENTRY_WRITE, ENTRY_EXECUTE, + ENTRY_EXECUTE_USER, LINEAR_ADDR_VALID, LINEAR_TO_PHYS_ADDR, LINEAR_ADDR_USER, LINEAR_ADDR_RO, + LINEAR_ADDR_XD, NMI_UNBLOCK_IRET, ACCESS_SHW_STACK, ENTRY_SHW_STACK_SUPER, RSVD_15, + ACCESS_PT_TRACE, RSVD_17_63)); +/** @} */ + + +/** @name Exit qualification for I/O instructions. + * @{ + */ +/** 0-2: IO operation size 0(=1 byte), 1(=2 bytes) and 3(=4 bytes). */ +#define VMX_EXIT_QUAL_IO_SIZE(a) ((a) & 7) +/** 3: IO operation direction. */ +#define VMX_EXIT_QUAL_IO_DIRECTION(a) (((a) >> 3) & 1) +/** 4: String IO operation (INS / OUTS). */ +#define VMX_EXIT_QUAL_IO_IS_STRING(a) (((a) >> 4) & 1) +/** 5: Repeated IO operation. */ +#define VMX_EXIT_QUAL_IO_IS_REP(a) (((a) >> 5) & 1) +/** 6: Operand encoding. */ +#define VMX_EXIT_QUAL_IO_ENCODING(a) (((a) >> 6) & 1) +/** 16-31: IO Port (0-0xffff). */ +#define VMX_EXIT_QUAL_IO_PORT(a) (((a) >> 16) & 0xffff) + +/** Bit fields for Exit qualification for I/O instructions. */ +#define VMX_BF_EXIT_QUAL_IO_WIDTH_SHIFT 0 +#define VMX_BF_EXIT_QUAL_IO_WIDTH_MASK UINT64_C(0x0000000000000007) +#define VMX_BF_EXIT_QUAL_IO_DIRECTION_SHIFT 3 +#define VMX_BF_EXIT_QUAL_IO_DIRECTION_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_EXIT_QUAL_IO_IS_STRING_SHIFT 4 +#define VMX_BF_EXIT_QUAL_IO_IS_STRING_MASK UINT64_C(0x0000000000000010) +#define VMX_BF_EXIT_QUAL_IO_IS_REP_SHIFT 5 +#define VMX_BF_EXIT_QUAL_IO_IS_REP_MASK UINT64_C(0x0000000000000020) +#define VMX_BF_EXIT_QUAL_IO_ENCODING_SHIFT 6 +#define VMX_BF_EXIT_QUAL_IO_ENCODING_MASK UINT64_C(0x0000000000000040) +#define VMX_BF_EXIT_QUAL_IO_RSVD_7_15_SHIFT 7 +#define VMX_BF_EXIT_QUAL_IO_RSVD_7_15_MASK UINT64_C(0x000000000000ff80) +#define VMX_BF_EXIT_QUAL_IO_PORT_SHIFT 16 +#define VMX_BF_EXIT_QUAL_IO_PORT_MASK UINT64_C(0x00000000ffff0000) +#define VMX_BF_EXIT_QUAL_IO_RSVD_32_63_SHIFT 32 +#define VMX_BF_EXIT_QUAL_IO_RSVD_32_63_MASK UINT64_C(0xffffffff00000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_IO_, UINT64_C(0), UINT64_MAX, + (WIDTH, DIRECTION, IS_STRING, IS_REP, ENCODING, RSVD_7_15, PORT, RSVD_32_63)); +/** @} */ + + +/** @name Exit qualification for I/O instruction types. + * @{ + */ +#define VMX_EXIT_QUAL_IO_DIRECTION_OUT 0 +#define VMX_EXIT_QUAL_IO_DIRECTION_IN 1 +/** @} */ + + +/** @name Exit qualification for I/O instruction encoding. + * @{ + */ +#define VMX_EXIT_QUAL_IO_ENCODING_DX 0 +#define VMX_EXIT_QUAL_IO_ENCODING_IMM 1 +/** @} */ + + +/** @name Exit qualification for APIC-access VM-exits from linear and + * guest-physical accesses. + * @{ + */ +/** 0-11: If the APIC-access VM-exit is due to a linear access, the offset of + * access within the APIC page. */ +#define VMX_EXIT_QUAL_APIC_ACCESS_OFFSET(a) ((a) & 0xfff) +/** 12-15: Access type. */ +#define VMX_EXIT_QUAL_APIC_ACCESS_TYPE(a) (((a) & 0xf000) >> 12) +/* Rest reserved. */ + +/** Bit fields for Exit qualification for APIC-access VM-exits. */ +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_OFFSET_SHIFT 0 +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_OFFSET_MASK UINT64_C(0x0000000000000fff) +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_TYPE_SHIFT 12 +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_TYPE_MASK UINT64_C(0x000000000000f000) +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_RSVD_16_63_SHIFT 16 +#define VMX_BF_EXIT_QUAL_APIC_ACCESS_RSVD_16_63_MASK UINT64_C(0xffffffffffff0000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_EXIT_QUAL_APIC_ACCESS_, UINT64_C(0), UINT64_MAX, + (OFFSET, TYPE, RSVD_16_63)); +/** @} */ + + +/** @name Exit qualification for linear address APIC-access types. + * @{ + */ +/** Linear access for a data read during instruction execution. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_READ 0 +/** Linear access for a data write during instruction execution. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_WRITE 1 +/** Linear access for an instruction fetch. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_INSTR_FETCH 2 +/** Linear read/write access during event delivery. */ +#define VMX_APIC_ACCESS_TYPE_LINEAR_EVENT_DELIVERY 3 +/** Physical read/write access during event delivery. */ +#define VMX_APIC_ACCESS_TYPE_PHYSICAL_EVENT_DELIVERY 10 +/** Physical access for an instruction fetch or during instruction execution. */ +#define VMX_APIC_ACCESS_TYPE_PHYSICAL_INSTR 15 + +/** + * APIC-access type. + * In accordance with the VT-x spec. + */ +typedef enum +{ + VMXAPICACCESS_LINEAR_READ = VMX_APIC_ACCESS_TYPE_LINEAR_READ, + VMXAPICACCESS_LINEAR_WRITE = VMX_APIC_ACCESS_TYPE_LINEAR_WRITE, + VMXAPICACCESS_LINEAR_INSTR_FETCH = VMX_APIC_ACCESS_TYPE_LINEAR_INSTR_FETCH, + VMXAPICACCESS_LINEAR_EVENT_DELIVERY = VMX_APIC_ACCESS_TYPE_LINEAR_EVENT_DELIVERY, + VMXAPICACCESS_PHYSICAL_EVENT_DELIVERY = VMX_APIC_ACCESS_TYPE_PHYSICAL_EVENT_DELIVERY, + VMXAPICACCESS_PHYSICAL_INSTR = VMX_APIC_ACCESS_TYPE_PHYSICAL_INSTR +} VMXAPICACCESS; +AssertCompileSize(VMXAPICACCESS, 4); +/** @} */ + + +/** @name VMX_BF_XXTR_INSINFO_XXX - VMX_EXIT_XDTR_ACCESS instruction information. + * Found in VMX_VMCS32_RO_EXIT_INSTR_INFO. + * @{ + */ +/** Address calculation scaling field (powers of two). */ +#define VMX_BF_XDTR_INSINFO_SCALE_SHIFT 0 +#define VMX_BF_XDTR_INSINFO_SCALE_MASK UINT32_C(0x00000003) +/** Bits 2 thru 6 are undefined. */ +#define VMX_BF_XDTR_INSINFO_UNDEF_2_6_SHIFT 2 +#define VMX_BF_XDTR_INSINFO_UNDEF_2_6_MASK UINT32_C(0x0000007c) +/** Address size, only 0(=16), 1(=32) and 2(=64) are defined. + * @remarks anyone's guess why this is a 3 bit field... */ +#define VMX_BF_XDTR_INSINFO_ADDR_SIZE_SHIFT 7 +#define VMX_BF_XDTR_INSINFO_ADDR_SIZE_MASK UINT32_C(0x00000380) +/** Bit 10 is defined as zero. */ +#define VMX_BF_XDTR_INSINFO_ZERO_10_SHIFT 10 +#define VMX_BF_XDTR_INSINFO_ZERO_10_MASK UINT32_C(0x00000400) +/** Operand size, either (1=)32-bit or (0=)16-bit, but get this, it's undefined + * for exits from 64-bit code as the operand size there is fixed. */ +#define VMX_BF_XDTR_INSINFO_OP_SIZE_SHIFT 11 +#define VMX_BF_XDTR_INSINFO_OP_SIZE_MASK UINT32_C(0x00000800) +/** Bits 12 thru 14 are undefined. */ +#define VMX_BF_XDTR_INSINFO_UNDEF_12_14_SHIFT 12 +#define VMX_BF_XDTR_INSINFO_UNDEF_12_14_MASK UINT32_C(0x00007000) +/** Applicable segment register (X86_SREG_XXX values). */ +#define VMX_BF_XDTR_INSINFO_SREG_SHIFT 15 +#define VMX_BF_XDTR_INSINFO_SREG_MASK UINT32_C(0x00038000) +/** Index register (X86_GREG_XXX values). Undefined if HAS_INDEX_REG is clear. */ +#define VMX_BF_XDTR_INSINFO_INDEX_REG_SHIFT 18 +#define VMX_BF_XDTR_INSINFO_INDEX_REG_MASK UINT32_C(0x003c0000) +/** Is VMX_BF_XDTR_INSINFO_INDEX_REG_XXX valid (=1) or not (=0). */ +#define VMX_BF_XDTR_INSINFO_HAS_INDEX_REG_SHIFT 22 +#define VMX_BF_XDTR_INSINFO_HAS_INDEX_REG_MASK UINT32_C(0x00400000) +/** Base register (X86_GREG_XXX values). Undefined if HAS_BASE_REG is clear. */ +#define VMX_BF_XDTR_INSINFO_BASE_REG_SHIFT 23 +#define VMX_BF_XDTR_INSINFO_BASE_REG_MASK UINT32_C(0x07800000) +/** Is VMX_XDTR_INSINFO_BASE_REG_XXX valid (=1) or not (=0). */ +#define VMX_BF_XDTR_INSINFO_HAS_BASE_REG_SHIFT 27 +#define VMX_BF_XDTR_INSINFO_HAS_BASE_REG_MASK UINT32_C(0x08000000) +/** The instruction identity (VMX_XDTR_INSINFO_II_XXX values). */ +#define VMX_BF_XDTR_INSINFO_INSTR_ID_SHIFT 28 +#define VMX_BF_XDTR_INSINFO_INSTR_ID_MASK UINT32_C(0x30000000) +#define VMX_XDTR_INSINFO_II_SGDT 0 /**< Instruction ID: SGDT */ +#define VMX_XDTR_INSINFO_II_SIDT 1 /**< Instruction ID: SIDT */ +#define VMX_XDTR_INSINFO_II_LGDT 2 /**< Instruction ID: LGDT */ +#define VMX_XDTR_INSINFO_II_LIDT 3 /**< Instruction ID: LIDT */ +/** Bits 30 & 31 are undefined. */ +#define VMX_BF_XDTR_INSINFO_UNDEF_30_31_SHIFT 30 +#define VMX_BF_XDTR_INSINFO_UNDEF_30_31_MASK UINT32_C(0xc0000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_XDTR_INSINFO_, UINT32_C(0), UINT32_MAX, + (SCALE, UNDEF_2_6, ADDR_SIZE, ZERO_10, OP_SIZE, UNDEF_12_14, SREG, INDEX_REG, HAS_INDEX_REG, + BASE_REG, HAS_BASE_REG, INSTR_ID, UNDEF_30_31)); +/** @} */ + + +/** @name VMX_BF_YYTR_INSINFO_XXX - VMX_EXIT_TR_ACCESS instruction information. + * Found in VMX_VMCS32_RO_EXIT_INSTR_INFO. + * This is similar to VMX_BF_XDTR_INSINFO_XXX. + * @{ + */ +/** Address calculation scaling field (powers of two). */ +#define VMX_BF_YYTR_INSINFO_SCALE_SHIFT 0 +#define VMX_BF_YYTR_INSINFO_SCALE_MASK UINT32_C(0x00000003) +/** Bit 2 is undefined. */ +#define VMX_BF_YYTR_INSINFO_UNDEF_2_SHIFT 2 +#define VMX_BF_YYTR_INSINFO_UNDEF_2_MASK UINT32_C(0x00000004) +/** Register operand 1. Undefined if VMX_YYTR_INSINFO_HAS_REG1 is clear. */ +#define VMX_BF_YYTR_INSINFO_REG1_SHIFT 3 +#define VMX_BF_YYTR_INSINFO_REG1_MASK UINT32_C(0x00000078) +/** Address size, only 0(=16), 1(=32) and 2(=64) are defined. + * @remarks anyone's guess why this is a 3 bit field... */ +#define VMX_BF_YYTR_INSINFO_ADDR_SIZE_SHIFT 7 +#define VMX_BF_YYTR_INSINFO_ADDR_SIZE_MASK UINT32_C(0x00000380) +/** Is VMX_YYTR_INSINFO_REG1_XXX valid (=1) or not (=0). */ +#define VMX_BF_YYTR_INSINFO_HAS_REG1_SHIFT 10 +#define VMX_BF_YYTR_INSINFO_HAS_REG1_MASK UINT32_C(0x00000400) +/** Bits 11 thru 14 are undefined. */ +#define VMX_BF_YYTR_INSINFO_UNDEF_11_14_SHIFT 11 +#define VMX_BF_YYTR_INSINFO_UNDEF_11_14_MASK UINT32_C(0x00007800) +/** Applicable segment register (X86_SREG_XXX values). */ +#define VMX_BF_YYTR_INSINFO_SREG_SHIFT 15 +#define VMX_BF_YYTR_INSINFO_SREG_MASK UINT32_C(0x00038000) +/** Index register (X86_GREG_XXX values). Undefined if HAS_INDEX_REG is clear. */ +#define VMX_BF_YYTR_INSINFO_INDEX_REG_SHIFT 18 +#define VMX_BF_YYTR_INSINFO_INDEX_REG_MASK UINT32_C(0x003c0000) +/** Is VMX_YYTR_INSINFO_INDEX_REG_XXX valid (=1) or not (=0). */ +#define VMX_BF_YYTR_INSINFO_HAS_INDEX_REG_SHIFT 22 +#define VMX_BF_YYTR_INSINFO_HAS_INDEX_REG_MASK UINT32_C(0x00400000) +/** Base register (X86_GREG_XXX values). Undefined if HAS_BASE_REG is clear. */ +#define VMX_BF_YYTR_INSINFO_BASE_REG_SHIFT 23 +#define VMX_BF_YYTR_INSINFO_BASE_REG_MASK UINT32_C(0x07800000) +/** Is VMX_YYTR_INSINFO_BASE_REG_XXX valid (=1) or not (=0). */ +#define VMX_BF_YYTR_INSINFO_HAS_BASE_REG_SHIFT 27 +#define VMX_BF_YYTR_INSINFO_HAS_BASE_REG_MASK UINT32_C(0x08000000) +/** The instruction identity (VMX_YYTR_INSINFO_II_XXX values) */ +#define VMX_BF_YYTR_INSINFO_INSTR_ID_SHIFT 28 +#define VMX_BF_YYTR_INSINFO_INSTR_ID_MASK UINT32_C(0x30000000) +#define VMX_YYTR_INSINFO_II_SLDT 0 /**< Instruction ID: SLDT */ +#define VMX_YYTR_INSINFO_II_STR 1 /**< Instruction ID: STR */ +#define VMX_YYTR_INSINFO_II_LLDT 2 /**< Instruction ID: LLDT */ +#define VMX_YYTR_INSINFO_II_LTR 3 /**< Instruction ID: LTR */ +/** Bits 30 & 31 are undefined. */ +#define VMX_BF_YYTR_INSINFO_UNDEF_30_31_SHIFT 30 +#define VMX_BF_YYTR_INSINFO_UNDEF_30_31_MASK UINT32_C(0xc0000000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_YYTR_INSINFO_, UINT32_C(0), UINT32_MAX, + (SCALE, UNDEF_2, REG1, ADDR_SIZE, HAS_REG1, UNDEF_11_14, SREG, INDEX_REG, HAS_INDEX_REG, + BASE_REG, HAS_BASE_REG, INSTR_ID, UNDEF_30_31)); +/** @} */ + + +/** @name Format of Pending-Debug-Exceptions. + * Bits 4-11, 13, 15 and 17-63 are reserved. + * Similar to DR6 except bit 12 (breakpoint enabled) and bit 16 (RTM) are both + * possibly valid here but not in DR6. + * @{ + */ +/** Hardware breakpoint 0 was met. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP0 RT_BIT_64(0) +/** Hardware breakpoint 1 was met. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP1 RT_BIT_64(1) +/** Hardware breakpoint 2 was met. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP2 RT_BIT_64(2) +/** Hardware breakpoint 3 was met. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP3 RT_BIT_64(3) +/** At least one data or IO breakpoint was hit. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_EN_BP RT_BIT_64(12) +/** A debug exception would have been triggered by single-step execution mode. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS RT_BIT_64(14) +/** A debug exception occurred inside an RTM region. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_RTM RT_BIT_64(16) +/** Mask of valid bits. */ +#define VMX_VMCS_GUEST_PENDING_DEBUG_VALID_MASK ( VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP0 \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP1 \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP2 \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BP3 \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_EN_BP \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS \ + | VMX_VMCS_GUEST_PENDING_DEBUG_RTM) +#define VMX_VMCS_GUEST_PENDING_DEBUG_RTM_MASK ( VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_EN_BP \ + | VMX_VMCS_GUEST_PENDING_DEBUG_XCPT_BS \ + | VMX_VMCS_GUEST_PENDING_DEBUG_RTM) +/** Bit fields for Pending debug exceptions. */ +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP0_SHIFT 0 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP0_MASK UINT64_C(0x0000000000000001) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP1_SHIFT 1 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP1_MASK UINT64_C(0x0000000000000002) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP2_SHIFT 2 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP2_MASK UINT64_C(0x0000000000000004) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP3_SHIFT 3 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BP3_MASK UINT64_C(0x0000000000000008) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_4_11_SHIFT 4 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_4_11_MASK UINT64_C(0x0000000000000ff0) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_EN_BP_SHIFT 12 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_EN_BP_MASK UINT64_C(0x0000000000001000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_13_SHIFT 13 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_13_MASK UINT64_C(0x0000000000002000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BS_SHIFT 14 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_BS_MASK UINT64_C(0x0000000000004000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_15_SHIFT 15 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_15_MASK UINT64_C(0x0000000000008000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RTM_SHIFT 16 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RTM_MASK UINT64_C(0x0000000000010000) +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_17_63_SHIFT 17 +#define VMX_BF_VMCS_PENDING_DBG_XCPT_RSVD_17_63_MASK UINT64_C(0xfffffffffffe0000) +RT_BF_ASSERT_COMPILE_CHECKS(VMX_BF_VMCS_PENDING_DBG_XCPT_, UINT64_C(0), UINT64_MAX, + (BP0, BP1, BP2, BP3, RSVD_4_11, EN_BP, RSVD_13, BS, RSVD_15, RTM, RSVD_17_63)); +/** @} */ + + +/** + * VM-exit auxiliary information. + * + * This includes information that isn't necessarily stored in the guest-CPU + * context but provided as part of VM-exits. + */ +typedef struct +{ + /** The VM-exit reason. */ + uint32_t uReason; + /** The Exit qualification field. */ + uint64_t u64Qual; + /** The Guest-linear address field. */ + uint64_t u64GuestLinearAddr; + /** The Guest-physical address field. */ + uint64_t u64GuestPhysAddr; + /** The guest pending-debug exceptions. */ + uint64_t u64GuestPendingDbgXcpts; + /** The VM-exit instruction length. */ + uint32_t cbInstr; + /** The VM-exit instruction information. */ + VMXEXITINSTRINFO InstrInfo; + /** VM-exit interruption information. */ + uint32_t uExitIntInfo; + /** VM-exit interruption error code. */ + uint32_t uExitIntErrCode; + /** IDT-vectoring information. */ + uint32_t uIdtVectoringInfo; + /** IDT-vectoring error code. */ + uint32_t uIdtVectoringErrCode; +} VMXEXITAUX; +/** Pointer to a VMXEXITAUX struct. */ +typedef VMXEXITAUX *PVMXEXITAUX; +/** Pointer to a const VMXEXITAUX struct. */ +typedef const VMXEXITAUX *PCVMXEXITAUX; + + +/** @defgroup grp_hm_vmx_virt VMX virtualization. + * @{ + */ + +/** @name Virtual VMX MSR - Miscellaneous data. + * @{ */ +/** Number of CR3-target values supported. */ +#define VMX_V_CR3_TARGET_COUNT 4 +/** Activity states supported. */ +#define VMX_V_GUEST_ACTIVITY_STATE_MASK (VMX_VMCS_GUEST_ACTIVITY_HLT | VMX_VMCS_GUEST_ACTIVITY_SHUTDOWN) +/** VMX preemption-timer shift (Core i7-2600 taken as reference). */ +#define VMX_V_PREEMPT_TIMER_SHIFT 5 +/** Maximum number of MSRs in the auto-load/store MSR areas, (n+1) * 512. */ +#define VMX_V_AUTOMSR_COUNT_MAX 0 +/** SMM MSEG revision ID. */ +#define VMX_V_MSEG_REV_ID 0 +/** @} */ + +/** @name VMX_V_VMCS_STATE_XXX - Virtual VMCS launch state. + * @{ */ +/** VMCS launch state clear. */ +#define VMX_V_VMCS_LAUNCH_STATE_CLEAR RT_BIT(0) +/** VMCS launch state active. */ +#define VMX_V_VMCS_LAUNCH_STATE_ACTIVE RT_BIT(1) +/** VMCS launch state current. */ +#define VMX_V_VMCS_LAUNCH_STATE_CURRENT RT_BIT(2) +/** VMCS launch state launched. */ +#define VMX_V_VMCS_LAUNCH_STATE_LAUNCHED RT_BIT(3) +/** The mask of valid VMCS launch states. */ +#define VMX_V_VMCS_LAUNCH_STATE_MASK ( VMX_V_VMCS_LAUNCH_STATE_CLEAR \ + | VMX_V_VMCS_LAUNCH_STATE_ACTIVE \ + | VMX_V_VMCS_LAUNCH_STATE_CURRENT \ + | VMX_V_VMCS_LAUNCH_STATE_LAUNCHED) +/** @} */ + +/** CR0 bits set here must always be set when in VMX operation. */ +#define VMX_V_CR0_FIXED0 (X86_CR0_PE | X86_CR0_NE | X86_CR0_PG) +/** CR0 bits set here must always be set when in VMX non-root operation with + * unrestricted-guest control enabled. */ +#define VMX_V_CR0_FIXED0_UX (X86_CR0_NE) +/** CR0 bits cleared here must always be cleared when in VMX operation. */ +#define VMX_V_CR0_FIXED1 UINT32_C(0xffffffff) +/** CR4 bits set here must always be set when in VMX operation. */ +#define VMX_V_CR4_FIXED0 (X86_CR4_VMXE) + +/** Virtual VMCS revision ID. Bump this arbitarily chosen identifier if incompatible + * changes to the layout of VMXVVMCS is done. Bit 31 MBZ. */ +#define VMX_V_VMCS_REVISION_ID UINT32_C(0x40000001) +AssertCompile(!(VMX_V_VMCS_REVISION_ID & RT_BIT(31))); + +/** The size of the virtual VMCS region (we use the maximum allowed size to avoid + * complications when teleporation may be implemented). */ +#define VMX_V_VMCS_SIZE X86_PAGE_4K_SIZE +/** The size of the virtual VMCS region (in pages). */ +#define VMX_V_VMCS_PAGES 1 + +/** The size of the virtual shadow VMCS region. */ +#define VMX_V_SHADOW_VMCS_SIZE VMX_V_VMCS_SIZE +/** The size of the virtual shadow VMCS region (in pages). */ +#define VMX_V_SHADOW_VMCS_PAGES VMX_V_VMCS_PAGES + +/** The size of the Virtual-APIC page (in bytes). */ +#define VMX_V_VIRT_APIC_SIZE X86_PAGE_4K_SIZE +/** The size of the Virtual-APIC page (in pages). */ +#define VMX_V_VIRT_APIC_PAGES 1 + +/** The size of the VMREAD/VMWRITE bitmap (in bytes). */ +#define VMX_V_VMREAD_VMWRITE_BITMAP_SIZE X86_PAGE_4K_SIZE +/** The size of the VMREAD/VMWRITE-bitmap (in pages). */ +#define VMX_V_VMREAD_VMWRITE_BITMAP_PAGES 1 + +/** The size of the MSR bitmap (in bytes). */ +#define VMX_V_MSR_BITMAP_SIZE X86_PAGE_4K_SIZE +/** The size of the MSR bitmap (in pages). */ +#define VMX_V_MSR_BITMAP_PAGES 1 + +/** The size of I/O bitmap A (in bytes). */ +#define VMX_V_IO_BITMAP_A_SIZE X86_PAGE_4K_SIZE +/** The size of I/O bitmap A (in pages). */ +#define VMX_V_IO_BITMAP_A_PAGES 1 + +/** The size of I/O bitmap B (in bytes). */ +#define VMX_V_IO_BITMAP_B_SIZE X86_PAGE_4K_SIZE +/** The size of I/O bitmap B (in pages). */ +#define VMX_V_IO_BITMAP_B_PAGES 1 + +/** The size of the auto-load/store MSR area (in bytes). */ +#define VMX_V_AUTOMSR_AREA_SIZE ((512 * (VMX_V_AUTOMSR_COUNT_MAX + 1)) * sizeof(VMXAUTOMSR)) +/* Assert that the size is page aligned or adjust the VMX_V_AUTOMSR_AREA_PAGES macro below. */ +AssertCompile(RT_ALIGN_Z(VMX_V_AUTOMSR_AREA_SIZE, X86_PAGE_4K_SIZE) == VMX_V_AUTOMSR_AREA_SIZE); +/** The size of the auto-load/store MSR area (in pages). */ +#define VMX_V_AUTOMSR_AREA_PAGES ((VMX_V_AUTOMSR_AREA_SIZE) >> X86_PAGE_4K_SHIFT) + +/** The highest index value used for supported virtual VMCS field encoding. */ +#define VMX_V_VMCS_MAX_INDEX RT_BF_GET(VMX_VMCS64_CTRL_EXIT2_HIGH, VMX_BF_VMCSFIELD_INDEX) + +/** + * Virtual VM-exit information. + * + * This is a convenience structure that bundles some VM-exit information related + * fields together. + */ +typedef struct +{ + /** The VM-exit reason. */ + uint32_t uReason; + /** The VM-exit instruction length. */ + uint32_t cbInstr; + /** The VM-exit instruction information. */ + VMXEXITINSTRINFO InstrInfo; + /** The VM-exit instruction ID. */ + VMXINSTRID uInstrId; + + /** The Exit qualification field. */ + uint64_t u64Qual; + /** The Guest-linear address field. */ + uint64_t u64GuestLinearAddr; + /** The Guest-physical address field. */ + uint64_t u64GuestPhysAddr; + /** The guest pending-debug exceptions. */ + uint64_t u64GuestPendingDbgXcpts; + /** The effective guest-linear address if @a InstrInfo indicates a memory-based + * instruction VM-exit. */ + RTGCPTR GCPtrEffAddr; +} VMXVEXITINFO; +/** Pointer to the VMXVEXITINFO struct. */ +typedef VMXVEXITINFO *PVMXVEXITINFO; +/** Pointer to a const VMXVEXITINFO struct. */ +typedef const VMXVEXITINFO *PCVMXVEXITINFO; +AssertCompileMemberAlignment(VMXVEXITINFO, u64Qual, 8); + +/** Initialize a VMXVEXITINFO structure from only an exit reason. */ +#define VMXVEXITINFO_INIT_ONLY_REASON(a_uReason) \ + { (a_uReason), 0, { 0 }, VMXINSTRID_NONE, 0, 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason and instruction length (no info). */ +#define VMXVEXITINFO_INIT_WITH_INSTR_LEN(a_uReason, a_cbInstr) \ + { (a_uReason), (a_cbInstr), { 0 }, VMXINSTRID_NONE, 0, 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason and exit qualification. */ +#define VMXVEXITINFO_INIT_WITH_QUAL(a_uReason, a_uQual) \ + { (a_uReason), 0, { 0 }, VMXINSTRID_NONE, (a_uQual), 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction info and length. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO(a_uReason, a_uQual, a_uInstrInfo, a_cbInstr) \ + { (a_uReason), (a_cbInstr), { a_uInstrInfo }, VMXINSTRID_NONE, (a_uQual), 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction info and length all copied from a VMXTRANSIENT structure. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_FROM_TRANSIENT(a_pVmxTransient) \ + VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO((a_pVmxTransient)->uExitReason, \ + (a_pVmxTransient)->uExitQual, \ + (a_pVmxTransient)->ExitInstrInfo.u, \ + (a_pVmxTransient)->cbExitInstr) + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction length (no info). */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN(a_uReason, a_uQual, a_cbInstr) \ + { (a_uReason), (a_cbInstr), { 0 }, VMXINSTRID_NONE, (a_uQual), 0, 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification and + * instruction length (no info) all copied from a VMXTRANSIENT structure. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_FROM_TRANSIENT(a_pVmxTransient) \ + VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN((a_pVmxTransient)->uExitReason, \ + (a_pVmxTransient)->uExitQual, \ + (a_pVmxTransient)->cbExitInstr) + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction info, instruction length and guest linear address. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_AND_LIN_ADDR(a_uReason, a_uQual, a_uInstrInfo, \ + a_cbInstr, a_uGstLinAddr) \ + { (a_uReason), (a_cbInstr), { (a_uInstrInfo) }, VMXINSTRID_NONE, (a_uQual), (a_uGstLinAddr), 0, 0, 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction info, instruction length and guest linear address all copied + * from a VMXTRANSIENT structure. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_AND_LIN_ADDR_FROM_TRANSIENT(a_pVmxTransient) \ + VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_INFO_AND_LIN_ADDR((a_pVmxTransient)->uExitReason, \ + (a_pVmxTransient)->uExitQual, \ + (a_pVmxTransient)->ExitInstrInfo.u, \ + (a_pVmxTransient)->cbExitInstr, \ + (a_pVmxTransient)->uGuestLinearAddr) + +/** Initialize a VMXVEXITINFO structure from exit reason and pending debug + * exceptions. */ +#define VMXVEXITINFO_INIT_WITH_DBG_XCPTS(a_uReason, a_uPendingDbgXcpts) \ + { (a_uReason), 0, { 0 }, VMXINSTRID_NONE, 0, 0, 0, (a_uPendingDbgXcpts), 0 } + +/** Initialize a VMXVEXITINFO structure from exit reason and pending debug + * exceptions both copied from a VMXTRANSIENT structure. */ +#define VMXVEXITINFO_INIT_WITH_DBG_XCPTS_FROM_TRANSIENT(a_pVmxTransient) \ + VMXVEXITINFO_INIT_WITH_DBG_XCPTS((a_pVmxTransient)->uExitReason, (a_pVmxTransient)->uGuestPendingDbgXcpts) + + +/** Initialize a VMXVEXITINFO structure from exit reason, exit qualification, + * instruction length, guest linear address and guest physical address. */ +#define VMXVEXITINFO_INIT_WITH_QUAL_AND_INSTR_LEN_AND_GST_ADDRESSES(a_uReason, a_uQual, a_cbInstr, \ + a_uGstLinAddr, a_uGstPhysAddr) \ + { (a_uReason), (a_cbInstr), { 0 }, VMXINSTRID_NONE, (a_uQual), (a_uGstLinAddr), (a_uGstPhysAddr), 0, 0 } + + +/** + * Virtual VM-exit information for events. + * + * This is a convenience structure that bundles some event-based VM-exit information + * related fields together that are not included in VMXVEXITINFO. + * + * This is kept as a separate structure and not included in VMXVEXITINFO, to make it + * easier to distinguish that IEM VM-exit handlers will set one or more of the + * following fields in the virtual VMCS. Including it in the VMXVEXITINFO will not + * make it ovbious which fields may get set (or cleared). + */ +typedef struct +{ + /** VM-exit interruption information. */ + uint32_t uExitIntInfo; + /** VM-exit interruption error code. */ + uint32_t uExitIntErrCode; + /** IDT-vectoring information. */ + uint32_t uIdtVectoringInfo; + /** IDT-vectoring error code. */ + uint32_t uIdtVectoringErrCode; +} VMXVEXITEVENTINFO; +/** Pointer to the VMXVEXITEVENTINFO struct. */ +typedef VMXVEXITEVENTINFO *PVMXVEXITEVENTINFO; +/** Pointer to a const VMXVEXITEVENTINFO struct. */ +typedef const VMXVEXITEVENTINFO *PCVMXVEXITEVENTINFO; + +/** Initialize a VMXVEXITEVENTINFO. */ +#define VMXVEXITEVENTINFO_INIT(a_uExitIntInfo, a_uExitIntErrCode, a_uIdtVectoringInfo, a_uIdtVectoringErrCode) \ + { (a_uExitIntInfo), (a_uExitIntErrCode), (a_uIdtVectoringInfo), (a_uIdtVectoringErrCode) } + +/** Initialize a VMXVEXITEVENTINFO with VM-exit interruption info and VM-exit + * interruption error code. */ +#define VMXVEXITEVENTINFO_INIT_ONLY_INT(a_uExitIntInfo, a_uExitIntErrCode) \ + VMXVEXITEVENTINFO_INIT(a_uExitIntInfo, a_uExitIntErrCode, 0, 0) + +/** Initialize a VMXVEXITEVENTINFO with IDT vectoring info and IDT + * vectoring error code. */ +#define VMXVEXITEVENTINFO_INIT_ONLY_IDT(a_uIdtVectoringInfo, a_uIdtVectoringErrCode) \ + VMXVEXITEVENTINFO_INIT(0, 0, a_uIdtVectoringInfo, a_uIdtVectoringErrCode) + +/** + * Virtual VMCS. + * + * This is our custom format. Relevant fields from this VMCS will be merged into the + * actual/shadow VMCS when we execute nested-guest code using hardware-assisted + * VMX. + * + * The first 8 bytes must be in accordance with the Intel VT-x spec. + * See Intel spec. 24.2 "Format of the VMCS Region". + * + * The offset and size of the VMCS state field (@a fVmcsState) is also fixed (not by + * the Intel spec. but for our own requirements) as we use it to offset into guest + * memory. + * + * Although the guest is supposed to access the VMCS only through the execution of + * VMX instructions (VMREAD, VMWRITE etc.), since the VMCS may reside in guest + * memory (e.g, active but not current VMCS), for saved-states compatibility, and + * for teleportation purposes, any newly added fields should be added to the + * appropriate reserved sections or at the end of the structure. + * + * We always treat natural-width fields as 64-bit in our implementation since + * it's easier, allows for teleporation in the future and does not affect guest + * software. + * + * @note Any fields that are added or modified here, make sure to update the + * corresponding fields in IEM (g_aoffVmcsMap), the corresponding saved + * state structure in CPUM (g_aVmxHwvirtVmcs) and bump the SSM version. + * Also consider updating CPUMIsGuestVmxVmcsFieldValid and cpumR3InfoVmxVmcs. + */ +#pragma pack(1) +typedef struct +{ + /** @name Header. + * @{ + */ + VMXVMCSREVID u32VmcsRevId; /**< 0x000 - VMX VMCS revision identifier. */ + VMXABORT enmVmxAbort; /**< 0x004 - VMX-abort indicator. */ + uint8_t fVmcsState; /**< 0x008 - VMCS launch state, see VMX_V_VMCS_LAUNCH_STATE_XXX. */ + uint8_t au8Padding0[3]; /**< 0x009 - Reserved for future. */ + uint32_t au32Reserved0[12]; /**< 0x00c - Reserved for future. */ + /** @} */ + + /** @name Read-only fields. + * @{ */ + /** 16-bit fields. */ + uint16_t u16Reserved0[14]; /**< 0x03c - Reserved for future. */ + + /** 32-bit fields. */ + uint32_t u32RoVmInstrError; /**< 0x058 - VM-instruction error. */ + uint32_t u32RoExitReason; /**< 0x05c - VM-exit reason. */ + uint32_t u32RoExitIntInfo; /**< 0x060 - VM-exit interruption information. */ + uint32_t u32RoExitIntErrCode; /**< 0x064 - VM-exit interruption error code. */ + uint32_t u32RoIdtVectoringInfo; /**< 0x068 - IDT-vectoring information. */ + uint32_t u32RoIdtVectoringErrCode; /**< 0x06c - IDT-vectoring error code. */ + uint32_t u32RoExitInstrLen; /**< 0x070 - VM-exit instruction length. */ + uint32_t u32RoExitInstrInfo; /**< 0x074 - VM-exit instruction information. */ + uint32_t au32RoReserved2[16]; /**< 0x078 - Reserved for future. */ + + /** 64-bit fields. */ + RTUINT64U u64RoGuestPhysAddr; /**< 0x0b8 - Guest-physical address. */ + RTUINT64U au64Reserved1[8]; /**< 0x0c0 - Reserved for future. */ + + /** Natural-width fields. */ + RTUINT64U u64RoExitQual; /**< 0x100 - Exit qualification. */ + RTUINT64U u64RoIoRcx; /**< 0x108 - I/O RCX. */ + RTUINT64U u64RoIoRsi; /**< 0x110 - I/O RSI. */ + RTUINT64U u64RoIoRdi; /**< 0x118 - I/O RDI. */ + RTUINT64U u64RoIoRip; /**< 0x120 - I/O RIP. */ + RTUINT64U u64RoGuestLinearAddr; /**< 0x128 - Guest-linear address. */ + RTUINT64U au64Reserved5[16]; /**< 0x130 - Reserved for future. */ + /** @} */ + + /** @name Control fields. + * @{ */ + /** 16-bit fields. */ + uint16_t u16Vpid; /**< 0x1b0 - Virtual processor ID. */ + uint16_t u16PostIntNotifyVector; /**< 0x1b2 - Posted interrupt notify vector. */ + uint16_t u16EptpIndex; /**< 0x1b4 - EPTP index. */ + uint16_t u16HlatPrefixSize; /**< 0x1b6 - HLAT prefix size. */ + uint16_t au16Reserved0[12]; /**< 0x1b8 - Reserved for future. */ + + /** 32-bit fields. */ + uint32_t u32PinCtls; /**< 0x1d0 - Pin-based VM-execution controls. */ + uint32_t u32ProcCtls; /**< 0x1d4 - Processor-based VM-execution controls. */ + uint32_t u32XcptBitmap; /**< 0x1d8 - Exception bitmap. */ + uint32_t u32XcptPFMask; /**< 0x1dc - Page-fault exception error mask. */ + uint32_t u32XcptPFMatch; /**< 0x1e0 - Page-fault exception error match. */ + uint32_t u32Cr3TargetCount; /**< 0x1e4 - CR3-target count. */ + uint32_t u32ExitCtls; /**< 0x1e8 - VM-exit controls. */ + uint32_t u32ExitMsrStoreCount; /**< 0x1ec - VM-exit MSR store count. */ + uint32_t u32ExitMsrLoadCount; /**< 0x1f0 - VM-exit MSR load count. */ + uint32_t u32EntryCtls; /**< 0x1f4 - VM-entry controls. */ + uint32_t u32EntryMsrLoadCount; /**< 0x1f8 - VM-entry MSR load count. */ + uint32_t u32EntryIntInfo; /**< 0x1fc - VM-entry interruption information. */ + uint32_t u32EntryXcptErrCode; /**< 0x200 - VM-entry exception error code. */ + uint32_t u32EntryInstrLen; /**< 0x204 - VM-entry instruction length. */ + uint32_t u32TprThreshold; /**< 0x208 - TPR-threshold. */ + uint32_t u32ProcCtls2; /**< 0x20c - Secondary-processor based VM-execution controls. */ + uint32_t u32PleGap; /**< 0x210 - Pause-loop exiting Gap. */ + uint32_t u32PleWindow; /**< 0x214 - Pause-loop exiting Window. */ + uint32_t au32Reserved1[16]; /**< 0x218 - Reserved for future. */ + + /** 64-bit fields. */ + RTUINT64U u64AddrIoBitmapA; /**< 0x258 - I/O bitmap A address. */ + RTUINT64U u64AddrIoBitmapB; /**< 0x260 - I/O bitmap B address. */ + RTUINT64U u64AddrMsrBitmap; /**< 0x268 - MSR bitmap address. */ + RTUINT64U u64AddrExitMsrStore; /**< 0x270 - VM-exit MSR-store area address. */ + RTUINT64U u64AddrExitMsrLoad; /**< 0x278 - VM-exit MSR-load area address. */ + RTUINT64U u64AddrEntryMsrLoad; /**< 0x280 - VM-entry MSR-load area address. */ + RTUINT64U u64ExecVmcsPtr; /**< 0x288 - Executive-VMCS pointer. */ + RTUINT64U u64AddrPml; /**< 0x290 - Page-modification log address (PML). */ + RTUINT64U u64TscOffset; /**< 0x298 - TSC offset. */ + RTUINT64U u64AddrVirtApic; /**< 0x2a0 - Virtual-APIC address. */ + RTUINT64U u64AddrApicAccess; /**< 0x2a8 - APIC-access address. */ + RTUINT64U u64AddrPostedIntDesc; /**< 0x2b0 - Posted-interrupt descriptor address. */ + RTUINT64U u64VmFuncCtls; /**< 0x2b8 - VM-functions control. */ + RTUINT64U u64EptPtr; /**< 0x2c0 - EPT pointer. */ + RTUINT64U u64EoiExitBitmap0; /**< 0x2c8 - EOI-exit bitmap 0. */ + RTUINT64U u64EoiExitBitmap1; /**< 0x2d0 - EOI-exit bitmap 1. */ + RTUINT64U u64EoiExitBitmap2; /**< 0x2d8 - EOI-exit bitmap 2. */ + RTUINT64U u64EoiExitBitmap3; /**< 0x2e0 - EOI-exit bitmap 3. */ + RTUINT64U u64AddrEptpList; /**< 0x2e8 - EPTP-list address. */ + RTUINT64U u64AddrVmreadBitmap; /**< 0x2f0 - VMREAD-bitmap address. */ + RTUINT64U u64AddrVmwriteBitmap; /**< 0x2f8 - VMWRITE-bitmap address. */ + RTUINT64U u64AddrXcptVeInfo; /**< 0x300 - Virtualization-exception information address. */ + RTUINT64U u64XssExitBitmap; /**< 0x308 - XSS-exiting bitmap. */ + RTUINT64U u64EnclsExitBitmap; /**< 0x310 - ENCLS-exiting bitmap address. */ + RTUINT64U u64SppTablePtr; /**< 0x318 - Sub-page-permission-table pointer (SPPTP). */ + RTUINT64U u64TscMultiplier; /**< 0x320 - TSC multiplier. */ + RTUINT64U u64ProcCtls3; /**< 0x328 - Tertiary-Processor based VM-execution controls. */ + RTUINT64U u64EnclvExitBitmap; /**< 0x330 - ENCLV-exiting bitmap. */ + RTUINT64U u64PconfigExitBitmap; /**< 0x338 - PCONFIG-exiting bitmap. */ + RTUINT64U u64HlatPtr; /**< 0x340 - HLAT pointer. */ + RTUINT64U u64ExitCtls2; /**< 0x348 - Secondary VM-exit controls. */ + RTUINT64U au64Reserved0[10]; /**< 0x350 - Reserved for future. */ + + /** Natural-width fields. */ + RTUINT64U u64Cr0Mask; /**< 0x3a0 - CR0 guest/host Mask. */ + RTUINT64U u64Cr4Mask; /**< 0x3a8 - CR4 guest/host Mask. */ + RTUINT64U u64Cr0ReadShadow; /**< 0x3b0 - CR0 read shadow. */ + RTUINT64U u64Cr4ReadShadow; /**< 0x3b8 - CR4 read shadow. */ + RTUINT64U u64Cr3Target0; /**< 0x3c0 - CR3-target value 0. */ + RTUINT64U u64Cr3Target1; /**< 0x3c8 - CR3-target value 1. */ + RTUINT64U u64Cr3Target2; /**< 0x3d0 - CR3-target value 2. */ + RTUINT64U u64Cr3Target3; /**< 0x3d8 - CR3-target value 3. */ + RTUINT64U au64Reserved4[32]; /**< 0x3e0 - Reserved for future. */ + /** @} */ + + /** @name Host-state fields. + * @{ */ + /** 16-bit fields. */ + /* Order of [Es..Gs] fields below must match [X86_SREG_ES..X86_SREG_GS]. */ + RTSEL HostEs; /**< 0x4e0 - Host ES selector. */ + RTSEL HostCs; /**< 0x4e2 - Host CS selector. */ + RTSEL HostSs; /**< 0x4e4 - Host SS selector. */ + RTSEL HostDs; /**< 0x4e6 - Host DS selector. */ + RTSEL HostFs; /**< 0x4e8 - Host FS selector. */ + RTSEL HostGs; /**< 0x4ea - Host GS selector. */ + RTSEL HostTr; /**< 0x4ec - Host TR selector. */ + uint16_t au16Reserved2[13]; /**< 0x4ee - Reserved for future. */ + + /** 32-bit fields. */ + uint32_t u32HostSysenterCs; /**< 0x508 - Host SYSENTER CS. */ + uint32_t au32Reserved4[11]; /**< 0x50c - Reserved for future. */ + + /** 64-bit fields. */ + RTUINT64U u64HostPatMsr; /**< 0x538 - Host PAT MSR. */ + RTUINT64U u64HostEferMsr; /**< 0x540 - Host EFER MSR. */ + RTUINT64U u64HostPerfGlobalCtlMsr; /**< 0x548 - Host global performance-control MSR. */ + RTUINT64U u64HostPkrsMsr; /**< 0x550 - Host PKRS MSR. */ + RTUINT64U au64Reserved3[15]; /**< 0x558 - Reserved for future. */ + + /** Natural-width fields. */ + RTUINT64U u64HostCr0; /**< 0x5d0 - Host CR0. */ + RTUINT64U u64HostCr3; /**< 0x5d8 - Host CR3. */ + RTUINT64U u64HostCr4; /**< 0x5e0 - Host CR4. */ + RTUINT64U u64HostFsBase; /**< 0x5e8 - Host FS base. */ + RTUINT64U u64HostGsBase; /**< 0x5f0 - Host GS base. */ + RTUINT64U u64HostTrBase; /**< 0x5f8 - Host TR base. */ + RTUINT64U u64HostGdtrBase; /**< 0x600 - Host GDTR base. */ + RTUINT64U u64HostIdtrBase; /**< 0x608 - Host IDTR base. */ + RTUINT64U u64HostSysenterEsp; /**< 0x610 - Host SYSENTER ESP base. */ + RTUINT64U u64HostSysenterEip; /**< 0x618 - Host SYSENTER ESP base. */ + RTUINT64U u64HostRsp; /**< 0x620 - Host RSP. */ + RTUINT64U u64HostRip; /**< 0x628 - Host RIP. */ + RTUINT64U u64HostSCetMsr; /**< 0x630 - Host S_CET MSR. */ + RTUINT64U u64HostSsp; /**< 0x638 - Host SSP. */ + RTUINT64U u64HostIntrSspTableAddrMsr; /**< 0x640 - Host Interrupt SSP table address MSR. */ + RTUINT64U au64Reserved7[29]; /**< 0x648 - Reserved for future. */ + /** @} */ + + /** @name Guest-state fields. + * @{ */ + /** 16-bit fields. */ + /* Order of [Es..Gs] fields below must match [X86_SREG_ES..X86_SREG_GS]. */ + RTSEL GuestEs; /**< 0x730 - Guest ES selector. */ + RTSEL GuestCs; /**< 0x732 - Guest ES selector. */ + RTSEL GuestSs; /**< 0x734 - Guest ES selector. */ + RTSEL GuestDs; /**< 0x736 - Guest ES selector. */ + RTSEL GuestFs; /**< 0x738 - Guest ES selector. */ + RTSEL GuestGs; /**< 0x73a - Guest ES selector. */ + RTSEL GuestLdtr; /**< 0x73c - Guest LDTR selector. */ + RTSEL GuestTr; /**< 0x73e - Guest TR selector. */ + uint16_t u16GuestIntStatus; /**< 0x740 - Guest interrupt status (virtual-interrupt delivery). */ + uint16_t u16PmlIndex; /**< 0x742 - PML index. */ + uint16_t au16Reserved1[14]; /**< 0x744 - Reserved for future. */ + + /** 32-bit fields. */ + /* Order of [Es..Gs] fields below must match [X86_SREG_ES..X86_SREG_GS]. */ + uint32_t u32GuestEsLimit; /**< 0x760 - Guest ES limit. */ + uint32_t u32GuestCsLimit; /**< 0x764 - Guest CS limit. */ + uint32_t u32GuestSsLimit; /**< 0x768 - Guest SS limit. */ + uint32_t u32GuestDsLimit; /**< 0x76c - Guest DS limit. */ + uint32_t u32GuestFsLimit; /**< 0x770 - Guest FS limit. */ + uint32_t u32GuestGsLimit; /**< 0x774 - Guest GS limit. */ + uint32_t u32GuestLdtrLimit; /**< 0x778 - Guest LDTR limit. */ + uint32_t u32GuestTrLimit; /**< 0x77c - Guest TR limit. */ + uint32_t u32GuestGdtrLimit; /**< 0x780 - Guest GDTR limit. */ + uint32_t u32GuestIdtrLimit; /**< 0x784 - Guest IDTR limit. */ + uint32_t u32GuestEsAttr; /**< 0x788 - Guest ES attributes. */ + uint32_t u32GuestCsAttr; /**< 0x78c - Guest CS attributes. */ + uint32_t u32GuestSsAttr; /**< 0x790 - Guest SS attributes. */ + uint32_t u32GuestDsAttr; /**< 0x794 - Guest DS attributes. */ + uint32_t u32GuestFsAttr; /**< 0x798 - Guest FS attributes. */ + uint32_t u32GuestGsAttr; /**< 0x79c - Guest GS attributes. */ + uint32_t u32GuestLdtrAttr; /**< 0x7a0 - Guest LDTR attributes. */ + uint32_t u32GuestTrAttr; /**< 0x7a4 - Guest TR attributes. */ + uint32_t u32GuestIntrState; /**< 0x7a8 - Guest interruptibility state. */ + uint32_t u32GuestActivityState; /**< 0x7ac - Guest activity state. */ + uint32_t u32GuestSmBase; /**< 0x7b0 - Guest SMBASE. */ + uint32_t u32GuestSysenterCS; /**< 0x7b4 - Guest SYSENTER CS. */ + uint32_t u32PreemptTimer; /**< 0x7b8 - Preemption timer value. */ + uint32_t au32Reserved3[11]; /**< 0x7bc - Reserved for future. */ + + /** 64-bit fields. */ + RTUINT64U u64VmcsLinkPtr; /**< 0x7e8 - VMCS link pointer. */ + RTUINT64U u64GuestDebugCtlMsr; /**< 0x7f0 - Guest debug-control MSR. */ + RTUINT64U u64GuestPatMsr; /**< 0x7f8 - Guest PAT MSR. */ + RTUINT64U u64GuestEferMsr; /**< 0x800 - Guest EFER MSR. */ + RTUINT64U u64GuestPerfGlobalCtlMsr; /**< 0x808 - Guest global performance-control MSR. */ + RTUINT64U u64GuestPdpte0; /**< 0x810 - Guest PDPTE 0. */ + RTUINT64U u64GuestPdpte1; /**< 0x818 - Guest PDPTE 0. */ + RTUINT64U u64GuestPdpte2; /**< 0x820 - Guest PDPTE 1. */ + RTUINT64U u64GuestPdpte3; /**< 0x828 - Guest PDPTE 2. */ + RTUINT64U u64GuestBndcfgsMsr; /**< 0x830 - Guest Bounds config MPX MSR (Intel Memory Protection Extensions). */ + RTUINT64U u64GuestRtitCtlMsr; /**< 0x838 - Guest RTIT control MSR (Intel Real Time Instruction Trace). */ + RTUINT64U u64GuestPkrsMsr; /**< 0x840 - Guest PKRS MSR. */ + RTUINT64U au64Reserved2[31]; /**< 0x848 - Reserved for future. */ + + /** Natural-width fields. */ + RTUINT64U u64GuestCr0; /**< 0x940 - Guest CR0. */ + RTUINT64U u64GuestCr3; /**< 0x948 - Guest CR3. */ + RTUINT64U u64GuestCr4; /**< 0x950 - Guest CR4. */ + RTUINT64U u64GuestEsBase; /**< 0x958 - Guest ES base. */ + RTUINT64U u64GuestCsBase; /**< 0x960 - Guest CS base. */ + RTUINT64U u64GuestSsBase; /**< 0x968 - Guest SS base. */ + RTUINT64U u64GuestDsBase; /**< 0x970 - Guest DS base. */ + RTUINT64U u64GuestFsBase; /**< 0x978 - Guest FS base. */ + RTUINT64U u64GuestGsBase; /**< 0x980 - Guest GS base. */ + RTUINT64U u64GuestLdtrBase; /**< 0x988 - Guest LDTR base. */ + RTUINT64U u64GuestTrBase; /**< 0x990 - Guest TR base. */ + RTUINT64U u64GuestGdtrBase; /**< 0x998 - Guest GDTR base. */ + RTUINT64U u64GuestIdtrBase; /**< 0x9a0 - Guest IDTR base. */ + RTUINT64U u64GuestDr7; /**< 0x9a8 - Guest DR7. */ + RTUINT64U u64GuestRsp; /**< 0x9b0 - Guest RSP. */ + RTUINT64U u64GuestRip; /**< 0x9b8 - Guest RIP. */ + RTUINT64U u64GuestRFlags; /**< 0x9c0 - Guest RFLAGS. */ + RTUINT64U u64GuestPendingDbgXcpts; /**< 0x9c8 - Guest pending debug exceptions. */ + RTUINT64U u64GuestSysenterEsp; /**< 0x9d0 - Guest SYSENTER ESP. */ + RTUINT64U u64GuestSysenterEip; /**< 0x9d8 - Guest SYSENTER EIP. */ + RTUINT64U u64GuestSCetMsr; /**< 0x9e0 - Guest S_CET MSR. */ + RTUINT64U u64GuestSsp; /**< 0x9e8 - Guest SSP. */ + RTUINT64U u64GuestIntrSspTableAddrMsr; /**< 0x9f0 - Guest Interrupt SSP table address MSR. */ + RTUINT64U au64Reserved6[29]; /**< 0x9f8 - Reserved for future. */ + /** @} */ + + /** 0xae0 - Padding / reserved for future use. */ + uint8_t abPadding[X86_PAGE_4K_SIZE - 0xae0]; +} VMXVVMCS; +#pragma pack() +/** Pointer to the VMXVVMCS struct. */ +typedef VMXVVMCS *PVMXVVMCS; +/** Pointer to a const VMXVVMCS struct. */ +typedef const VMXVVMCS *PCVMXVVMCS; +AssertCompileSize(VMXVVMCS, X86_PAGE_4K_SIZE); +AssertCompileMemberSize(VMXVVMCS, fVmcsState, sizeof(uint8_t)); +AssertCompileMemberOffset(VMXVVMCS, enmVmxAbort, 0x004); +AssertCompileMemberOffset(VMXVVMCS, fVmcsState, 0x008); +AssertCompileMemberOffset(VMXVVMCS, u32RoVmInstrError, 0x058); +AssertCompileMemberOffset(VMXVVMCS, u64RoGuestPhysAddr, 0x0b8); +AssertCompileMemberOffset(VMXVVMCS, u64RoExitQual, 0x100); +AssertCompileMemberOffset(VMXVVMCS, u16Vpid, 0x1b0); +AssertCompileMemberOffset(VMXVVMCS, u32PinCtls, 0x1d0); +AssertCompileMemberOffset(VMXVVMCS, u64AddrIoBitmapA, 0x258); +AssertCompileMemberOffset(VMXVVMCS, u64Cr0Mask, 0x3a0); +AssertCompileMemberOffset(VMXVVMCS, HostEs, 0x4e0); +AssertCompileMemberOffset(VMXVVMCS, u32HostSysenterCs, 0x508); +AssertCompileMemberOffset(VMXVVMCS, u64HostPatMsr, 0x538); +AssertCompileMemberOffset(VMXVVMCS, u64HostCr0, 0x5d0); +AssertCompileMemberOffset(VMXVVMCS, GuestEs, 0x730); +AssertCompileMemberOffset(VMXVVMCS, u32GuestEsLimit, 0x760); +AssertCompileMemberOffset(VMXVVMCS, u64VmcsLinkPtr, 0x7e8); +AssertCompileMemberOffset(VMXVVMCS, u64GuestCr0, 0x940); + +/** + * Virtual VMX-instruction and VM-exit diagnostics. + * + * These are not the same as VM instruction errors that are enumerated in the Intel + * spec. These are purely internal, fine-grained definitions used for diagnostic + * purposes and are not reported to guest software under the VM-instruction error + * field in its VMCS. + * + * @note Members of this enum are used as array indices, so no gaps are allowed. + * Please update g_apszVmxVDiagDesc when you add new fields to this enum. + */ +typedef enum +{ + /* Internal processing errors. */ + kVmxVDiag_None = 0, + kVmxVDiag_Ipe_1, + kVmxVDiag_Ipe_2, + kVmxVDiag_Ipe_3, + kVmxVDiag_Ipe_4, + kVmxVDiag_Ipe_5, + kVmxVDiag_Ipe_6, + kVmxVDiag_Ipe_7, + kVmxVDiag_Ipe_8, + kVmxVDiag_Ipe_9, + kVmxVDiag_Ipe_10, + kVmxVDiag_Ipe_11, + kVmxVDiag_Ipe_12, + kVmxVDiag_Ipe_13, + kVmxVDiag_Ipe_14, + kVmxVDiag_Ipe_15, + kVmxVDiag_Ipe_16, + /* VMXON. */ + kVmxVDiag_Vmxon_A20M, + kVmxVDiag_Vmxon_Cpl, + kVmxVDiag_Vmxon_Cr0Fixed0, + kVmxVDiag_Vmxon_Cr0Fixed1, + kVmxVDiag_Vmxon_Cr4Fixed0, + kVmxVDiag_Vmxon_Cr4Fixed1, + kVmxVDiag_Vmxon_Intercept, + kVmxVDiag_Vmxon_LongModeCS, + kVmxVDiag_Vmxon_MsrFeatCtl, + kVmxVDiag_Vmxon_PtrAbnormal, + kVmxVDiag_Vmxon_PtrAlign, + kVmxVDiag_Vmxon_PtrMap, + kVmxVDiag_Vmxon_PtrReadPhys, + kVmxVDiag_Vmxon_PtrWidth, + kVmxVDiag_Vmxon_RealOrV86Mode, + kVmxVDiag_Vmxon_ShadowVmcs, + kVmxVDiag_Vmxon_VmxAlreadyRoot, + kVmxVDiag_Vmxon_Vmxe, + kVmxVDiag_Vmxon_VmcsRevId, + kVmxVDiag_Vmxon_VmxRootCpl, + /* VMXOFF. */ + kVmxVDiag_Vmxoff_Cpl, + kVmxVDiag_Vmxoff_Intercept, + kVmxVDiag_Vmxoff_LongModeCS, + kVmxVDiag_Vmxoff_RealOrV86Mode, + kVmxVDiag_Vmxoff_Vmxe, + kVmxVDiag_Vmxoff_VmxRoot, + /* VMPTRLD. */ + kVmxVDiag_Vmptrld_Cpl, + kVmxVDiag_Vmptrld_LongModeCS, + kVmxVDiag_Vmptrld_PtrAbnormal, + kVmxVDiag_Vmptrld_PtrAlign, + kVmxVDiag_Vmptrld_PtrMap, + kVmxVDiag_Vmptrld_PtrReadPhys, + kVmxVDiag_Vmptrld_PtrVmxon, + kVmxVDiag_Vmptrld_PtrWidth, + kVmxVDiag_Vmptrld_RealOrV86Mode, + kVmxVDiag_Vmptrld_RevPtrReadPhys, + kVmxVDiag_Vmptrld_ShadowVmcs, + kVmxVDiag_Vmptrld_VmcsRevId, + kVmxVDiag_Vmptrld_VmxRoot, + /* VMPTRST. */ + kVmxVDiag_Vmptrst_Cpl, + kVmxVDiag_Vmptrst_LongModeCS, + kVmxVDiag_Vmptrst_PtrMap, + kVmxVDiag_Vmptrst_RealOrV86Mode, + kVmxVDiag_Vmptrst_VmxRoot, + /* VMCLEAR. */ + kVmxVDiag_Vmclear_Cpl, + kVmxVDiag_Vmclear_LongModeCS, + kVmxVDiag_Vmclear_PtrAbnormal, + kVmxVDiag_Vmclear_PtrAlign, + kVmxVDiag_Vmclear_PtrMap, + kVmxVDiag_Vmclear_PtrReadPhys, + kVmxVDiag_Vmclear_PtrVmxon, + kVmxVDiag_Vmclear_PtrWidth, + kVmxVDiag_Vmclear_RealOrV86Mode, + kVmxVDiag_Vmclear_VmxRoot, + /* VMWRITE. */ + kVmxVDiag_Vmwrite_Cpl, + kVmxVDiag_Vmwrite_FieldInvalid, + kVmxVDiag_Vmwrite_FieldRo, + kVmxVDiag_Vmwrite_LinkPtrInvalid, + kVmxVDiag_Vmwrite_LongModeCS, + kVmxVDiag_Vmwrite_PtrInvalid, + kVmxVDiag_Vmwrite_PtrMap, + kVmxVDiag_Vmwrite_RealOrV86Mode, + kVmxVDiag_Vmwrite_VmxRoot, + /* VMREAD. */ + kVmxVDiag_Vmread_Cpl, + kVmxVDiag_Vmread_FieldInvalid, + kVmxVDiag_Vmread_LinkPtrInvalid, + kVmxVDiag_Vmread_LongModeCS, + kVmxVDiag_Vmread_PtrInvalid, + kVmxVDiag_Vmread_PtrMap, + kVmxVDiag_Vmread_RealOrV86Mode, + kVmxVDiag_Vmread_VmxRoot, + /* INVVPID. */ + kVmxVDiag_Invvpid_Cpl, + kVmxVDiag_Invvpid_DescRsvd, + kVmxVDiag_Invvpid_LongModeCS, + kVmxVDiag_Invvpid_RealOrV86Mode, + kVmxVDiag_Invvpid_TypeInvalid, + kVmxVDiag_Invvpid_Type0InvalidAddr, + kVmxVDiag_Invvpid_Type0InvalidVpid, + kVmxVDiag_Invvpid_Type1InvalidVpid, + kVmxVDiag_Invvpid_Type3InvalidVpid, + kVmxVDiag_Invvpid_VmxRoot, + /* INVEPT. */ + kVmxVDiag_Invept_Cpl, + kVmxVDiag_Invept_DescRsvd, + kVmxVDiag_Invept_EptpInvalid, + kVmxVDiag_Invept_LongModeCS, + kVmxVDiag_Invept_RealOrV86Mode, + kVmxVDiag_Invept_TypeInvalid, + kVmxVDiag_Invept_VmxRoot, + /* VMLAUNCH/VMRESUME. */ + kVmxVDiag_Vmentry_AddrApicAccess, + kVmxVDiag_Vmentry_AddrApicAccessEqVirtApic, + kVmxVDiag_Vmentry_AddrApicAccessHandlerReg, + kVmxVDiag_Vmentry_AddrEntryMsrLoad, + kVmxVDiag_Vmentry_AddrExitMsrLoad, + kVmxVDiag_Vmentry_AddrExitMsrStore, + kVmxVDiag_Vmentry_AddrIoBitmapA, + kVmxVDiag_Vmentry_AddrIoBitmapB, + kVmxVDiag_Vmentry_AddrMsrBitmap, + kVmxVDiag_Vmentry_AddrVirtApicPage, + kVmxVDiag_Vmentry_AddrVmcsLinkPtr, + kVmxVDiag_Vmentry_AddrVmreadBitmap, + kVmxVDiag_Vmentry_AddrVmwriteBitmap, + kVmxVDiag_Vmentry_ApicRegVirt, + kVmxVDiag_Vmentry_BlocKMovSS, + kVmxVDiag_Vmentry_Cpl, + kVmxVDiag_Vmentry_Cr3TargetCount, + kVmxVDiag_Vmentry_EntryCtlsAllowed1, + kVmxVDiag_Vmentry_EntryCtlsDisallowed0, + kVmxVDiag_Vmentry_EntryInstrLen, + kVmxVDiag_Vmentry_EntryInstrLenZero, + kVmxVDiag_Vmentry_EntryIntInfoErrCodePe, + kVmxVDiag_Vmentry_EntryIntInfoErrCodeVec, + kVmxVDiag_Vmentry_EntryIntInfoTypeVecRsvd, + kVmxVDiag_Vmentry_EntryXcptErrCodeRsvd, + kVmxVDiag_Vmentry_EptpAccessDirty, + kVmxVDiag_Vmentry_EptpPageWalkLength, + kVmxVDiag_Vmentry_EptpMemType, + kVmxVDiag_Vmentry_EptpRsvd, + kVmxVDiag_Vmentry_ExitCtlsAllowed1, + kVmxVDiag_Vmentry_ExitCtlsDisallowed0, + kVmxVDiag_Vmentry_GuestActStateHlt, + kVmxVDiag_Vmentry_GuestActStateRsvd, + kVmxVDiag_Vmentry_GuestActStateShutdown, + kVmxVDiag_Vmentry_GuestActStateSsDpl, + kVmxVDiag_Vmentry_GuestActStateStiMovSs, + kVmxVDiag_Vmentry_GuestCr0Fixed0, + kVmxVDiag_Vmentry_GuestCr0Fixed1, + kVmxVDiag_Vmentry_GuestCr0PgPe, + kVmxVDiag_Vmentry_GuestCr3, + kVmxVDiag_Vmentry_GuestCr4Fixed0, + kVmxVDiag_Vmentry_GuestCr4Fixed1, + kVmxVDiag_Vmentry_GuestDebugCtl, + kVmxVDiag_Vmentry_GuestDr7, + kVmxVDiag_Vmentry_GuestEferMsr, + kVmxVDiag_Vmentry_GuestEferMsrRsvd, + kVmxVDiag_Vmentry_GuestGdtrBase, + kVmxVDiag_Vmentry_GuestGdtrLimit, + kVmxVDiag_Vmentry_GuestIdtrBase, + kVmxVDiag_Vmentry_GuestIdtrLimit, + kVmxVDiag_Vmentry_GuestIntStateEnclave, + kVmxVDiag_Vmentry_GuestIntStateExtInt, + kVmxVDiag_Vmentry_GuestIntStateNmi, + kVmxVDiag_Vmentry_GuestIntStateRFlagsSti, + kVmxVDiag_Vmentry_GuestIntStateRsvd, + kVmxVDiag_Vmentry_GuestIntStateSmi, + kVmxVDiag_Vmentry_GuestIntStateStiMovSs, + kVmxVDiag_Vmentry_GuestIntStateVirtNmi, + kVmxVDiag_Vmentry_GuestPae, + kVmxVDiag_Vmentry_GuestPatMsr, + kVmxVDiag_Vmentry_GuestPcide, + kVmxVDiag_Vmentry_GuestPdpte, + kVmxVDiag_Vmentry_GuestPndDbgXcptBsNoTf, + kVmxVDiag_Vmentry_GuestPndDbgXcptBsTf, + kVmxVDiag_Vmentry_GuestPndDbgXcptRsvd, + kVmxVDiag_Vmentry_GuestPndDbgXcptRtm, + kVmxVDiag_Vmentry_GuestRip, + kVmxVDiag_Vmentry_GuestRipRsvd, + kVmxVDiag_Vmentry_GuestRFlagsIf, + kVmxVDiag_Vmentry_GuestRFlagsRsvd, + kVmxVDiag_Vmentry_GuestRFlagsVm, + kVmxVDiag_Vmentry_GuestSegAttrCsDefBig, + kVmxVDiag_Vmentry_GuestSegAttrCsDplEqSs, + kVmxVDiag_Vmentry_GuestSegAttrCsDplLtSs, + kVmxVDiag_Vmentry_GuestSegAttrCsDplZero, + kVmxVDiag_Vmentry_GuestSegAttrCsType, + kVmxVDiag_Vmentry_GuestSegAttrCsTypeRead, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeCs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeDs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeEs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeFs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeGs, + kVmxVDiag_Vmentry_GuestSegAttrDescTypeSs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplCs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplDs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplEs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplFs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplGs, + kVmxVDiag_Vmentry_GuestSegAttrDplRplSs, + kVmxVDiag_Vmentry_GuestSegAttrGranCs, + kVmxVDiag_Vmentry_GuestSegAttrGranDs, + kVmxVDiag_Vmentry_GuestSegAttrGranEs, + kVmxVDiag_Vmentry_GuestSegAttrGranFs, + kVmxVDiag_Vmentry_GuestSegAttrGranGs, + kVmxVDiag_Vmentry_GuestSegAttrGranSs, + kVmxVDiag_Vmentry_GuestSegAttrLdtrDescType, + kVmxVDiag_Vmentry_GuestSegAttrLdtrGran, + kVmxVDiag_Vmentry_GuestSegAttrLdtrPresent, + kVmxVDiag_Vmentry_GuestSegAttrLdtrRsvd, + kVmxVDiag_Vmentry_GuestSegAttrLdtrType, + kVmxVDiag_Vmentry_GuestSegAttrPresentCs, + kVmxVDiag_Vmentry_GuestSegAttrPresentDs, + kVmxVDiag_Vmentry_GuestSegAttrPresentEs, + kVmxVDiag_Vmentry_GuestSegAttrPresentFs, + kVmxVDiag_Vmentry_GuestSegAttrPresentGs, + kVmxVDiag_Vmentry_GuestSegAttrPresentSs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdCs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdDs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdEs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdFs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdGs, + kVmxVDiag_Vmentry_GuestSegAttrRsvdSs, + kVmxVDiag_Vmentry_GuestSegAttrSsDplEqRpl, + kVmxVDiag_Vmentry_GuestSegAttrSsDplZero, + kVmxVDiag_Vmentry_GuestSegAttrSsType, + kVmxVDiag_Vmentry_GuestSegAttrTrDescType, + kVmxVDiag_Vmentry_GuestSegAttrTrGran, + kVmxVDiag_Vmentry_GuestSegAttrTrPresent, + kVmxVDiag_Vmentry_GuestSegAttrTrRsvd, + kVmxVDiag_Vmentry_GuestSegAttrTrType, + kVmxVDiag_Vmentry_GuestSegAttrTrUnusable, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccCs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccDs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccEs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccFs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccGs, + kVmxVDiag_Vmentry_GuestSegAttrTypeAccSs, + kVmxVDiag_Vmentry_GuestSegAttrV86Cs, + kVmxVDiag_Vmentry_GuestSegAttrV86Ds, + kVmxVDiag_Vmentry_GuestSegAttrV86Es, + kVmxVDiag_Vmentry_GuestSegAttrV86Fs, + kVmxVDiag_Vmentry_GuestSegAttrV86Gs, + kVmxVDiag_Vmentry_GuestSegAttrV86Ss, + kVmxVDiag_Vmentry_GuestSegBaseCs, + kVmxVDiag_Vmentry_GuestSegBaseDs, + kVmxVDiag_Vmentry_GuestSegBaseEs, + kVmxVDiag_Vmentry_GuestSegBaseFs, + kVmxVDiag_Vmentry_GuestSegBaseGs, + kVmxVDiag_Vmentry_GuestSegBaseLdtr, + kVmxVDiag_Vmentry_GuestSegBaseSs, + kVmxVDiag_Vmentry_GuestSegBaseTr, + kVmxVDiag_Vmentry_GuestSegBaseV86Cs, + kVmxVDiag_Vmentry_GuestSegBaseV86Ds, + kVmxVDiag_Vmentry_GuestSegBaseV86Es, + kVmxVDiag_Vmentry_GuestSegBaseV86Fs, + kVmxVDiag_Vmentry_GuestSegBaseV86Gs, + kVmxVDiag_Vmentry_GuestSegBaseV86Ss, + kVmxVDiag_Vmentry_GuestSegLimitV86Cs, + kVmxVDiag_Vmentry_GuestSegLimitV86Ds, + kVmxVDiag_Vmentry_GuestSegLimitV86Es, + kVmxVDiag_Vmentry_GuestSegLimitV86Fs, + kVmxVDiag_Vmentry_GuestSegLimitV86Gs, + kVmxVDiag_Vmentry_GuestSegLimitV86Ss, + kVmxVDiag_Vmentry_GuestSegSelCsSsRpl, + kVmxVDiag_Vmentry_GuestSegSelLdtr, + kVmxVDiag_Vmentry_GuestSegSelTr, + kVmxVDiag_Vmentry_GuestSysenterEspEip, + kVmxVDiag_Vmentry_VmcsLinkPtrCurVmcs, + kVmxVDiag_Vmentry_VmcsLinkPtrReadPhys, + kVmxVDiag_Vmentry_VmcsLinkPtrRevId, + kVmxVDiag_Vmentry_VmcsLinkPtrShadow, + kVmxVDiag_Vmentry_HostCr0Fixed0, + kVmxVDiag_Vmentry_HostCr0Fixed1, + kVmxVDiag_Vmentry_HostCr3, + kVmxVDiag_Vmentry_HostCr4Fixed0, + kVmxVDiag_Vmentry_HostCr4Fixed1, + kVmxVDiag_Vmentry_HostCr4Pae, + kVmxVDiag_Vmentry_HostCr4Pcide, + kVmxVDiag_Vmentry_HostCsTr, + kVmxVDiag_Vmentry_HostEferMsr, + kVmxVDiag_Vmentry_HostEferMsrRsvd, + kVmxVDiag_Vmentry_HostGuestLongMode, + kVmxVDiag_Vmentry_HostGuestLongModeNoCpu, + kVmxVDiag_Vmentry_HostLongMode, + kVmxVDiag_Vmentry_HostPatMsr, + kVmxVDiag_Vmentry_HostRip, + kVmxVDiag_Vmentry_HostRipRsvd, + kVmxVDiag_Vmentry_HostSel, + kVmxVDiag_Vmentry_HostSegBase, + kVmxVDiag_Vmentry_HostSs, + kVmxVDiag_Vmentry_HostSysenterEspEip, + kVmxVDiag_Vmentry_IoBitmapAPtrReadPhys, + kVmxVDiag_Vmentry_IoBitmapBPtrReadPhys, + kVmxVDiag_Vmentry_LongModeCS, + kVmxVDiag_Vmentry_MsrBitmapPtrReadPhys, + kVmxVDiag_Vmentry_MsrLoad, + kVmxVDiag_Vmentry_MsrLoadCount, + kVmxVDiag_Vmentry_MsrLoadPtrReadPhys, + kVmxVDiag_Vmentry_MsrLoadRing3, + kVmxVDiag_Vmentry_MsrLoadRsvd, + kVmxVDiag_Vmentry_NmiWindowExit, + kVmxVDiag_Vmentry_PinCtlsAllowed1, + kVmxVDiag_Vmentry_PinCtlsDisallowed0, + kVmxVDiag_Vmentry_ProcCtlsAllowed1, + kVmxVDiag_Vmentry_ProcCtlsDisallowed0, + kVmxVDiag_Vmentry_ProcCtls2Allowed1, + kVmxVDiag_Vmentry_ProcCtls2Disallowed0, + kVmxVDiag_Vmentry_PtrInvalid, + kVmxVDiag_Vmentry_PtrShadowVmcs, + kVmxVDiag_Vmentry_RealOrV86Mode, + kVmxVDiag_Vmentry_SavePreemptTimer, + kVmxVDiag_Vmentry_TprThresholdRsvd, + kVmxVDiag_Vmentry_TprThresholdVTpr, + kVmxVDiag_Vmentry_VirtApicPagePtrReadPhys, + kVmxVDiag_Vmentry_VirtIntDelivery, + kVmxVDiag_Vmentry_VirtNmi, + kVmxVDiag_Vmentry_VirtX2ApicTprShadow, + kVmxVDiag_Vmentry_VirtX2ApicVirtApic, + kVmxVDiag_Vmentry_VmcsClear, + kVmxVDiag_Vmentry_VmcsLaunch, + kVmxVDiag_Vmentry_VmreadBitmapPtrReadPhys, + kVmxVDiag_Vmentry_VmwriteBitmapPtrReadPhys, + kVmxVDiag_Vmentry_VmxRoot, + kVmxVDiag_Vmentry_Vpid, + kVmxVDiag_Vmexit_HostPdpte, + kVmxVDiag_Vmexit_MsrLoad, + kVmxVDiag_Vmexit_MsrLoadCount, + kVmxVDiag_Vmexit_MsrLoadPtrReadPhys, + kVmxVDiag_Vmexit_MsrLoadRing3, + kVmxVDiag_Vmexit_MsrLoadRsvd, + kVmxVDiag_Vmexit_MsrStore, + kVmxVDiag_Vmexit_MsrStoreCount, + kVmxVDiag_Vmexit_MsrStorePtrReadPhys, + kVmxVDiag_Vmexit_MsrStorePtrWritePhys, + kVmxVDiag_Vmexit_MsrStoreRing3, + kVmxVDiag_Vmexit_MsrStoreRsvd, + kVmxVDiag_Vmexit_VirtApicPagePtrWritePhys, + /* Last member for determining array index limit. */ + kVmxVDiag_End +} VMXVDIAG; +AssertCompileSize(VMXVDIAG, 4); + +/** @} */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_hm_vmx_h */ + diff --git a/include/VBox/vmm/hm_vmx.mac b/include/VBox/vmm/hm_vmx.mac new file mode 100644 index 00000000..15373887 --- /dev/null +++ b/include/VBox/vmm/hm_vmx.mac @@ -0,0 +1,163 @@ +;; @file +; HM - VMX Structures and Definitions. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%define VMX_VMCS_GUEST_FIELD_ES 0800h +%define VMX_VMCS_GUEST_FIELD_CS 0802h +%define VMX_VMCS_GUEST_FIELD_SS 0804h +%define VMX_VMCS_GUEST_FIELD_DS 0806h +%define VMX_VMCS_GUEST_FIELD_FS 0808h +%define VMX_VMCS_GUEST_FIELD_GS 080Ah +%define VMX_VMCS_GUEST_FIELD_LDTR 080Ch +%define VMX_VMCS_GUEST_FIELD_TR 080Eh +%define VMX_VMCS_HOST_FIELD_ES 0C00h +%define VMX_VMCS_HOST_FIELD_CS 0C02h +%define VMX_VMCS_HOST_FIELD_SS 0C04h +%define VMX_VMCS_HOST_FIELD_DS 0C06h +%define VMX_VMCS_HOST_FIELD_FS 0C08h +%define VMX_VMCS_HOST_FIELD_GS 0C0Ah +%define VMX_VMCS_HOST_FIELD_TR 0C0Ch +%define VMX_VMCS_CTRL_IO_BITMAP_A_FULL 02000h +%define VMX_VMCS_CTRL_IO_BITMAP_A_HIGH 02001h +%define VMX_VMCS_CTRL_IO_BITMAP_B_FULL 02002h +%define VMX_VMCS_CTRL_IO_BITMAP_B_HIGH 02003h +%define VMX_VMCS_CTRL_MSR_BITMAP_FULL 02004h +%define VMX_VMCS_CTRL_MSR_BITMAP_HIGH 02005h +%define VMX_VMCS_CTRL_VMEXIT_MSR_STORE_FULL 02006h +%define VMX_VMCS_CTRL_VMEXIT_MSR_STORE_HIGH 02007h +%define VMX_VMCS_CTRL_VMEXIT_MSR_LOAD_FULL 02008h +%define VMX_VMCS_CTRL_VMEXIT_MSR_LOAD_HIGH 02009h +%define VMX_VMCS_CTRL_VMENTRY_MSR_LOAD_FULL 0200Ah +%define VMX_VMCS_CTRL_VMENTRY_MSR_LOAD_HIGH 0200Bh +%define VMX_VMCS_CTRL_EXEC_VMCS_PTR_FULL 0200Ch +%define VMX_VMCS_CTRL_EXEC_VMCS_PTR_HIGH 0200Dh +%define VMX_VMCS_CTRL_TSC_OFFSET_FULL 02010h +%define VMX_VMCS_CTRL_TSC_OFFSET_HIGH 02011h +%define VMX_VMCS_CTRL_VAPIC_PAGEADDR_FULL 02012h +%define VMX_VMCS_CTRL_VAPIC_PAGEADDR_HIGH 02013h +%define VMX_VMCS_GUEST_LINK_PTR_FULL 02800h +%define VMX_VMCS_GUEST_LINK_PTR_HIGH 02801h +%define VMX_VMCS_GUEST_DEBUGCTL_FULL 02802h +%define VMX_VMCS_GUEST_DEBUGCTL_HIGH 02803h +%define VMX_VMCS_CTRL_PIN_EXEC 04000h +%define VMX_VMCS_CTRL_PROC_EXEC 04002h +%define VMX_VMCS_CTRL_EXCEPTION_BITMAP 04004h +%define VMX_VMCS_CTRL_PAGEFAULT_ERROR_MASK 04006h +%define VMX_VMCS_CTRL_PAGEFAULT_ERROR_MATCH 04008h +%define VMX_VMCS_CTRL_CR3_TARGET_COUNT 0400Ah +%define VMX_VMCS_CTRL_EXIT 0400Ch +%define VMX_VMCS_CTRL_EXIT_MSR_STORE_COUNT 0400Eh +%define VMX_VMCS_CTRL_EXIT_MSR_LOAD_COUNT 04010h +%define VMX_VMCS_CTRL_ENTRY 04012h +%define VMX_VMCS_CTRL_ENTRY_MSR_LOAD_COUNT 04014h +%define VMX_VMCS_CTRL_ENTRY_IRQ_INFO 04016h +%define VMX_VMCS_CTRL_ENTRY_EXCEPTION_ERRCODE 04018h +%define VMX_VMCS_CTRL_ENTRY_INSTR_LENGTH 0401Ah +%define VMX_VMCS_CTRL_TRP_TRESHOLD 0401Ch +%define VMX_VMCS_RO_VM_INSTR_ERROR 04400h +%define VMX_VMCS_RO_EXIT_REASON 04402h +%define VMX_VMCS_RO_EXIT_INTERRUPTION_INFO 04404h +%define VMX_VMCS_RO_EXIT_INTERRUPTION_ERRCODE 04406h +%define VMX_VMCS_RO_IDT_INFO 04408h +%define VMX_VMCS_RO_IDT_ERRCODE 0440Ah +%define VMX_VMCS_RO_EXIT_INSTR_LENGTH 0440Ch +%define VMX_VMCS_RO_EXIT_INSTR_INFO 0440Eh +%define VMX_VMCS_GUEST_ES_LIMIT 04800h +%define VMX_VMCS_GUEST_CS_LIMIT 04802h +%define VMX_VMCS_GUEST_SS_LIMIT 04804h +%define VMX_VMCS_GUEST_DS_LIMIT 04806h +%define VMX_VMCS_GUEST_FS_LIMIT 04808h +%define VMX_VMCS_GUEST_GS_LIMIT 0480Ah +%define VMX_VMCS_GUEST_LDTR_LIMIT 0480Ch +%define VMX_VMCS_GUEST_TR_LIMIT 0480Eh +%define VMX_VMCS_GUEST_GDTR_LIMIT 04810h +%define VMX_VMCS_GUEST_IDTR_LIMIT 04812h +%define VMX_VMCS_GUEST_ES_ACCESS_RIGHTS 04814h +%define VMX_VMCS_GUEST_CS_ACCESS_RIGHTS 04816h +%define VMX_VMCS_GUEST_SS_ACCESS_RIGHTS 04818h +%define VMX_VMCS_GUEST_DS_ACCESS_RIGHTS 0481Ah +%define VMX_VMCS_GUEST_FS_ACCESS_RIGHTS 0481Ch +%define VMX_VMCS_GUEST_GS_ACCESS_RIGHTS 0481Eh +%define VMX_VMCS_GUEST_LDTR_ACCESS_RIGHTS 04820h +%define VMX_VMCS_GUEST_TR_ACCESS_RIGHTS 04822h +%define VMX_VMCS_GUEST_INTERRUPTIBILITY_STATE 04824h +%define VMX_VMCS_GUEST_ACTIVITY_STATE 04826h +%define VMX_VMCS_GUEST_SYSENTER_CS 0482Ah +%define VMX_VMCS_CTRL_CR0_MASK 06000h +%define VMX_VMCS_CTRL_CR4_MASK 06002h +%define VMX_VMCS_CTRL_CR0_READ_SHADOW 06004h +%define VMX_VMCS_CTRL_CR4_READ_SHADOW 06006h +%define VMX_VMCS_CTRL_CR3_TARGET_VAL0 06008h +%define VMX_VMCS_CTRL_CR3_TARGET_VAL1 0600Ah +%define VMX_VMCS_CTRL_CR3_TARGET_VAL2 0600Ch +%define VMX_VMCS_CTRL_CR3_TARGET_VAL31 0600Eh +%define VMX_VMCS_RO_EXIT_QUALIFICATION 06400h +%define VMX_VMCS_RO_IO_RCX 06402h +%define VMX_VMCS_RO_IO_RSX 06404h +%define VMX_VMCS_RO_IO_RDI 06406h +%define VMX_VMCS_RO_IO_RIP 06408h +%define VMX_VMCS_GUEST_LINEAR_ADDR 0640Ah +%define VMX_VMCS64_GUEST_CR0 06800h +%define VMX_VMCS64_GUEST_CR3 06802h +%define VMX_VMCS64_GUEST_CR4 06804h +%define VMX_VMCS64_GUEST_ES_BASE 06806h +%define VMX_VMCS64_GUEST_CS_BASE 06808h +%define VMX_VMCS64_GUEST_SS_BASE 0680Ah +%define VMX_VMCS64_GUEST_DS_BASE 0680Ch +%define VMX_VMCS64_GUEST_FS_BASE 0680Eh +%define VMX_VMCS64_GUEST_GS_BASE 06810h +%define VMX_VMCS64_GUEST_LDTR_BASE 06812h +%define VMX_VMCS64_GUEST_TR_BASE 06814h +%define VMX_VMCS64_GUEST_GDTR_BASE 06816h +%define VMX_VMCS64_GUEST_IDTR_BASE 06818h +%define VMX_VMCS64_GUEST_DR7 0681Ah +%define VMX_VMCS64_GUEST_RSP 0681Ch +%define VMX_VMCS64_GUEST_RIP 0681Eh +%define VMX_VMCS64_GUEST_RFLAGS 06820h +%define VMX_VMCS_GUEST_DEBUG_EXCEPTIONS 06822h +%define VMX_VMCS64_GUEST_SYSENTER_ESP 06824h +%define VMX_VMCS64_GUEST_SYSENTER_EIP 06826h +%define VMX_VMCS_HOST_CR0 06C00h +%define VMX_VMCS_HOST_CR3 06C02h +%define VMX_VMCS_HOST_CR4 06C04h +%define VMX_VMCS_HOST_FS_BASE 06C06h +%define VMX_VMCS_HOST_GS_BASE 06C08h +%define VMX_VMCS_HOST_TR_BASE 06C0Ah +%define VMX_VMCS_HOST_GDTR_BASE 06C0Ch +%define VMX_VMCS_HOST_IDTR_BASE 06C0Eh +%define VMX_VMCS_HOST_SYSENTER_ESP 06C10h +%define VMX_VMCS_HOST_SYSENTER_EIP 06C12h +%define VMX_VMCS_HOST_RSP 06C14h +%define VMX_VMCS_HOST_RIP 06C16h + diff --git a/include/VBox/vmm/hmvmxinline.h b/include/VBox/vmm/hmvmxinline.h new file mode 100644 index 00000000..a0103786 --- /dev/null +++ b/include/VBox/vmm/hmvmxinline.h @@ -0,0 +1,1172 @@ +/** @file + * HM - VMX Structures and Definitions. (VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_hmvmxinline_h +#define VBOX_INCLUDED_vmm_hmvmxinline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +/* In Visual C++ versions prior to 2012, the vmx intrinsics are only available + when targeting AMD64. */ +#if RT_INLINE_ASM_USES_INTRIN >= RT_MSC_VER_VS2010 && defined(RT_ARCH_AMD64) +# include +/* We always want them as intrinsics, no functions. */ +# pragma intrinsic(__vmx_on) +# pragma intrinsic(__vmx_off) +# pragma intrinsic(__vmx_vmclear) +# pragma intrinsic(__vmx_vmptrld) +# pragma intrinsic(__vmx_vmread) +# pragma intrinsic(__vmx_vmwrite) +# define VMX_USE_MSC_INTRINSICS 1 +#else +# define VMX_USE_MSC_INTRINSICS 0 +#endif + +/** + * Whether we think the assembler supports VMX instructions. + * + * Guess that GCC 5 should have sufficient recent enough binutils. + */ +#if RT_INLINE_ASM_GNU_STYLE && RT_GNUC_PREREQ(5,0) +# define VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS 1 +#else +# define VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS 0 +#endif + +/** Whether we can use the subsection trick to put error handling code + * elsewhere. */ +#if VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS && defined(__ELF__) +# define VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK 1 +#else +# define VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK 0 +#endif + +/* Skip checking VMREAD/VMWRITE failures on non-strict builds. */ +#ifndef VBOX_STRICT +# define VBOX_WITH_VMREAD_VMWRITE_NOCHECK +#endif + + +/** @defgroup grp_hm_vmx_inline VMX Inline Helpers + * @ingroup grp_hm_vmx + * @{ + */ +/** + * Gets the effective width of a VMCS field given it's encoding adjusted for + * HIGH/FULL access for 64-bit fields. + * + * @returns The effective VMCS field width. + * @param uFieldEnc The VMCS field encoding. + * + * @remarks Warning! This function does not verify the encoding is for a valid and + * supported VMCS field. + */ +DECLINLINE(uint8_t) VMXGetVmcsFieldWidthEff(uint32_t uFieldEnc) +{ + /* Only the "HIGH" parts of all 64-bit fields have bit 0 set. */ + if (uFieldEnc & RT_BIT(0)) + return VMXVMCSFIELDWIDTH_32BIT; + + /* Bits 13:14 contains the width of the VMCS field, see VMXVMCSFIELDWIDTH_XXX. */ + return (uFieldEnc >> 13) & 0x3; +} + + +/** + * Returns whether the given VMCS field is a read-only VMCS field or not. + * + * @returns @c true if it's a read-only field, @c false otherwise. + * @param uFieldEnc The VMCS field encoding. + * + * @remarks Warning! This function does not verify that the encoding is for a valid + * and/or supported VMCS field. + */ +DECLINLINE(bool) VMXIsVmcsFieldReadOnly(uint32_t uFieldEnc) +{ + /* See Intel spec. B.4.2 "Natural-Width Read-Only Data Fields". */ + return (RT_BF_GET(uFieldEnc, VMX_BF_VMCSFIELD_TYPE) == VMXVMCSFIELDTYPE_VMEXIT_INFO); +} + + +/** + * Returns whether the given VM-entry interruption-information type is valid or not. + * + * @returns @c true if it's a valid type, @c false otherwise. + * @param fSupportsMTF Whether the Monitor-Trap Flag CPU feature is supported. + * @param uType The VM-entry interruption-information type. + */ +DECLINLINE(bool) VMXIsEntryIntInfoTypeValid(bool fSupportsMTF, uint8_t uType) +{ + /* See Intel spec. 26.2.1.3 "VM-Entry Control Fields". */ + switch (uType) + { + case VMX_ENTRY_INT_INFO_TYPE_EXT_INT: + case VMX_ENTRY_INT_INFO_TYPE_NMI: + case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT: + case VMX_ENTRY_INT_INFO_TYPE_SW_INT: + case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT: + case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT: return true; + case VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT: return fSupportsMTF; + default: + return false; + } +} + + +/** + * Returns whether the given VM-entry interruption-information vector and type + * combination is valid or not. + * + * @returns @c true if it's a valid vector/type combination, @c false otherwise. + * @param uVector The VM-entry interruption-information vector. + * @param uType The VM-entry interruption-information type. + * + * @remarks Warning! This function does not validate the type field individually. + * Use it after verifying type is valid using HMVmxIsEntryIntInfoTypeValid. + */ +DECLINLINE(bool) VMXIsEntryIntInfoVectorValid(uint8_t uVector, uint8_t uType) +{ + /* See Intel spec. 26.2.1.3 "VM-Entry Control Fields". */ + if ( uType == VMX_ENTRY_INT_INFO_TYPE_NMI + && uVector != X86_XCPT_NMI) + return false; + if ( uType == VMX_ENTRY_INT_INFO_TYPE_HW_XCPT + && uVector > X86_XCPT_LAST) + return false; + if ( uType == VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT + && uVector != VMX_ENTRY_INT_INFO_VECTOR_MTF) + return false; + return true; +} + + +/** + * Returns whether or not the VM-exit is trap-like or fault-like. + * + * @returns @c true if it's a trap-like VM-exit, @c false otherwise. + * @param uExitReason The VM-exit reason. + * + * @remarks Warning! This does not validate the VM-exit reason. + */ +DECLINLINE(bool) VMXIsVmexitTrapLike(uint32_t uExitReason) +{ + /* + * Trap-like VM-exits - The instruction causing the VM-exit completes before the + * VM-exit occurs. + * + * Fault-like VM-exits - The instruction causing the VM-exit is not completed before + * the VM-exit occurs. + * + * See Intel spec. 25.5.2 "Monitor Trap Flag". + * See Intel spec. 29.1.4 "EOI Virtualization". + * See Intel spec. 29.4.3.3 "APIC-Write VM Exits". + * See Intel spec. 29.1.2 "TPR Virtualization". + */ + /** @todo NSTVMX: r=ramshankar: What about VM-exits due to debug traps (single-step, + * I/O breakpoints, data breakpoints), debug exceptions (data breakpoint) + * delayed by MovSS blocking, machine-check exceptions. */ + switch (uExitReason) + { + case VMX_EXIT_MTF: + case VMX_EXIT_VIRTUALIZED_EOI: + case VMX_EXIT_APIC_WRITE: + case VMX_EXIT_TPR_BELOW_THRESHOLD: + return true; + } + return false; +} + + +/** + * Returns whether the VM-entry is vectoring or not given the VM-entry interruption + * information field. + * + * @returns @c true if the VM-entry is vectoring, @c false otherwise. + * @param uEntryIntInfo The VM-entry interruption information field. + * @param pEntryIntInfoType The VM-entry interruption information type field. + * Optional, can be NULL. Only updated when this + * function returns @c true. + */ +DECLINLINE(bool) VMXIsVmentryVectoring(uint32_t uEntryIntInfo, uint8_t *pEntryIntInfoType) +{ + /* + * The definition of what is a vectoring VM-entry is taken + * from Intel spec. 26.6 "Special Features of VM Entry". + */ + if (!VMX_ENTRY_INT_INFO_IS_VALID(uEntryIntInfo)) + return false; + + /* Scope and keep variable defines on top to satisy archaic c89 nonsense. */ + { + uint8_t const uType = VMX_ENTRY_INT_INFO_TYPE(uEntryIntInfo); + switch (uType) + { + case VMX_ENTRY_INT_INFO_TYPE_EXT_INT: + case VMX_ENTRY_INT_INFO_TYPE_NMI: + case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT: + case VMX_ENTRY_INT_INFO_TYPE_SW_INT: + case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT: + case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT: + { + if (pEntryIntInfoType) + *pEntryIntInfoType = uType; + return true; + } + } + } + return false; +} + + +/** + * Gets the description for a VMX abort reason. + * + * @returns The descriptive string. + * @param enmAbort The VMX abort reason. + */ +DECLINLINE(const char *) VMXGetAbortDesc(VMXABORT enmAbort) +{ + switch (enmAbort) + { + case VMXABORT_NONE: return "VMXABORT_NONE"; + case VMXABORT_SAVE_GUEST_MSRS: return "VMXABORT_SAVE_GUEST_MSRS"; + case VMXBOART_HOST_PDPTE: return "VMXBOART_HOST_PDPTE"; + case VMXABORT_CURRENT_VMCS_CORRUPT: return "VMXABORT_CURRENT_VMCS_CORRUPT"; + case VMXABORT_LOAD_HOST_MSR: return "VMXABORT_LOAD_HOST_MSR"; + case VMXABORT_MACHINE_CHECK_XCPT: return "VMXABORT_MACHINE_CHECK_XCPT"; + case VMXABORT_HOST_NOT_IN_LONG_MODE: return "VMXABORT_HOST_NOT_IN_LONG_MODE"; + default: + break; + } + return "Unknown/invalid"; +} + + +/** + * Gets the description for a virtual VMCS state. + * + * @returns The descriptive string. + * @param fVmcsState The virtual-VMCS state. + */ +DECLINLINE(const char *) VMXGetVmcsStateDesc(uint8_t fVmcsState) +{ + switch (fVmcsState) + { + case VMX_V_VMCS_LAUNCH_STATE_CLEAR: return "Clear"; + case VMX_V_VMCS_LAUNCH_STATE_LAUNCHED: return "Launched"; + default: return "Unknown"; + } +} + + +/** + * Gets the description for a VM-entry interruption information event type. + * + * @returns The descriptive string. + * @param uType The event type. + */ +DECLINLINE(const char *) VMXGetEntryIntInfoTypeDesc(uint8_t uType) +{ + switch (uType) + { + case VMX_ENTRY_INT_INFO_TYPE_EXT_INT: return "External Interrupt"; + case VMX_ENTRY_INT_INFO_TYPE_NMI: return "NMI"; + case VMX_ENTRY_INT_INFO_TYPE_HW_XCPT: return "Hardware Exception"; + case VMX_ENTRY_INT_INFO_TYPE_SW_INT: return "Software Interrupt"; + case VMX_ENTRY_INT_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception"; + case VMX_ENTRY_INT_INFO_TYPE_SW_XCPT: return "Software Exception"; + case VMX_ENTRY_INT_INFO_TYPE_OTHER_EVENT: return "Other Event"; + default: + break; + } + return "Unknown/invalid"; +} + + +/** + * Gets the description for a VM-exit interruption information event type. + * + * @returns The descriptive string. + * @param uType The event type. + */ +DECLINLINE(const char *) VMXGetExitIntInfoTypeDesc(uint8_t uType) +{ + switch (uType) + { + case VMX_EXIT_INT_INFO_TYPE_EXT_INT: return "External Interrupt"; + case VMX_EXIT_INT_INFO_TYPE_NMI: return "NMI"; + case VMX_EXIT_INT_INFO_TYPE_HW_XCPT: return "Hardware Exception"; + case VMX_EXIT_INT_INFO_TYPE_SW_INT: return "Software Interrupt"; + case VMX_EXIT_INT_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception"; + case VMX_EXIT_INT_INFO_TYPE_SW_XCPT: return "Software Exception"; + default: + break; + } + return "Unknown/invalid"; +} + + +/** + * Gets the description for an IDT-vectoring information event type. + * + * @returns The descriptive string. + * @param uType The event type. + */ +DECLINLINE(const char *) VMXGetIdtVectoringInfoTypeDesc(uint8_t uType) +{ + switch (uType) + { + case VMX_IDT_VECTORING_INFO_TYPE_EXT_INT: return "External Interrupt"; + case VMX_IDT_VECTORING_INFO_TYPE_NMI: return "NMI"; + case VMX_IDT_VECTORING_INFO_TYPE_HW_XCPT: return "Hardware Exception"; + case VMX_IDT_VECTORING_INFO_TYPE_SW_INT: return "Software Interrupt"; + case VMX_IDT_VECTORING_INFO_TYPE_PRIV_SW_XCPT: return "Priv. Software Exception"; + case VMX_IDT_VECTORING_INFO_TYPE_SW_XCPT: return "Software Exception"; + default: + break; + } + return "Unknown/invalid"; +} + + +/** @} */ + + +/** @defgroup grp_hm_vmx_asm VMX Assembly Helpers + * @{ + */ +#if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86) + +/** + * Dispatches an NMI to the host. + */ +DECLASM(int) VMXDispatchHostNmi(void); + + +/** + * Executes VMXON. + * + * @returns VBox status code. + * @param HCPhysVmxOn Physical address of VMXON structure. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXEnable(RTHCPHYS HCPhysVmxOn); +#else +DECLINLINE(int) VMXEnable(RTHCPHYS HCPhysVmxOn) +{ +# if VMX_USE_MSC_INTRINSICS + unsigned char rcMsc = __vmx_on(&HCPhysVmxOn); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMXON_PTR : VERR_VMX_VMXON_FAILED; + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + int rc; + __asm__ __volatile__ ( + "pushq %2 \n\t" + ".byte 0xf3, 0x0f, 0xc7, 0x34, 0x24 # VMXON [esp] \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_VMXON_FAILED)", %0 \n\t" + "2: \n\t" + "add $8, %%rsp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"(HCPhysVmxOn) /* don't allow direct memory reference here, */ + /* this would not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# else + int rc; + __asm__ __volatile__ ( + "push %3 \n\t" + "push %2 \n\t" + ".byte 0xf3, 0x0f, 0xc7, 0x34, 0x24 # VMXON [esp] \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMXON_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_VMXON_FAILED)", %0 \n\t" + "2: \n\t" + "add $8, %%esp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"((uint32_t)HCPhysVmxOn), /* don't allow direct memory reference here, */ + "ir"((uint32_t)(HCPhysVmxOn >> 32)) /* this would not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + push dword ptr [HCPhysVmxOn + 4] + push dword ptr [HCPhysVmxOn] + _emit 0xf3 + _emit 0x0f + _emit 0xc7 + _emit 0x34 + _emit 0x24 /* VMXON [esp] */ + jnc vmxon_good + mov dword ptr [rc], VERR_VMX_INVALID_VMXON_PTR + jmp the_end + +vmxon_good: + jnz the_end + mov dword ptr [rc], VERR_VMX_VMXON_FAILED +the_end: + add esp, 8 + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMXOFF. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(void) VMXDisable(void); +#else +DECLINLINE(void) VMXDisable(void) +{ +# if VMX_USE_MSC_INTRINSICS + __vmx_off(); + +# elif RT_INLINE_ASM_GNU_STYLE + __asm__ __volatile__ ( + ".byte 0x0f, 0x01, 0xc4 # VMXOFF \n\t" + ); + +# elif defined(RT_ARCH_X86) + __asm + { + _emit 0x0f + _emit 0x01 + _emit 0xc4 /* VMXOFF */ + } + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMCLEAR. + * + * @returns VBox status code. + * @param HCPhysVmcs Physical address of VM control structure. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs); +#else +DECLINLINE(int) VMXClearVmcs(RTHCPHYS HCPhysVmcs) +{ +# if VMX_USE_MSC_INTRINSICS + unsigned char rcMsc = __vmx_vmclear(&HCPhysVmcs); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return VERR_VMX_INVALID_VMCS_PTR; + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + int rc; + __asm__ __volatile__ ( + "pushq %2 \n\t" + ".byte 0x66, 0x0f, 0xc7, 0x34, 0x24 # VMCLEAR [esp] \n\t" + "jnc 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%rsp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"(HCPhysVmcs) /* don't allow direct memory reference here, */ + /* this would not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# else + int rc; + __asm__ __volatile__ ( + "push %3 \n\t" + "push %2 \n\t" + ".byte 0x66, 0x0f, 0xc7, 0x34, 0x24 # VMCLEAR [esp] \n\t" + "jnc 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%esp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */ + "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this would not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + push dword ptr [HCPhysVmcs + 4] + push dword ptr [HCPhysVmcs] + _emit 0x66 + _emit 0x0f + _emit 0xc7 + _emit 0x34 + _emit 0x24 /* VMCLEAR [esp] */ + jnc success + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR +success: + add esp, 8 + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMPTRLD. + * + * @returns VBox status code. + * @param HCPhysVmcs Physical address of VMCS structure. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs); +#else +DECLINLINE(int) VMXLoadVmcs(RTHCPHYS HCPhysVmcs) +{ +# if VMX_USE_MSC_INTRINSICS + unsigned char rcMsc = __vmx_vmptrld(&HCPhysVmcs); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return VERR_VMX_INVALID_VMCS_PTR; + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef RT_ARCH_AMD64 + int rc; + __asm__ __volatile__ ( + "pushq %2 \n\t" + ".byte 0x0f, 0xc7, 0x34, 0x24 # VMPTRLD [esp] \n\t" + "jnc 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%rsp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"(HCPhysVmcs) /* don't allow direct memory reference here, */ + /* this will not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# else + int rc; + __asm__ __volatile__ ( + "push %3 \n\t" + "push %2 \n\t" + ".byte 0x0f, 0xc7, 0x34, 0x24 # VMPTRLD [esp] \n\t" + "jnc 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "1: \n\t" + "add $8, %%esp \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "ir"((uint32_t)HCPhysVmcs), /* don't allow direct memory reference here, */ + "ir"((uint32_t)(HCPhysVmcs >> 32)) /* this will not work with -fomit-frame-pointer */ + :"memory" + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + push dword ptr [HCPhysVmcs + 4] + push dword ptr [HCPhysVmcs] + _emit 0x0f + _emit 0xc7 + _emit 0x34 + _emit 0x24 /* VMPTRLD [esp] */ + jnc success + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR +success: + add esp, 8 + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMPTRST. + * + * @returns VBox status code. + * @param pHCPhysVmcs Where to store the physical address of the current + * VMCS. + */ +DECLASM(int) VMXGetCurrentVmcs(RTHCPHYS *pHCPhysVmcs); + + +/** + * Executes VMWRITE for a 32-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uFieldEnc VMCS field encoding. + * @param u32Val The 32-bit value to set. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val); +#else +DECLINLINE(int) VMXWriteVmcs32(uint32_t uFieldEnc, uint32_t u32Val) +{ +# if VMX_USE_MSC_INTRINSICS +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __vmx_vmwrite(uFieldEnc, u32Val); + return VINF_SUCCESS; +# else + unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u32Val); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD; +# endif + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__ ( + ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t" + : + :"a"(uFieldEnc), + "d"(u32Val) + ); + return VINF_SUCCESS; +# else + int rc; + __asm__ __volatile__ ( + ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "a"(uFieldEnc), + "d"(u32Val) + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + push dword ptr [u32Val] + mov eax, [uFieldEnc] + _emit 0x0f + _emit 0x79 + _emit 0x04 + _emit 0x24 /* VMWRITE eax, [esp] */ + jnc valid_vmcs + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR + jmp the_end +valid_vmcs: + jnz the_end + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD +the_end: + add esp, 4 + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMWRITE for a 64-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uFieldEnc The VMCS field encoding. + * @param u64Val The 16, 32 or 64-bit value to set. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +#if defined(RT_ARCH_X86) || (RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS) +DECLASM(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val); +#else +DECLINLINE(int) VMXWriteVmcs64(uint32_t uFieldEnc, uint64_t u64Val) +{ +# if VMX_USE_MSC_INTRINSICS +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __vmx_vmwrite(uFieldEnc, u64Val); + return VINF_SUCCESS; +# else + unsigned char rcMsc = __vmx_vmwrite(uFieldEnc, u64Val); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD; +# endif + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__ ( + ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t" + : + :"a"(uFieldEnc), + "d"(u64Val) + ); + return VINF_SUCCESS; +# else + int rc; + __asm__ __volatile__ ( + ".byte 0x0f, 0x79, 0xc2 # VMWRITE eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=rm"(rc) + :"0"(VINF_SUCCESS), + "a"(uFieldEnc), + "d"(u64Val) + ); + return rc; +# endif + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMWRITE for a 16-bit VMCS field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uVmcsField The VMCS field. + * @param u16Val The 16-bit value to set. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +DECLINLINE(int) VMXWriteVmcs16(uint32_t uVmcsField, uint16_t u16Val) +{ + AssertMsg(RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH) == VMX_VMCSFIELD_WIDTH_16BIT, ("%#RX32\n", uVmcsField)); + return VMXWriteVmcs32(uVmcsField, u16Val); +} + + +/** + * Executes VMWRITE for a natural-width VMCS field. + */ +#ifdef RT_ARCH_AMD64 +# define VMXWriteVmcsNw VMXWriteVmcs64 +#else +# define VMXWriteVmcsNw VMXWriteVmcs32 +#endif + + +/** + * Invalidate a page using INVEPT. + * + * @returns VBox status code. + * @param enmFlush Type of flush. + * @param pDescriptor Pointer to the descriptor. + */ +DECLASM(int) VMXR0InvEPT(VMXTLBFLUSHEPT enmFlush, uint64_t *pDescriptor); + + +/** + * Invalidate a page using INVVPID. + * + * @returns VBox status code. + * @param enmFlush Type of flush. + * @param pDescriptor Pointer to the descriptor. + */ +DECLASM(int) VMXR0InvVPID(VMXTLBFLUSHVPID enmFlush, uint64_t *pDescriptor); + + +/** + * Executes VMREAD for a 32-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uFieldEnc The VMCS field encoding. + * @param pData Where to store VMCS field value. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +#if RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS +DECLASM(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData); +#else +DECLINLINE(int) VMXReadVmcs32(uint32_t uFieldEnc, uint32_t *pData) +{ +# if VMX_USE_MSC_INTRINSICS +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + uint64_t u64Tmp = 0; + __vmx_vmread(uFieldEnc, &u64Tmp); + *pData = (uint32_t)u64Tmp; + return VINF_SUCCESS; +# else + unsigned char rcMsc; + uint64_t u64Tmp; + rcMsc = __vmx_vmread(uFieldEnc, &u64Tmp); + *pData = (uint32_t)u64Tmp; + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD; +# endif + +# elif VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS + RTCCUINTREG uTmp = 0; +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__("vmread %[uField],%[uDst]" + : [uDst] "=mr" (uTmp) + : [uField] "r" ((RTCCUINTREG)uFieldEnc)); + *pData = (uint32_t)uTmp; + return VINF_SUCCESS; +# else +#if 0 + int rc; + __asm__ __volatile__("vmread %[uField],%[uDst]\n\t" + "movl %[rcSuccess],%[rc]\n\t" +# if VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK + "jna 1f\n\t" + ".section .text.vmread_failures, \"ax?\"\n\t" + "1:\n\t" + "movl %[rcInvalidVmcsPtr],%[rc]\n\t" + "jnz 2f\n\t" + "movl %[rcInvalidVmcsField],%[rc]\n\t" + "2:\n\t" + "jmp 3f\n\t" + ".previous\n\t" + "3:\n\t" +# else + "ja 1f\n\t" + "movl %[rcInvalidVmcsPtr],%[rc]\n\t" + "jnz 1f\n\t" + "movl %[rcInvalidVmcsField],%[rc]\n\t" + "1:\n\t" +# endif + : [uDst] "=mr" (uTmp) + , [rc] "=r" (rc) + : [uField] "r" ((RTCCUINTREG)uFieldEnc) + , [rcSuccess] "i" (VINF_SUCCESS) + , [rcInvalidVmcsPtr] "i" (VERR_VMX_INVALID_VMCS_PTR) + , [rcInvalidVmcsField] "i" (VERR_VMX_INVALID_VMCS_FIELD)); + *pData = uTmp; + return rc; +#else + int fSuccess, fFieldError; + __asm__ __volatile__("vmread %[uField],%[uDst]" + : [uDst] "=mr" (uTmp) + , "=@cca" (fSuccess) + , "=@ccnc" (fFieldError) + : [uField] "r" ((RTCCUINTREG)uFieldEnc)); + *pData = uTmp; + return RT_LIKELY(fSuccess) ? VINF_SUCCESS : fFieldError ? VERR_VMX_INVALID_VMCS_FIELD : VERR_VMX_INVALID_VMCS_PTR; +#endif +# endif + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__ ( + ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t" + :"=d"(*pData) + :"a"(uFieldEnc), + "d"(0) + ); + return VINF_SUCCESS; +# else + int rc; + __asm__ __volatile__ ( + "movl $" RT_XSTR(VINF_SUCCESS)", %0 \n\t" + ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=&r"(rc), + "=d"(*pData) + :"a"(uFieldEnc), + "d"(0) + ); + return rc; +# endif + +# elif defined(RT_ARCH_X86) + int rc = VINF_SUCCESS; + __asm + { + sub esp, 4 + mov dword ptr [esp], 0 + mov eax, [uFieldEnc] + _emit 0x0f + _emit 0x78 + _emit 0x04 + _emit 0x24 /* VMREAD eax, [esp] */ + mov edx, pData + pop dword ptr [edx] + jnc valid_vmcs + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_PTR + jmp the_end +valid_vmcs: + jnz the_end + mov dword ptr [rc], VERR_VMX_INVALID_VMCS_FIELD +the_end: + } + return rc; + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMREAD for a 64-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uFieldEnc The VMCS field encoding. + * @param pData Where to store VMCS field value. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +#if defined(RT_ARCH_X86) || (RT_INLINE_ASM_EXTERNAL && !VMX_USE_MSC_INTRINSICS) +DECLASM(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData); +#else +DECLINLINE(int) VMXReadVmcs64(uint32_t uFieldEnc, uint64_t *pData) +{ +# if VMX_USE_MSC_INTRINSICS +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __vmx_vmread(uFieldEnc, pData); + return VINF_SUCCESS; +# else + unsigned char rcMsc; + rcMsc = __vmx_vmread(uFieldEnc, pData); + if (RT_LIKELY(rcMsc == 0)) + return VINF_SUCCESS; + return rcMsc == 2 ? VERR_VMX_INVALID_VMCS_PTR : VERR_VMX_INVALID_VMCS_FIELD; +# endif + +# elif VMX_USE_GNU_STYLE_INLINE_VMX_INSTRUCTIONS + uint64_t uTmp = 0; +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__("vmreadq %[uField],%[uDst]" + : [uDst] "=m" (uTmp) + : [uField] "r" ((uint64_t)uFieldEnc)); + *pData = uTmp; + return VINF_SUCCESS; +# elif 0 + int rc; + __asm__ __volatile__("vmreadq %[uField],%[uDst]\n\t" + "movl %[rcSuccess],%[rc]\n\t" +# if VMX_USE_GNU_STYLE_INLINE_SECTION_TRICK + "jna 1f\n\t" + ".section .text.vmread_failures, \"ax?\"\n\t" + "1:\n\t" + "movl %[rcInvalidVmcsPtr],%[rc]\n\t" + "jnz 2f\n\t" + "movl %[rcInvalidVmcsField],%[rc]\n\t" + "2:\n\t" + "jmp 3f\n\t" + ".previous\n\t" + "3:\n\t" +# else + "ja 1f\n\t" + "movl %[rcInvalidVmcsPtr],%[rc]\n\t" + "jnz 1f\n\t" + "movl %[rcInvalidVmcsField],%[rc]\n\t" + "1:\n\t" +# endif + : [uDst] "=mr" (uTmp) + , [rc] "=r" (rc) + : [uField] "r" ((uint64_t)uFieldEnc) + , [rcSuccess] "i" (VINF_SUCCESS) + , [rcInvalidVmcsPtr] "i" (VERR_VMX_INVALID_VMCS_PTR) + , [rcInvalidVmcsField] "i" (VERR_VMX_INVALID_VMCS_FIELD) + ); + *pData = uTmp; + return rc; +# else + int fSuccess, fFieldError; + __asm__ __volatile__("vmread %[uField],%[uDst]" + : [uDst] "=mr" (uTmp) + , "=@cca" (fSuccess) + , "=@ccnc" (fFieldError) + : [uField] "r" ((RTCCUINTREG)uFieldEnc)); + *pData = uTmp; + return RT_LIKELY(fSuccess) ? VINF_SUCCESS : fFieldError ? VERR_VMX_INVALID_VMCS_FIELD : VERR_VMX_INVALID_VMCS_PTR; +# endif + +# elif RT_INLINE_ASM_GNU_STYLE +# ifdef VBOX_WITH_VMREAD_VMWRITE_NOCHECK + __asm__ __volatile__ ( + ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t" + :"=d"(*pData) + :"a"(uFieldEnc), + "d"(0) + ); + return VINF_SUCCESS; +# else + int rc; + __asm__ __volatile__ ( + "movl $" RT_XSTR(VINF_SUCCESS)", %0 \n\t" + ".byte 0x0f, 0x78, 0xc2 # VMREAD eax, edx \n\t" + "ja 2f \n\t" + "je 1f \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_PTR)", %0 \n\t" + "jmp 2f \n\t" + "1: \n\t" + "movl $" RT_XSTR(VERR_VMX_INVALID_VMCS_FIELD)", %0 \n\t" + "2: \n\t" + :"=&r"(rc), + "=d"(*pData) + :"a"(uFieldEnc), + "d"(0) + ); + return rc; +# endif + +# else +# error "Shouldn't be here..." +# endif +} +#endif + + +/** + * Executes VMREAD for a 16-bit field. + * + * @returns VBox status code. + * @retval VINF_SUCCESS. + * @retval VERR_VMX_INVALID_VMCS_PTR. + * @retval VERR_VMX_INVALID_VMCS_FIELD. + * + * @param uVmcsField The VMCS field. + * @param pData Where to store VMCS field value. + * + * @remarks The values of the two status codes can be OR'ed together, the result + * will be VERR_VMX_INVALID_VMCS_PTR. + */ +DECLINLINE(int) VMXReadVmcs16(uint32_t uVmcsField, uint16_t *pData) +{ + uint32_t u32Tmp; + int rc; + AssertMsg(RT_BF_GET(uVmcsField, VMX_BF_VMCSFIELD_WIDTH) == VMX_VMCSFIELD_WIDTH_16BIT, ("%#RX32\n", uVmcsField)); + rc = VMXReadVmcs32(uVmcsField, &u32Tmp); + *pData = (uint16_t)u32Tmp; + return rc; +} + + +/** + * Executes VMREAD for a natural-width VMCS field. + */ +#ifdef RT_ARCH_AMD64 +# define VMXReadVmcsNw VMXReadVmcs64 +#else +# define VMXReadVmcsNw VMXReadVmcs32 +#endif + +#endif /* RT_ARCH_AMD64 || RT_ARCH_X86 */ + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_hmvmxinline_h */ + diff --git a/include/VBox/vmm/iem.h b/include/VBox/vmm/iem.h new file mode 100644 index 00000000..ef50970d --- /dev/null +++ b/include/VBox/vmm/iem.h @@ -0,0 +1,422 @@ +/** @file + * IEM - Interpreted Execution Manager. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_iem_h +#define VBOX_INCLUDED_vmm_iem_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#ifdef VBOX_WITH_NESTED_HWVIRT_VMX +# include +#endif +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_iem The Interpreted Execution Manager API. + * @ingroup grp_vmm + * @{ + */ + +/** @name IEMXCPTRAISEINFO_XXX - Extra info. on a recursive exception situation. + * + * This is primarily used by HM for working around a PGM limitation (see + * @bugref{6607}) and special NMI/IRET handling. In the future, this may be + * used for diagnostics. + * + * @{ + */ +typedef uint32_t IEMXCPTRAISEINFO; +/** Pointer to a IEMXCPTINFO type. */ +typedef IEMXCPTRAISEINFO *PIEMXCPTRAISEINFO; +/** No addition info. available. */ +#define IEMXCPTRAISEINFO_NONE RT_BIT_32(0) +/** Delivery of a \#AC caused another \#AC. */ +#define IEMXCPTRAISEINFO_AC_AC RT_BIT_32(1) +/** Delivery of a \#PF caused another \#PF. */ +#define IEMXCPTRAISEINFO_PF_PF RT_BIT_32(2) +/** Delivery of a \#PF caused some contributory exception. */ +#define IEMXCPTRAISEINFO_PF_CONTRIBUTORY_XCPT RT_BIT_32(3) +/** Delivery of an external interrupt caused an exception. */ +#define IEMXCPTRAISEINFO_EXT_INT_XCPT RT_BIT_32(4) +/** Delivery of an external interrupt caused an \#PF. */ +#define IEMXCPTRAISEINFO_EXT_INT_PF RT_BIT_32(5) +/** Delivery of a software interrupt caused an exception. */ +#define IEMXCPTRAISEINFO_SOFT_INT_XCPT RT_BIT_32(6) +/** Delivery of an NMI caused an exception. */ +#define IEMXCPTRAISEINFO_NMI_XCPT RT_BIT_32(7) +/** Delivery of an NMI caused a \#PF. */ +#define IEMXCPTRAISEINFO_NMI_PF RT_BIT_32(8) +/** Can re-execute the instruction at CS:RIP. */ +#define IEMXCPTRAISEINFO_CAN_REEXEC_INSTR RT_BIT_32(9) +/** @} */ + + +/** @name IEMXCPTRAISE_XXX - Ways to handle a recursive exception condition. + * @{ */ +typedef enum IEMXCPTRAISE +{ + /** Raise the current (second) exception. */ + IEMXCPTRAISE_CURRENT_XCPT = 0, + /** Re-raise the previous (first) event (for HM, unused by IEM). */ + IEMXCPTRAISE_PREV_EVENT, + /** Re-execute instruction at CS:RIP (for HM, unused by IEM). */ + IEMXCPTRAISE_REEXEC_INSTR, + /** Raise a \#DF exception. */ + IEMXCPTRAISE_DOUBLE_FAULT, + /** Raise a triple fault. */ + IEMXCPTRAISE_TRIPLE_FAULT, + /** Cause a CPU hang. */ + IEMXCPTRAISE_CPU_HANG, + /** Invalid sequence of events. */ + IEMXCPTRAISE_INVALID = 0x7fffffff +} IEMXCPTRAISE; +/** Pointer to a IEMXCPTRAISE type. */ +typedef IEMXCPTRAISE *PIEMXCPTRAISE; +/** @} */ + + +/** @name Operand or addressing mode. + * @{ */ +typedef uint8_t IEMMODE; +#define IEMMODE_16BIT 0 +#define IEMMODE_32BIT 1 +#define IEMMODE_64BIT 2 +/** @} */ + + +/** @name IEM_XCPT_FLAGS_XXX - flags for iemRaiseXcptOrInt. + * @{ */ +/** CPU exception. */ +#define IEM_XCPT_FLAGS_T_CPU_XCPT RT_BIT_32(0) +/** External interrupt (from PIC, APIC, whatever). */ +#define IEM_XCPT_FLAGS_T_EXT_INT RT_BIT_32(1) +/** Software interrupt (int or into, not bound). + * Returns to the following instruction */ +#define IEM_XCPT_FLAGS_T_SOFT_INT RT_BIT_32(2) +/** Takes an error code. */ +#define IEM_XCPT_FLAGS_ERR RT_BIT_32(3) +/** Takes a CR2. */ +#define IEM_XCPT_FLAGS_CR2 RT_BIT_32(4) +/** Generated by the breakpoint instruction. */ +#define IEM_XCPT_FLAGS_BP_INSTR RT_BIT_32(5) +/** Generated by a DRx instruction breakpoint and RF should be cleared. */ +#define IEM_XCPT_FLAGS_DRx_INSTR_BP RT_BIT_32(6) +/** Generated by the icebp instruction. */ +#define IEM_XCPT_FLAGS_ICEBP_INSTR RT_BIT_32(7) +/** Generated by the overflow instruction. */ +#define IEM_XCPT_FLAGS_OF_INSTR RT_BIT_32(8) +/** @} */ + + +/** @name IEMTARGETCPU_XXX - IEM target CPU specification. + * + * This is a gross simpliciation of CPUMMICROARCH for dealing with really old + * CPUs which didn't have much in the way of hinting at supported instructions + * and features. This slowly changes with the introduction of CPUID with the + * Intel Pentium. + * + * @{ + */ +/** The dynamic target CPU mode is for getting thru the BIOS and then use + * the debugger or modifying instruction behaviour (e.g. HLT) to switch to a + * different target CPU. */ +#define IEMTARGETCPU_DYNAMIC UINT32_C(0) +/** Intel 8086/8088. */ +#define IEMTARGETCPU_8086 UINT32_C(1) +/** NEC V20/V30. + * @remarks must be between 8086 and 80186. */ +#define IEMTARGETCPU_V20 UINT32_C(2) +/** Intel 80186/80188. */ +#define IEMTARGETCPU_186 UINT32_C(3) +/** Intel 80286. */ +#define IEMTARGETCPU_286 UINT32_C(4) +/** Intel 80386. */ +#define IEMTARGETCPU_386 UINT32_C(5) +/** Intel 80486. */ +#define IEMTARGETCPU_486 UINT32_C(6) +/** Intel Pentium . */ +#define IEMTARGETCPU_PENTIUM UINT32_C(7) +/** Intel PentiumPro. */ +#define IEMTARGETCPU_PPRO UINT32_C(8) +/** A reasonably current CPU, probably newer than the pentium pro when it comes + * to the feature set and behaviour. Generally the CPUID info and CPU vendor + * dicates the behaviour here. */ +#define IEMTARGETCPU_CURRENT UINT32_C(9) +/** @} */ + + +/** @name IEM status codes. + * + * Not quite sure how this will play out in the end, just aliasing safe status + * codes for now. + * + * @{ */ +#define VINF_IEM_RAISED_XCPT VINF_EM_RESCHEDULE +/** @} */ + + +/** The CPUMCTX_EXTRN_XXX mask required to be cleared when interpreting anything. + * IEM will ASSUME the caller of IEM APIs has ensured these are already present. */ +#define IEM_CPUMCTX_EXTRN_MUST_MASK ( CPUMCTX_EXTRN_GPRS_MASK \ + | CPUMCTX_EXTRN_RIP \ + | CPUMCTX_EXTRN_RFLAGS \ + | CPUMCTX_EXTRN_SS \ + | CPUMCTX_EXTRN_CS \ + | CPUMCTX_EXTRN_CR0 \ + | CPUMCTX_EXTRN_CR3 \ + | CPUMCTX_EXTRN_CR4 \ + | CPUMCTX_EXTRN_APIC_TPR \ + | CPUMCTX_EXTRN_EFER \ + | CPUMCTX_EXTRN_DR7 ) +/** The CPUMCTX_EXTRN_XXX mask needed when injecting an exception/interrupt. + * IEM will import missing bits, callers are encouraged to make these registers + * available prior to injection calls if fetching state anyway. */ +#define IEM_CPUMCTX_EXTRN_XCPT_MASK ( IEM_CPUMCTX_EXTRN_MUST_MASK \ + | CPUMCTX_EXTRN_CR2 \ + | CPUMCTX_EXTRN_SREG_MASK \ + | CPUMCTX_EXTRN_TABLE_MASK ) +/** The CPUMCTX_EXTRN_XXX mask required to be cleared when calling any + * IEMExecDecoded API not using memory. IEM will ASSUME the caller of IEM + * APIs has ensured these are already present. + * @note ASSUMES execution engine has checked for instruction breakpoints + * during decoding. */ +#define IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK ( CPUMCTX_EXTRN_RIP \ + | CPUMCTX_EXTRN_RFLAGS \ + | CPUMCTX_EXTRN_SS /* for CPL */ \ + | CPUMCTX_EXTRN_CS /* for mode */ \ + | CPUMCTX_EXTRN_CR0 /* for mode */ \ + | CPUMCTX_EXTRN_EFER /* for mode */ ) +/** The CPUMCTX_EXTRN_XXX mask required to be cleared when calling any + * IEMExecDecoded API using memory. IEM will ASSUME the caller of IEM + * APIs has ensured these are already present. + * @note ASSUMES execution engine has checked for instruction breakpoints + * during decoding. */ +#define IEM_CPUMCTX_EXTRN_EXEC_DECODED_MEM_MASK ( IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK \ + | CPUMCTX_EXTRN_CR3 /* for page tables */ \ + | CPUMCTX_EXTRN_CR4 /* for mode paging mode */ \ + | CPUMCTX_EXTRN_DR7 /* for memory breakpoints */ ) + +#ifdef VBOX_WITH_NESTED_HWVIRT_VMX +/** The CPUMCTX_EXTRN_XXX mask needed when calling IEMExecDecodedVmlaunchVmresume(). + * IEM will ASSUME the caller has ensured these are already present. */ +# define IEM_CPUMCTX_EXTRN_VMX_VMENTRY_MASK ( IEM_CPUMCTX_EXTRN_EXEC_DECODED_NO_MEM_MASK \ + | CPUMCTX_EXTRN_CR2 \ + | CPUMCTX_EXTRN_HWVIRT ) + +/** The CPUMCTX_EXTRN_XXX mask that the IEM VM-exit code will import on-demand when + * needed, primarily because there are several IEM VM-exit interface functions and + * some of which may not cause a VM-exit at all. + * + * This is currently unused, but keeping it here in case we can get away a bit more + * fine-grained state handling. + * + * @note Update HM_CHANGED_VMX_VMEXIT_MASK if something here changes. */ +# define IEM_CPUMCTX_EXTRN_VMX_VMEXIT_MASK ( CPUMCTX_EXTRN_CR0 | CPUMCTX_EXTRN_CR3 | CPUMCTX_EXTRN_CR4 \ + | CPUMCTX_EXTRN_DR7 | CPUMCTX_EXTRN_DR6 \ + | CPUMCTX_EXTRN_EFER \ + | CPUMCTX_EXTRN_SYSENTER_MSRS \ + | CPUMCTX_EXTRN_OTHER_MSRS /* for PAT MSR */ \ + | CPUMCTX_EXTRN_RIP | CPUMCTX_EXTRN_RSP | CPUMCTX_EXTRN_RFLAGS \ + | CPUMCTX_EXTRN_SREG_MASK \ + | CPUMCTX_EXTRN_TR \ + | CPUMCTX_EXTRN_LDTR | CPUMCTX_EXTRN_GDTR | CPUMCTX_EXTRN_IDTR \ + | CPUMCTX_EXTRN_HWVIRT ) +#endif + +#ifdef VBOX_WITH_NESTED_HWVIRT_SVM +/** The CPUMCTX_EXTRN_XXX mask needed when calling IEMExecSvmVmexit(). + * IEM will ASSUME the caller has ensured these are already present. */ +# define IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK ( CPUMCTX_EXTRN_RSP \ + | CPUMCTX_EXTRN_RAX \ + | CPUMCTX_EXTRN_RIP \ + | CPUMCTX_EXTRN_RFLAGS \ + | CPUMCTX_EXTRN_CS \ + | CPUMCTX_EXTRN_SS \ + | CPUMCTX_EXTRN_DS \ + | CPUMCTX_EXTRN_ES \ + | CPUMCTX_EXTRN_GDTR \ + | CPUMCTX_EXTRN_IDTR \ + | CPUMCTX_EXTRN_CR_MASK \ + | CPUMCTX_EXTRN_EFER \ + | CPUMCTX_EXTRN_DR6 \ + | CPUMCTX_EXTRN_DR7 \ + | CPUMCTX_EXTRN_OTHER_MSRS \ + | CPUMCTX_EXTRN_HWVIRT \ + | CPUMCTX_EXTRN_APIC_TPR \ + | CPUMCTX_EXTRN_HM_SVM_HWVIRT_VIRQ) + +/** The CPUMCTX_EXTRN_XXX mask needed when calling IEMExecDecodedVmrun(). + * IEM will ASSUME the caller has ensured these are already present. */ +# define IEM_CPUMCTX_EXTRN_SVM_VMRUN_MASK IEM_CPUMCTX_EXTRN_SVM_VMEXIT_MASK +#endif + +VMMDECL(VBOXSTRICTRC) IEMExecOne(PVMCPUCC pVCpu); +VMMDECL(VBOXSTRICTRC) IEMExecOneEx(PVMCPUCC pVCpu, uint32_t *pcbWritten); +VMMDECL(VBOXSTRICTRC) IEMExecOneWithPrefetchedByPC(PVMCPUCC pVCpu, uint64_t OpcodeBytesPC, + const void *pvOpcodeBytes, size_t cbOpcodeBytes); +VMMDECL(VBOXSTRICTRC) IEMExecOneBypassEx(PVMCPUCC pVCpu, uint32_t *pcbWritten); +VMMDECL(VBOXSTRICTRC) IEMExecOneBypassWithPrefetchedByPC(PVMCPUCC pVCpu, uint64_t OpcodeBytesPC, + const void *pvOpcodeBytes, size_t cbOpcodeBytes); +VMMDECL(VBOXSTRICTRC) IEMExecOneIgnoreLock(PVMCPUCC pVCpu); +VMMDECL(VBOXSTRICTRC) IEMExecLots(PVMCPUCC pVCpu, uint32_t cMaxInstructions, uint32_t cPollRate, uint32_t *pcInstructions); +/** Statistics returned by IEMExecForExits. */ +typedef struct IEMEXECFOREXITSTATS +{ + uint32_t cInstructions; + uint32_t cExits; + uint32_t cMaxExitDistance; + uint32_t cReserved; +} IEMEXECFOREXITSTATS; +/** Pointer to statistics returned by IEMExecForExits. */ +typedef IEMEXECFOREXITSTATS *PIEMEXECFOREXITSTATS; +VMMDECL(VBOXSTRICTRC) IEMExecForExits(PVMCPUCC pVCpu, uint32_t fWillExit, uint32_t cMinInstructions, uint32_t cMaxInstructions, + uint32_t cMaxInstructionsWithoutExits, PIEMEXECFOREXITSTATS pStats); +VMMDECL(VBOXSTRICTRC) IEMInjectTrpmEvent(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMInjectTrap(PVMCPUCC pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType, uint16_t uErrCode, RTGCPTR uCr2, + uint8_t cbInstr); + +VMM_INT_DECL(int) IEMBreakpointSet(PVM pVM, RTGCPTR GCPtrBp); +VMM_INT_DECL(int) IEMBreakpointClear(PVM pVM, RTGCPTR GCPtrBp); + +VMM_INT_DECL(void) IEMTlbInvalidateAll(PVMCPUCC pVCpu); +VMM_INT_DECL(void) IEMTlbInvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCPtr); +VMM_INT_DECL(void) IEMTlbInvalidateAllPhysical(PVMCPUCC pVCpu); +VMM_INT_DECL(void) IEMTlbInvalidateAllPhysicalAllCpus(PVMCC pVM, VMCPUID idCpuCaller); +VMM_INT_DECL(bool) IEMGetCurrentXcpt(PVMCPUCC pVCpu, uint8_t *puVector, uint32_t *pfFlags, uint32_t *puErr, + uint64_t *puCr2); +VMM_INT_DECL(IEMXCPTRAISE) IEMEvaluateRecursiveXcpt(PVMCPUCC pVCpu, uint32_t fPrevFlags, uint8_t uPrevVector, uint32_t fCurFlags, + uint8_t uCurVector, PIEMXCPTRAISEINFO pXcptRaiseInfo); + +/** @name Given Instruction Interpreters + * @{ */ +VMM_INT_DECL(VBOXSTRICTRC) IEMExecStringIoWrite(PVMCPUCC pVCpu, uint8_t cbValue, IEMMODE enmAddrMode, + bool fRepPrefix, uint8_t cbInstr, uint8_t iEffSeg, bool fIoChecked); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecStringIoRead(PVMCPUCC pVCpu, uint8_t cbValue, IEMMODE enmAddrMode, + bool fRepPrefix, uint8_t cbInstr, bool fIoChecked); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedOut(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t u16Port, bool fImm, uint8_t cbReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedIn(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t u16Port, bool fImm, uint8_t cbReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMovCRxWrite(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iCrReg, uint8_t iGReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMovCRxRead(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iGReg, uint8_t iCrReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMovDRxWrite(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iDrReg, uint8_t iGReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMovDRxRead(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iGReg, uint8_t iDrReg); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedClts(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedLmsw(PVMCPUCC pVCpu, uint8_t cbInstr, uint16_t uValue, RTGCPTR GCPtrEffDst); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedXsetbv(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedWbinvd(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvd(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvlpg(PVMCPUCC pVCpu, uint8_t cbInstr, RTGCPTR GCPtrPage); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvpcid(PVMCPUCC pVCpu, uint8_t cbInstr, uint8_t iEffSeg, RTGCPTR GCPtrDesc, + uint64_t uType); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedCpuid(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedRdpmc(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedRdtsc(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedRdtscp(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedRdmsr(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedWrmsr(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMonitor(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedMwait(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedHlt(PVMCPUCC pVCpu, uint8_t cbInstr); + +#ifdef VBOX_WITH_NESTED_HWVIRT_SVM +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedClgi(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedStgi(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmload(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmsave(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvlpga(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmrun(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecSvmVmexit(PVMCPUCC pVCpu, uint64_t uExitCode, uint64_t uExitInfo1, uint64_t uExitInfo2); +#endif + +#ifdef VBOX_WITH_NESTED_HWVIRT_VMX +VMM_INT_DECL(void) IEMReadVmxVmcsField(PCVMXVVMCS pVmcs, uint64_t u64VmcsField, uint64_t *pu64Dst); +VMM_INT_DECL(void) IEMWriteVmxVmcsField(PVMXVVMCS pVmcs, uint64_t u64VmcsField, uint64_t u64Val); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVirtApicAccessMsr(PVMCPUCC pVCpu, uint32_t idMsr, uint64_t *pu64Val, bool fWrite); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitApicWrite(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitPreemptTimer(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitExtInt(PVMCPUCC pVCpu, uint8_t uVector, bool fIntPending); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitXcpt(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo, PCVMXVEXITEVENTINFO pExitEventInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitXcptNmi(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitTripleFault(PVMCPUCC pVCpu); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitStartupIpi(PVMCPUCC pVCpu, uint8_t uVector); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitInstrWithInfo(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitInstr(PVMCPUCC pVCpu, uint32_t uExitReason, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitTrapLike(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitTaskSwitch(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo, PCVMXVEXITEVENTINFO pExitEventInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitApicAccess(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo, PCVMXVEXITEVENTINFO pExitEventInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexit(PVMCPUCC pVCpu, uint32_t uExitReason, uint64_t uExitQual); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmread(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmwrite(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmptrld(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmptrst(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmclear(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmlaunchVmresume(PVMCPUCC pVCpu, uint8_t cbInstr, VMXINSTRID uInstrId); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmxon(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedVmxoff(PVMCPUCC pVCpu, uint8_t cbInstr); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvvpid(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT +VMM_INT_DECL(VBOXSTRICTRC) IEMExecDecodedInvept(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitEptViolation(PVMCPUCC pVCpu, PCVMXVEXITINFO pExitInfo, PCVMXVEXITEVENTINFO pExitEventInfo); +VMM_INT_DECL(VBOXSTRICTRC) IEMExecVmxVmexitEptMisconfig(PVMCPUCC pVCpu, RTGCPHYS GCPhysAddr, PCVMXVEXITEVENTINFO pExitEventInfo); +# endif +#endif +/** @} */ + +/** @defgroup grp_iem_r3 The IEM Host Context Ring-3 API. + * @{ + */ +VMMR0_INT_DECL(int) IEMR0InitVM(PGVM pGVM); +/** @} */ + + +/** @defgroup grp_iem_r3 The IEM Host Context Ring-3 API. + * @{ + */ +VMMR3DECL(int) IEMR3Init(PVM pVM); +VMMR3DECL(int) IEMR3Term(PVM pVM); +VMMR3DECL(void) IEMR3Relocate(PVM pVM); +VMMR3_INT_DECL(VBOXSTRICTRC) IEMR3ProcessForceFlag(PVM pVM, PVMCPUCC pVCpu, VBOXSTRICTRC rcStrict); +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_iem_h */ + diff --git a/include/VBox/vmm/iom.h b/include/VBox/vmm/iom.h new file mode 100644 index 00000000..a2ff5891 --- /dev/null +++ b/include/VBox/vmm/iom.h @@ -0,0 +1,550 @@ +/** @file + * IOM - Input / Output Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_iom_h +#define VBOX_INCLUDED_vmm_iom_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_iom The Input / Ouput Monitor API + * @ingroup grp_vmm + * @{ + */ + +/** @def IOM_NO_PDMINS_CHECKS + * Until all devices have been fully adjusted to PDM style, the pPdmIns + * parameter is not checked by IOM. + * @todo Check this again, now. + */ +#define IOM_NO_PDMINS_CHECKS + +/** + * Macro for checking if an I/O or MMIO emulation call succeeded. + * + * This macro shall only be used with the IOM APIs where it's mentioned + * in the return value description. And there it must be used to correctly + * determine if the call succeeded and things like the RIP needs updating. + * + * + * @returns Success indicator (true/false). + * + * @param rc The status code. This may be evaluated + * more than once! + * + * @remarks To avoid making assumptions about the layout of the + * VINF_EM_FIRST...VINF_EM_LAST range we're checking explicitly for + * each exact exception. However, for efficiency we ASSUME that the + * VINF_EM_LAST is smaller than most of the relevant status codes. We + * also ASSUME that the VINF_EM_RESCHEDULE_REM status code is the + * most frequent status code we'll enounter in this range. + * + * @todo Will have to add VINF_EM_DBG_HYPER_BREAKPOINT if the + * I/O port and MMIO breakpoints should trigger before + * the I/O is done. Currently, we don't implement these + * kind of breakpoints. + */ +#ifdef IN_RING3 +# define IOM_SUCCESS(rc) ( (rc) == VINF_SUCCESS \ + || ( (rc) <= VINF_EM_LAST \ + && (rc) != VINF_EM_RESCHEDULE_REM \ + && (rc) >= VINF_EM_FIRST \ + && (rc) != VINF_EM_RESCHEDULE_RAW \ + && (rc) != VINF_EM_RESCHEDULE_HM \ + ) \ + ) +#else +# define IOM_SUCCESS(rc) ( (rc) == VINF_SUCCESS \ + || ( (rc) <= VINF_EM_LAST \ + && (rc) != VINF_EM_RESCHEDULE_REM \ + && (rc) >= VINF_EM_FIRST \ + && (rc) != VINF_EM_RESCHEDULE_RAW \ + && (rc) != VINF_EM_RESCHEDULE_HM \ + ) \ + || (rc) == VINF_IOM_R3_IOPORT_COMMIT_WRITE \ + || (rc) == VINF_IOM_R3_MMIO_COMMIT_WRITE \ + ) +#endif + +/** @name IOMMMIO_FLAGS_XXX + * @{ */ +/** Pass all reads thru unmodified. */ +#define IOMMMIO_FLAGS_READ_PASSTHRU UINT32_C(0x00000000) +/** All read accesses are DWORD sized (32-bit). */ +#define IOMMMIO_FLAGS_READ_DWORD UINT32_C(0x00000001) +/** All read accesses are DWORD (32-bit) or QWORD (64-bit) sized. + * Only accesses that are both QWORD sized and aligned are performed as QWORD. + * All other access will be done DWORD fashion (because it is way simpler). */ +#define IOMMMIO_FLAGS_READ_DWORD_QWORD UINT32_C(0x00000002) +/** The read access mode mask. */ +#define IOMMMIO_FLAGS_READ_MODE UINT32_C(0x00000003) + +/** Pass all writes thru unmodified. */ +#define IOMMMIO_FLAGS_WRITE_PASSTHRU UINT32_C(0x00000000) +/** All write accesses are DWORD (32-bit) sized and unspecified bytes are + * written as zero. */ +#define IOMMMIO_FLAGS_WRITE_DWORD_ZEROED UINT32_C(0x00000010) +/** All write accesses are either DWORD (32-bit) or QWORD (64-bit) sized, + * missing bytes will be written as zero. Only accesses that are both QWORD + * sized and aligned are performed as QWORD, all other accesses will be done + * DWORD fashion (because it's way simpler). */ +#define IOMMMIO_FLAGS_WRITE_DWORD_QWORD_ZEROED UINT32_C(0x00000020) +/** All write accesses are DWORD (32-bit) sized and unspecified bytes are + * read from the device first as DWORDs. + * @remarks This isn't how it happens on real hardware, but it allows + * simplifications of devices where reads doesn't change the device + * state in any way. */ +#define IOMMMIO_FLAGS_WRITE_DWORD_READ_MISSING UINT32_C(0x00000030) +/** All write accesses are DWORD (32-bit) or QWORD (64-bit) sized and + * unspecified bytes are read from the device first as DWORDs. Only accesses + * that are both QWORD sized and aligned are performed as QWORD, all other + * accesses will be done DWORD fashion (because it's way simpler). + * @remarks This isn't how it happens on real hardware, but it allows + * simplifications of devices where reads doesn't change the device + * state in any way. */ +#define IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING UINT32_C(0x00000040) +/** All write accesses are DWORD (32-bit) sized and aligned, attempts at other + * accesses are ignored. + * @remarks E1000, APIC */ +#define IOMMMIO_FLAGS_WRITE_ONLY_DWORD UINT32_C(0x00000050) +/** All write accesses are DWORD (32-bit) or QWORD (64-bit) sized and aligned, + * attempts at other accesses are ignored. + * @remarks Seemingly required by AHCI (although I doubt it's _really_ + * required as EM/REM doesn't do the right thing in ring-3 anyway, + * esp. not in raw-mode). */ +#define IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD UINT32_C(0x00000060) +/** The read access mode mask. */ +#define IOMMMIO_FLAGS_WRITE_MODE UINT32_C(0x00000070) + +/** Whether to do a DBGSTOP on complicated reads. + * What this includes depends on the read mode, but generally all misaligned + * reads as well as word and byte reads and maybe qword reads. */ +#define IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_READ UINT32_C(0x00000100) +/** Whether to do a DBGSTOP on complicated writes. + * This depends on the write mode, but generally all writes where we have to + * supply bytes (zero them or read them). */ +#define IOMMMIO_FLAGS_DBGSTOP_ON_COMPLICATED_WRITE UINT32_C(0x00000200) + +/** Pass the absolute physical address (GC) to the callback rather than the + * relative one. + * @note New-style only, is implicit in old-style interface. */ +#define IOMMMIO_FLAGS_ABS UINT32_C(0x00001000) + +/** Mask of valid flags. */ +#define IOMMMIO_FLAGS_VALID_MASK UINT32_C(0x00001373) +/** @} */ + +/** + * Checks whether the write mode allows aligned QWORD accesses to be passed + * thru to the device handler. + * @param a_fFlags The MMIO handler flags. + */ +#define IOMMMIO_DOES_WRITE_MODE_ALLOW_QWORD(a_fFlags) \ + ( ((a_fFlags) & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_QWORD_ZEROED \ + || ((a_fFlags) & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_DWORD_QWORD_READ_MISSING \ + || ((a_fFlags) & IOMMMIO_FLAGS_WRITE_MODE) == IOMMMIO_FLAGS_WRITE_ONLY_DWORD_QWORD ) + + +/** + * Port I/O Handler for IN operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * @returns VERR_IOM_IOPORT_UNUSED if the port is really unused and a ~0 value should be returned. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param uPort Port number used for the IN operation. + * @param pu32 Where to store the result. This is always a 32-bit + * variable regardless of what @a cb might say. + * @param cb Number of bytes read. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMIOPORTIN,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t *pu32, unsigned cb)); +/** Pointer to a FNIOMIOPORTIN(). */ +typedef FNIOMIOPORTIN *PFNIOMIOPORTIN; + +/** + * Port I/O Handler for string IN operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * @returns VERR_IOM_IOPORT_UNUSED if the port is really unused and a ~0 value should be returned. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param uPort Port number used for the IN operation. + * @param pbDst Pointer to the destination buffer. + * @param pcTransfers Pointer to the number of transfer units to read, on + * return remaining transfer units. + * @param cb Size of the transfer unit (1, 2 or 4 bytes). + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMIOPORTINSTRING,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint8_t *pbDst, + uint32_t *pcTransfers, unsigned cb)); +/** Pointer to a FNIOMIOPORTINSTRING(). */ +typedef FNIOMIOPORTINSTRING *PFNIOMIOPORTINSTRING; + +/** + * Port I/O Handler for OUT operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param uPort Port number used for the OUT operation. + * @param u32 The value to output. + * @param cb The value size in bytes. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMIOPORTOUT,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, uint32_t u32, unsigned cb)); +/** Pointer to a FNIOMIOPORTOUT(). */ +typedef FNIOMIOPORTOUT *PFNIOMIOPORTOUT; + +/** + * Port I/O Handler for string OUT operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param uPort Port number used for the OUT operation. + * @param pbSrc Pointer to the source buffer. + * @param pcTransfers Pointer to the number of transfer units to write, on + * return remaining transfer units. + * @param cb Size of the transfer unit (1, 2 or 4 bytes). + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMIOPORTOUTSTRING,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT uPort, const uint8_t *pbSrc, + uint32_t *pcTransfers, unsigned cb)); +/** Pointer to a FNIOMIOPORTOUTSTRING(). */ +typedef FNIOMIOPORTOUTSTRING *PFNIOMIOPORTOUTSTRING; + + +/** + * Port I/O Handler for IN operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * @returns VERR_IOM_IOPORT_UNUSED if the port is really unused and a ~0 value should be returned. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param offPort The port number if IOM_IOPORT_F_ABS is used, otherwise + * relative to the mapping base. + * @param pu32 Where to store the result. This is always a 32-bit + * variable regardless of what @a cb might say. + * @param cb Number of bytes read. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMIOPORTNEWIN,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, + uint32_t *pu32, unsigned cb)); +/** Pointer to a FNIOMIOPORTNEWIN(). */ +typedef FNIOMIOPORTNEWIN *PFNIOMIOPORTNEWIN; + +/** + * Port I/O Handler for string IN operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * @returns VERR_IOM_IOPORT_UNUSED if the port is really unused and a ~0 value should be returned. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param offPort The port number if IOM_IOPORT_F_ABS is used, otherwise + * relative to the mapping base. + * @param pbDst Pointer to the destination buffer. + * @param pcTransfers Pointer to the number of transfer units to read, on + * return remaining transfer units. + * @param cb Size of the transfer unit (1, 2 or 4 bytes). + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMIOPORTNEWINSTRING,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, uint8_t *pbDst, + uint32_t *pcTransfers, unsigned cb)); +/** Pointer to a FNIOMIOPORTNEWINSTRING(). */ +typedef FNIOMIOPORTNEWINSTRING *PFNIOMIOPORTNEWINSTRING; + +/** + * Port I/O Handler for OUT operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param offPort The port number if IOM_IOPORT_F_ABS is used, otherwise + * relative to the mapping base. + * @param u32 The value to output. + * @param cb The value size in bytes. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMIOPORTNEWOUT,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, + uint32_t u32, unsigned cb)); +/** Pointer to a FNIOMIOPORTNEWOUT(). */ +typedef FNIOMIOPORTNEWOUT *PFNIOMIOPORTNEWOUT; + +/** + * Port I/O Handler for string OUT operations. + * + * @returns VINF_SUCCESS or VINF_EM_*. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param offPort The port number if IOM_IOPORT_F_ABS is used, otherwise + * relative to the mapping base. + * @param pbSrc Pointer to the source buffer. + * @param pcTransfers Pointer to the number of transfer units to write, on + * return remaining transfer units. + * @param cb Size of the transfer unit (1, 2 or 4 bytes). + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMIOPORTNEWOUTSTRING,(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT offPort, + const uint8_t *pbSrc, uint32_t *pcTransfers, unsigned cb)); +/** Pointer to a FNIOMIOPORTNEWOUTSTRING(). */ +typedef FNIOMIOPORTNEWOUTSTRING *PFNIOMIOPORTNEWOUTSTRING; + +/** + * I/O port description. + * + * If both pszIn and pszOut are NULL, the entry is considered a terminator. + */ +typedef struct IOMIOPORTDESC +{ + /** Brief description / name of the IN port. */ + const char *pszIn; + /** Brief description / name of the OUT port. */ + const char *pszOut; + /** Detailed description of the IN port, optional. */ + const char *pszInDetail; + /** Detialed description of the OUT port, optional. */ + const char *pszOutDetail; +} IOMIOPORTDESC; +/** Pointer to an I/O port description. */ +typedef IOMIOPORTDESC const *PCIOMIOPORTDESC; + + +/** + * Memory mapped I/O Handler for read operations. + * + * @returns VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param GCPhysAddr Physical address (in GC) where the read starts. + * @param pv Where to store the result. + * @param cb Number of bytes read. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMMMIOREAD,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void *pv, unsigned cb)); +/** Pointer to a FNIOMMMIOREAD(). */ +typedef FNIOMMMIOREAD *PFNIOMMMIOREAD; + +/** + * Memory mapped I/O Handler for write operations. + * + * @returns VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param GCPhysAddr Physical address (in GC) where the read starts. + * @param pv Where to fetch the result. + * @param cb Number of bytes to write. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMMMIOWRITE,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, void const *pv, unsigned cb)); +/** Pointer to a FNIOMMMIOWRITE(). */ +typedef FNIOMMMIOWRITE *PFNIOMMMIOWRITE; + +/** + * Memory mapped I/O Handler for memset operations, actually for REP STOS* instructions handling. + * + * @returns VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param GCPhysAddr Physical address (in GC) where the write starts. + * @param u32Item Byte/Word/Dword data to fill. + * @param cbItem Size of data in u32Item parameter, restricted to 1/2/4 bytes. + * @param cItems Number of iterations. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNIOMMMIOFILL,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS GCPhysAddr, + uint32_t u32Item, unsigned cbItem, unsigned cItems)); +/** Pointer to a FNIOMMMIOFILL(). */ +typedef FNIOMMMIOFILL *PFNIOMMMIOFILL; + + +/** + * Memory mapped I/O Handler for read operations. + * + * @returns Strict VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param off Offset into the mapping of the read, + * or the physical address if IOMMMIO_FLAGS_ABS is active. + * @param pv Where to store the result. + * @param cb Number of bytes read. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMMMIONEWREAD,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, uint32_t cb)); +/** Pointer to a FNIOMMMIONEWREAD(). */ +typedef FNIOMMMIONEWREAD *PFNIOMMMIONEWREAD; + +/** + * Memory mapped I/O Handler for write operations. + * + * @returns Strict VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param off Offset into the mapping of the write, + * or the physical address if IOMMMIO_FLAGS_ABS is active. + * @param pv Where to fetch the result. + * @param cb Number of bytes to write. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMMMIONEWWRITE,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, + void const *pv, uint32_t cb)); +/** Pointer to a FNIOMMMIONEWWRITE(). */ +typedef FNIOMMMIONEWWRITE *PFNIOMMMIONEWWRITE; + +/** + * Memory mapped I/O Handler for memset operations, actually for REP STOS* instructions handling. + * + * @returns Strict VBox status code. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param off Offset into the mapping of the fill, + * or the physical address if IOMMMIO_FLAGS_ABS is active. + * @param u32Item Byte/Word/Dword data to fill. + * @param cbItem Size of data in u32Item parameter, restricted to 1/2/4 bytes. + * @param cItems Number of iterations. + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNIOMMMIONEWFILL,(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, + uint32_t u32Item, uint32_t cbItem, uint32_t cItems)); +/** Pointer to a FNIOMMMIONEWFILL(). */ +typedef FNIOMMMIONEWFILL *PFNIOMMMIONEWFILL; + +VMMDECL(VBOXSTRICTRC) IOMIOPortRead(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t *pu32Value, size_t cbValue); +VMMDECL(VBOXSTRICTRC) IOMIOPortWrite(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, uint32_t u32Value, size_t cbValue); +VMM_INT_DECL(VBOXSTRICTRC) IOMIOPortReadString(PVMCC pVM, PVMCPU pVCpu, RTIOPORT Port, void *pvDst, + uint32_t *pcTransfers, unsigned cb); +VMM_INT_DECL(VBOXSTRICTRC) IOMIOPortWriteString(PVMCC pVM, PVMCPU pVCpu, RTIOPORT uPort, void const *pvSrc, + uint32_t *pcTransfers, unsigned cb); +VMM_INT_DECL(VBOXSTRICTRC) IOMR0MmioPhysHandler(PVMCC pVM, PVMCPUCC pVCpu, uint32_t uErrorCode, RTGCPHYS GCPhysFault); +VMMDECL(int) IOMMmioMapMmio2Page(PVMCC pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion, + uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags); +VMMR0_INT_DECL(int) IOMR0MmioMapMmioHCPage(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint64_t fPageFlags); +VMMDECL(int) IOMMmioResetRegion(PVMCC pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion); + + +/** @name IOM_IOPORT_F_XXX - Flags for IOMR3IoPortCreate() and PDMDevHlpIoPortCreateEx(). + * @{ */ +/** Pass the absolute I/O port to the callback rather than the relative one. */ +#define IOM_IOPORT_F_ABS RT_BIT_32(0) +/** Valid flags for IOMR3IoPortCreate(). */ +#define IOM_IOPORT_F_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +#ifdef IN_RING3 +/** @defgroup grp_iom_r3 The IOM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) IOMR3Init(PVM pVM); +VMMR3_INT_DECL(int) IOMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3_INT_DECL(void) IOMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) IOMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) IOMR3Term(PVM pVM); + +VMMR3_INT_DECL(int) IOMR3IoPortCreate(PVM pVM, PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev, + uint32_t iPciRegion, PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, RTR3PTR pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts); +VMMR3_INT_DECL(int) IOMR3IoPortMap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, RTIOPORT Port); +VMMR3_INT_DECL(int) IOMR3IoPortUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts); +VMMR3_INT_DECL(int) IOMR3IoPortValidateHandle(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts); +VMMR3_INT_DECL(uint32_t) IOMR3IoPortGetMappingAddress(PVM pVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts); + +VMMR3_INT_DECL(int) IOMR3MmioCreate(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS cbRegion, uint32_t fFlags, PPDMPCIDEV pPciDev, + uint32_t iPciRegion, PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, + PFNIOMMMIONEWFILL pfnFill, void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion); +VMMR3_INT_DECL(int) IOMR3MmioMap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys); +VMMR3_INT_DECL(int) IOMR3MmioUnmap(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion); +VMMR3_INT_DECL(int) IOMR3MmioReduce(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion); +VMMR3_INT_DECL(int) IOMR3MmioValidateHandle(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion); +VMMR3_INT_DECL(RTGCPHYS) IOMR3MmioGetMappingAddress(PVM pVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion); + +VMMR3_INT_DECL(VBOXSTRICTRC) IOMR3ProcessForceFlag(PVM pVM, PVMCPU pVCpu, VBOXSTRICTRC rcStrict); + +VMMR3_INT_DECL(void) IOMR3NotifyBreakpointCountChange(PVM pVM, bool fPortIo, bool fMmio); +VMMR3_INT_DECL(void) IOMR3NotifyDebugEventChange(PVM pVM, DBGFEVENT enmEvent, bool fEnabled); +/** @} */ +#endif /* IN_RING3 */ + + +#if defined(IN_RING0) || defined(DOXYGEN_RUNNING) +/** @defgroup grpm_iom_r0 The IOM Host Context Ring-0 API + * @{ */ +VMMR0_INT_DECL(void) IOMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(int) IOMR0InitVM(PGVM pGVM); +VMMR0_INT_DECL(void) IOMR0CleanupVM(PGVM pGVM); + +VMMR0_INT_DECL(int) IOMR0IoPortSetUpContext(PGVM pGVM, PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, void *pvUser); +VMMR0_INT_DECL(int) IOMR0IoPortGrowRegistrationTables(PGVM pGVM, uint64_t cMinEntries); +VMMR0_INT_DECL(int) IOMR0IoPortGrowStatisticsTable(PGVM pGVM, uint64_t cMinEntries); +VMMR0_INT_DECL(int) IOMR0IoPortSyncStatisticsIndices(PGVM pGVM); + +VMMR0_INT_DECL(int) IOMR0MmioSetUpContext(PGVM pGVM, PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser); +VMMR0_INT_DECL(int) IOMR0MmioGrowRegistrationTables(PGVM pGVM, uint64_t cMinEntries); +VMMR0_INT_DECL(int) IOMR0MmioGrowStatisticsTable(PGVM pGVM, uint64_t cMinEntries); +VMMR0_INT_DECL(int) IOMR0MmioSyncStatisticsIndices(PGVM pGVM); + +/** @} */ +#endif /* IN_RING0 || DOXYGEN_RUNNING */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_iom_h */ + diff --git a/include/VBox/vmm/mm.h b/include/VBox/vmm/mm.h new file mode 100644 index 00000000..540ba6d2 --- /dev/null +++ b/include/VBox/vmm/mm.h @@ -0,0 +1,244 @@ +/** @file + * MM - The Memory Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_mm_h +#define VBOX_INCLUDED_vmm_mm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_mm The Memory Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * Memory Allocation Tags. + * For use with MMHyperAlloc(), MMR3HeapAlloc(), MMR3HeapAllocEx(), + * MMR3HeapAllocZ() and MMR3HeapAllocZEx(). + * + * @remark Don't forget to update the dump command in MMHeap.cpp! + */ +typedef enum MMTAG +{ + MM_TAG_INVALID = 0, + + MM_TAG_CFGM, + MM_TAG_CFGM_BYTES, + MM_TAG_CFGM_STRING, + MM_TAG_CFGM_USER, + + MM_TAG_CSAM, + MM_TAG_CSAM_PATCH, + + MM_TAG_CPUM_CTX, + MM_TAG_CPUM_CPUID, + MM_TAG_CPUM_MSRS, + + MM_TAG_DBGF, + MM_TAG_DBGF_AS, + MM_TAG_DBGF_CORE_WRITE, + MM_TAG_DBGF_INFO, + MM_TAG_DBGF_LINE, + MM_TAG_DBGF_LINE_DUP, + MM_TAG_DBGF_MODULE, + MM_TAG_DBGF_OS, + MM_TAG_DBGF_REG, + MM_TAG_DBGF_STACK, + MM_TAG_DBGF_SYMBOL, + MM_TAG_DBGF_SYMBOL_DUP, + MM_TAG_DBGF_TYPE, + MM_TAG_DBGF_TRACER, + MM_TAG_DBGF_FLOWTRACE, + + MM_TAG_EM, + + MM_TAG_IEM, + + MM_TAG_IOM, + MM_TAG_IOM_STATS, + + MM_TAG_MM, + MM_TAG_MM_LOOKUP_GUEST, + MM_TAG_MM_LOOKUP_PHYS, + MM_TAG_MM_LOOKUP_VIRT, + MM_TAG_MM_PAGE, + + MM_TAG_PARAV, + + MM_TAG_PATM, + MM_TAG_PATM_PATCH, + + MM_TAG_PDM, + MM_TAG_PDM_ASYNC_COMPLETION, + MM_TAG_PDM_DEVICE, + MM_TAG_PDM_DEVICE_DESC, + MM_TAG_PDM_DEVICE_USER, + MM_TAG_PDM_DRIVER, + MM_TAG_PDM_DRIVER_DESC, + MM_TAG_PDM_DRIVER_USER, + MM_TAG_PDM_USB, + MM_TAG_PDM_USB_DESC, + MM_TAG_PDM_USB_USER, + MM_TAG_PDM_LUN, +#ifdef VBOX_WITH_NETSHAPER + MM_TAG_PDM_NET_SHAPER, +#endif /* VBOX_WITH_NETSHAPER */ + MM_TAG_PDM_QUEUE, + MM_TAG_PDM_THREAD, + + MM_TAG_PGM, + MM_TAG_PGM_CHUNK_MAPPING, + MM_TAG_PGM_HANDLERS, + MM_TAG_PGM_HANDLER_TYPES, + MM_TAG_PGM_MAPPINGS, + MM_TAG_PGM_PHYS, + MM_TAG_PGM_POOL, + + MM_TAG_REM, + + MM_TAG_SELM, + + MM_TAG_SSM, + + MM_TAG_STAM, + + MM_TAG_TM, + + MM_TAG_TRPM, + + MM_TAG_VM, + MM_TAG_VM_REQ, + + MM_TAG_VMM, + + MM_TAG_HM, + + MM_TAG_32BIT_HACK = 0x7fffffff +} MMTAG; + + + + +/** @defgroup grp_mm_hyper Hypervisor Memory Management + * @{ */ + +VMMDECL(RTR0PTR) MMHyperR3ToR0(PVM pVM, RTR3PTR R3Ptr); + +#ifndef IN_RING3 +VMMDECL(void *) MMHyperR3ToCC(PVM pVM, RTR3PTR R3Ptr); +#else +DECLINLINE(void *) MMHyperR3ToCC(PVM pVM, RTR3PTR R3Ptr) +{ + NOREF(pVM); + return R3Ptr; +} +#endif + + +/** @def MMHYPER_RC_ASSERT_RCPTR + * Asserts that an address is either NULL or inside the hypervisor memory area. + * This assertion only works while IN_RC, it's a NOP everywhere else. + * @thread The Emulation Thread. + */ +#define MMHYPER_RC_ASSERT_RCPTR(pVM, RCPtr) do { } while (0) + +/** @} */ + + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_mm_r3 The MM Host Context Ring-3 API + * @{ + */ + +VMMR3DECL(int) MMR3InitUVM(PUVM pUVM); +VMMR3DECL(int) MMR3Init(PVM pVM); +VMMR3DECL(int) MMR3InitPaging(PVM pVM); +VMMR3DECL(int) MMR3Term(PVM pVM); +VMMR3DECL(void) MMR3TermUVM(PUVM pUVM); +VMMR3DECL(int) MMR3ReserveHandyPages(PVM pVM, uint32_t cHandyPages); +VMMR3DECL(int) MMR3IncreaseBaseReservation(PVM pVM, uint64_t cAddBasePages); +VMMR3DECL(int) MMR3AdjustFixedReservation(PVM pVM, int32_t cDeltaFixedPages, const char *pszDesc); +VMMR3DECL(int) MMR3UpdateShadowReservation(PVM pVM, uint32_t cShadowPages); +/** @} */ + + +/** @defgroup grp_mm_phys Guest Physical Memory Manager + * @todo retire this group, elimintating or moving MMR3PhysGetRamSize to PGMPhys. + * @{ */ +VMMR3DECL(uint64_t) MMR3PhysGetRamSize(PVM pVM); +VMMR3DECL(uint32_t) MMR3PhysGetRamSizeBelow4GB(PVM pVM); +VMMR3DECL(uint64_t) MMR3PhysGetRamSizeAbove4GB(PVM pVM); +VMMR3DECL(uint32_t) MMR3PhysGet4GBRamHoleSize(PVM pVM); +/** @} */ + + +/** @defgroup grp_mm_heap Heap Manager + * @{ */ +VMMR3DECL(void *) MMR3HeapAlloc(PVM pVM, MMTAG enmTag, size_t cbSize); +VMMR3DECL(void *) MMR3HeapAllocU(PUVM pUVM, MMTAG enmTag, size_t cbSize); +VMMR3DECL(int) MMR3HeapAllocEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv); +VMMR3DECL(int) MMR3HeapAllocExU(PUVM pUVM, MMTAG enmTag, size_t cbSize, void **ppv); +VMMR3DECL(void *) MMR3HeapAllocZ(PVM pVM, MMTAG enmTag, size_t cbSize); +VMMR3DECL(void *) MMR3HeapAllocZU(PUVM pUVM, MMTAG enmTag, size_t cbSize); +VMMR3DECL(int) MMR3HeapAllocZEx(PVM pVM, MMTAG enmTag, size_t cbSize, void **ppv); +VMMR3DECL(int) MMR3HeapAllocZExU(PUVM pUVM, MMTAG enmTag, size_t cbSize, void **ppv); +VMMR3DECL(void *) MMR3HeapRealloc(void *pv, size_t cbNewSize); +VMMR3DECL(char *) MMR3HeapStrDup(PVM pVM, MMTAG enmTag, const char *psz); +VMMR3DECL(char *) MMR3HeapStrDupU(PUVM pUVM, MMTAG enmTag, const char *psz); +VMMR3DECL(char *) MMR3HeapAPrintf(PVM pVM, MMTAG enmTag, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VMMR3DECL(char *) MMR3HeapAPrintfU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(3, 4); +VMMR3DECL(char *) MMR3HeapAPrintfV(PVM pVM, MMTAG enmTag, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); +VMMR3DECL(char *) MMR3HeapAPrintfVU(PUVM pUVM, MMTAG enmTag, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(3, 0); +VMMR3DECL(void) MMR3HeapFree(void *pv); +/** @} */ + +#endif /* IN_RING3 || DOXYGEN_RUNNING */ + + +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_mm_h */ + diff --git a/include/VBox/vmm/nem.h b/include/VBox/vmm/nem.h new file mode 100644 index 00000000..3004efa5 --- /dev/null +++ b/include/VBox/vmm/nem.h @@ -0,0 +1,256 @@ +/** @file + * NEM - The Native Execution Manager. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_nem_h +#define VBOX_INCLUDED_vmm_nem_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_nem The Native Execution Manager API + * @ingroup grp_vmm + * @{ + */ + +/** @defgroup grp_nem_r3 The NEM ring-3 Context API + * @{ + */ +VMMR3_INT_DECL(int) NEMR3InitConfig(PVM pVM); +VMMR3_INT_DECL(int) NEMR3Init(PVM pVM, bool fFallback, bool fForced); +VMMR3_INT_DECL(int) NEMR3InitAfterCPUM(PVM pVM); +#ifdef IN_RING3 +VMMR3_INT_DECL(int) NEMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +#endif +VMMR3_INT_DECL(int) NEMR3Term(PVM pVM); +VMMR3DECL(bool) NEMR3IsEnabled(PUVM pVM); +VMMR3_INT_DECL(bool) NEMR3NeedSpecialTscMode(PVM pVM); +VMMR3_INT_DECL(void) NEMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) NEMR3ResetCpu(PVMCPU pVCpu, bool fInitIpi); +VMMR3DECL(const char *) NEMR3GetExitName(uint32_t uExit); +VMMR3_INT_DECL(VBOXSTRICTRC) NEMR3RunGC(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(bool) NEMR3CanExecuteGuest(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(bool) NEMR3SetSingleInstruction(PVM pVM, PVMCPU pVCpu, bool fEnable); +VMMR3_INT_DECL(void) NEMR3NotifyFF(PVM pVM, PVMCPU pVCpu, uint32_t fFlags); + +/** + * Checks if dirty page tracking for MMIO2 ranges is supported. + * + * If it is, PGM will not install a physical write access handler for the MMIO2 + * region and instead just forward dirty bit queries NEMR3QueryMmio2DirtyBits. + * The enable/disable control of the tracking will be ignored, and PGM will + * always set NEM_NOTIFY_PHYS_MMIO_EX_F_TRACK_DIRTY_PAGES for such ranges. + * + * @retval true if supported. + * @retval false if not. + * @param pVM The cross context VM structure. + */ +VMMR3_INT_DECL(bool) NEMR3IsMmio2DirtyPageTrackingSupported(PVM pVM); + +/** + * Worker for PGMR3PhysMmio2QueryAndResetDirtyBitmap. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param GCPhys The address of the MMIO2 range. + * @param cb The size of the MMIO2 range. + * @param uNemRange The NEM internal range number. + * @param pvBitmap The output bitmap. Must be 8-byte aligned. Ignored + * when @a cbBitmap is zero. + * @param cbBitmap The size of the bitmap. Must be the size of the whole + * MMIO2 range, rounded up to the nearest 8 bytes. + * When zero only a reset is done. + */ +VMMR3_INT_DECL(int) NEMR3PhysMmio2QueryAndResetDirtyBitmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t uNemRange, + void *pvBitmap, size_t cbBitmap); + +VMMR3_INT_DECL(int) NEMR3NotifyPhysRamRegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvR3, + uint8_t *pu2State, uint32_t *puNemRange); +VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExMapEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, + void *pvRam, void *pvMmio2, uint8_t *pu2State, uint32_t *puNemRange); +VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExMapLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, + void *pvRam, void *pvMmio2, uint32_t *puNemRange); +VMMR3_INT_DECL(int) NEMR3NotifyPhysMmioExUnmap(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, uint32_t fFlags, + void *pvRam, void *pvMmio2, uint8_t *pu2State, uint32_t *puNemRange); +/** @name Flags for NEMR3NotifyPhysMmioExMap and NEMR3NotifyPhysMmioExUnmap. + * @{ */ +/** Set if the range is replacing RAM rather that unused space. */ +#define NEM_NOTIFY_PHYS_MMIO_EX_F_REPLACE RT_BIT(0) +/** Set if it's MMIO2 being mapped or unmapped. */ +#define NEM_NOTIFY_PHYS_MMIO_EX_F_MMIO2 RT_BIT(1) +/** Set if MMIO2 and dirty page tracking is configured. */ +#define NEM_NOTIFY_PHYS_MMIO_EX_F_TRACK_DIRTY_PAGES RT_BIT(2) +/** @} */ + +/** + * Called very early during ROM registration, basically so an existing RAM range + * can be adjusted if desired. + * + * It will be succeeded by a number of NEMHCNotifyPhysPageProtChanged() + * calls and finally a call to NEMR3NotifyPhysRomRegisterLate(). + * + * @returns VBox status code + * @param pVM The cross context VM structure. + * @param GCPhys The ROM address (page aligned). + * @param cb The size (page aligned). + * @param pvPages Pointer to the ROM (RAM) pages in simplified mode + * when NEM_NOTIFY_PHYS_ROM_F_REPLACE is set, otherwise + * NULL. + * @param fFlags NEM_NOTIFY_PHYS_ROM_F_XXX. + * @param pu2State New page state or UINT8_MAX to leave as-is. + * @param puNemRange Access to the relevant PGMRAMRANGE::uNemRange field. + */ +VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterEarly(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvPages, + uint32_t fFlags, uint8_t *pu2State, uint32_t *puNemRange); + +/** + * Called after the ROM range has been fully completed. + * + * This will be preceeded by a NEMR3NotifyPhysRomRegisterEarly() call as well a + * number of NEMHCNotifyPhysPageProtChanged calls. + * + * @returns VBox status code + * @param pVM The cross context VM structure. + * @param GCPhys The ROM address (page aligned). + * @param cb The size (page aligned). + * @param pvPages Pointer to the ROM pages. + * @param fFlags NEM_NOTIFY_PHYS_ROM_F_XXX. + * @param pu2State Where to return the new NEM page state, UINT8_MAX + * for unchanged. + * @param puNemRange Access to the relevant PGMRAMRANGE::uNemRange field. + */ +VMMR3_INT_DECL(int) NEMR3NotifyPhysRomRegisterLate(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, void *pvPages, + uint32_t fFlags, uint8_t *pu2State, uint32_t *puNemRange); + +/** @name Flags for NEMR3NotifyPhysRomRegisterEarly and NEMR3NotifyPhysRomRegisterLate. + * @{ */ +/** Set if the range is replacing RAM rather that unused space. */ +#define NEM_NOTIFY_PHYS_ROM_F_REPLACE RT_BIT(1) +/** Set if it's MMIO2 being mapped or unmapped. */ +#define NEM_NOTIFY_PHYS_ROM_F_SHADOW RT_BIT(2) +/** @} */ + +/** + * Called when the A20 state changes. + * + * Windows: Hyper-V doesn't seem to offer a simple way of implementing the A20 + * line features of PCs. So, we do a very minimal emulation of the HMA to make + * DOS happy. + * + * @param pVCpu The CPU the A20 state changed on. + * @param fEnabled Whether it was enabled (true) or disabled. + */ +VMMR3_INT_DECL(void) NEMR3NotifySetA20(PVMCPU pVCpu, bool fEnabled); +VMMR3_INT_DECL(void) NEMR3NotifyDebugEventChanged(PVM pVM); +VMMR3_INT_DECL(void) NEMR3NotifyDebugEventChangedPerCpu(PVM pVM, PVMCPU pVCpu); +/** @} */ + + +/** @defgroup grp_nem_r0 The NEM ring-0 Context API + * @{ */ +VMMR0_INT_DECL(int) NEMR0Init(void); +VMMR0_INT_DECL(void) NEMR0Term(void); +VMMR0_INT_DECL(int) NEMR0InitVM(PGVM pGVM); +VMMR0_INT_DECL(int) NEMR0InitVMPart2(PGVM pGVM); +VMMR0_INT_DECL(void) NEMR0CleanupVM(PGVM pGVM); +VMMR0_INT_DECL(int) NEMR0MapPages(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0UnmapPages(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0ExportState(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0ImportState(PGVM pGVM, VMCPUID idCpu, uint64_t fWhat); +VMMR0_INT_DECL(int) NEMR0QueryCpuTick(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0ResumeCpuTickOnAll(PGVM pGVM, VMCPUID idCpu, uint64_t uPausedTscValue); +VMMR0_INT_DECL(VBOXSTRICTRC) NEMR0RunGuestCode(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0UpdateStatistics(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) NEMR0DoExperiment(PGVM pGVM, VMCPUID idCpu, uint64_t u64Arg); +#ifdef RT_OS_WINDOWS +VMMR0_INT_DECL(int) NEMR0WinGetPartitionId(PGVM pGVM, uintptr_t uHandle); +#endif +/** @} */ + + +/** @defgroup grp_nem_hc The NEM Host Context API + * @{ + */ +VMM_INT_DECL(bool) NEMHCIsLongModeAllowed(PVMCC pVM); +VMM_INT_DECL(uint32_t) NEMHCGetFeatures(PVMCC pVM); +VMM_INT_DECL(int) NEMImportStateOnDemand(PVMCPUCC pVCpu, uint64_t fWhat); + +/** @name NEM_FEAT_F_XXX - Features supported by the NEM backend + * @{ */ +/** NEM backend uses nested paging for the guest. */ +#define NEM_FEAT_F_NESTED_PAGING RT_BIT(0) +/** NEM backend uses full (unrestricted) guest execution. */ +#define NEM_FEAT_F_FULL_GST_EXEC RT_BIT(1) +/** NEM backend offers an xsave/xrstor interface. */ +#define NEM_FEAT_F_XSAVE_XRSTOR RT_BIT(2) +/** @} */ + +VMM_INT_DECL(void) NEMHCNotifyHandlerPhysicalRegister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb); +VMM_INT_DECL(void) NEMHCNotifyHandlerPhysicalDeregister(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhys, RTGCPHYS cb, + RTR3PTR pvMemR3, uint8_t *pu2State); +VMM_INT_DECL(void) NEMHCNotifyHandlerPhysicalModify(PVMCC pVM, PGMPHYSHANDLERKIND enmKind, RTGCPHYS GCPhysOld, + RTGCPHYS GCPhysNew, RTGCPHYS cb, bool fRestoreAsRAM); + +VMM_INT_DECL(int) NEMHCNotifyPhysPageAllocated(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, uint32_t fPageProt, + PGMPAGETYPE enmType, uint8_t *pu2State); +VMM_INT_DECL(void) NEMHCNotifyPhysPageProtChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhys, RTR3PTR pvR3, uint32_t fPageProt, + PGMPAGETYPE enmType, uint8_t *pu2State); +VMM_INT_DECL(void) NEMHCNotifyPhysPageChanged(PVMCC pVM, RTGCPHYS GCPhys, RTHCPHYS HCPhysPrev, RTHCPHYS HCPhysNew, + RTR3PTR pvNewR3, uint32_t fPageProt, PGMPAGETYPE enmType, uint8_t *pu2State); +/** @name NEM_PAGE_PROT_XXX - Page protection + * @{ */ +#define NEM_PAGE_PROT_NONE UINT32_C(0) /**< All access causes VM exits. */ +#define NEM_PAGE_PROT_READ RT_BIT(0) /**< Read access. */ +#define NEM_PAGE_PROT_EXECUTE RT_BIT(1) /**< Execute access. */ +#define NEM_PAGE_PROT_WRITE RT_BIT(2) /**< write access. */ +/** @} */ + +VMM_INT_DECL(int) NEMHCQueryCpuTick(PVMCPUCC pVCpu, uint64_t *pcTicks, uint32_t *puAux); +VMM_INT_DECL(int) NEMHCResumeCpuTickOnAll(PVMCC pVM, PVMCPUCC pVCpu, uint64_t uPausedTscValue); + +/** @} */ + +/** @} */ +RT_C_DECLS_END + + +#endif /* !VBOX_INCLUDED_vmm_nem_h */ + diff --git a/include/VBox/vmm/pdm.h b/include/VBox/vmm/pdm.h new file mode 100644 index 00000000..be46e570 --- /dev/null +++ b/include/VBox/vmm/pdm.h @@ -0,0 +1,54 @@ +/** @file + * PDM - Pluggable Device Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdm_h +#define VBOX_INCLUDED_vmm_pdm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#endif /* !VBOX_INCLUDED_vmm_pdm_h */ + diff --git a/include/VBox/vmm/pdmapi.h b/include/VBox/vmm/pdmapi.h new file mode 100644 index 00000000..bf25f043 --- /dev/null +++ b/include/VBox/vmm/pdmapi.h @@ -0,0 +1,393 @@ +/** @file + * PDM - Pluggable Device Manager, Core API. + * + * The 'Core API' has been put in a different header because everyone + * is currently including pdm.h. So, pdm.h is for including all of the + * PDM stuff, while pdmapi.h is for the core stuff. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmapi_h +#define VBOX_INCLUDED_vmm_pdmapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#ifdef IN_RING3 +# include +#endif +#include + +struct PDMDEVMODREGR0; + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm The Pluggable Device Manager API + * @ingroup grp_vmm + * @{ + */ + +VMMDECL(int) PDMGetInterrupt(PVMCPUCC pVCpu, uint8_t *pu8Interrupt); +VMMDECL(int) PDMIsaSetIrq(PVMCC pVM, uint8_t u8Irq, uint8_t u8Level, uint32_t uTagSrc); +VMM_INT_DECL(bool) PDMHasIoApic(PVM pVM); +VMM_INT_DECL(bool) PDMHasApic(PVM pVM); +VMM_INT_DECL(PPDMDEVINS) PDMDeviceRing0IdxToInstance(PVMCC pVM, uint64_t idxR0Device); +VMM_INT_DECL(int) PDMIoApicSetIrq(PVM pVM, PCIBDF uBusDevFn, uint8_t u8Irq, uint8_t u8Level, uint32_t uTagSrc); +VMM_INT_DECL(void) PDMIoApicBroadcastEoi(PVMCC pVM, uint8_t uVector); +VMM_INT_DECL(void) PDMIoApicSendMsi(PVMCC pVM, PCIBDF uBusDevFn, PCMSIMSG pMsi, uint32_t uTagSrc); +VMM_INT_DECL(int) PDMVmmDevHeapR3ToGCPhys(PVM pVM, RTR3PTR pv, RTGCPHYS *pGCPhys); +VMM_INT_DECL(bool) PDMVmmDevHeapIsEnabled(PVM pVM); + +/** + * Mapping/unmapping callback for an VMMDev heap allocation. + * + * @param pVM The cross context VM structure. + * @param pvAllocation The allocation address (ring-3). + * @param GCPhysAllocation The guest physical address of the mapping if + * it's being mapped, NIL_RTGCPHYS if it's being + * unmapped. + */ +typedef DECLCALLBACKTYPE(void, FNPDMVMMDEVHEAPNOTIFY,(PVM pVM, void *pvAllocation, RTGCPHYS GCPhysAllocation)); +/** Pointer (ring-3) to a FNPDMVMMDEVHEAPNOTIFY function. */ +typedef R3PTRTYPE(FNPDMVMMDEVHEAPNOTIFY *) PFNPDMVMMDEVHEAPNOTIFY; + + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_pdm_r3 The PDM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(int) PDMR3InitUVM(PUVM pUVM); +VMMR3_INT_DECL(int) PDMR3LdrLoadVMMR0U(PUVM pUVM); +VMMR3_INT_DECL(int) PDMR3Init(PVM pVM); +VMMR3_INT_DECL(int) PDMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3DECL(void) PDMR3PowerOn(PVM pVM); +VMMR3_INT_DECL(bool) PDMR3GetResetInfo(PVM pVM, uint32_t fOverride, uint32_t *pfResetFlags); +VMMR3_INT_DECL(void) PDMR3ResetCpu(PVMCPU pVCpu); +VMMR3_INT_DECL(void) PDMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) PDMR3MemSetup(PVM pVM, bool fAtReset); +VMMR3_INT_DECL(void) PDMR3SoftReset(PVM pVM, uint32_t fResetFlags); +VMMR3_INT_DECL(void) PDMR3Suspend(PVM pVM); +VMMR3_INT_DECL(void) PDMR3Resume(PVM pVM); +VMMR3DECL(void) PDMR3PowerOff(PVM pVM); +VMMR3_INT_DECL(void) PDMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) PDMR3Term(PVM pVM); +VMMR3_INT_DECL(void) PDMR3TermUVM(PUVM pUVM); +VMMR3_INT_DECL(bool) PDMR3HasLoadedState(PVM pVM); + +/** PDM loader context indicator. */ +typedef enum PDMLDRCTX +{ + /** Invalid zero value. */ + PDMLDRCTX_INVALID = 0, + /** Ring-0 context. */ + PDMLDRCTX_RING_0, + /** Ring-3 context. */ + PDMLDRCTX_RING_3, + /** Raw-mode context. */ + PDMLDRCTX_RAW_MODE, + /** End of valid context values. */ + PDMLDRCTX_END, + /** 32-bit type hack. */ + PDMLDRCTX_32BIT_HACK = 0x7fffffff +} PDMLDRCTX; + +/** + * Module enumeration callback function. + * + * @returns VBox status. + * Failure will stop the search and return the return code. + * Warnings will be ignored and not returned. + * @param pVM The cross context VM structure. + * @param pszFilename Module filename. + * @param pszName Module name. (short and unique) + * @param ImageBase Address where to executable image is loaded. + * @param cbImage Size of the executable image. + * @param enmCtx The context the module is loaded into. + * @param pvArg User argument. + */ +typedef DECLCALLBACKTYPE(int, FNPDMR3ENUM,(PVM pVM, const char *pszFilename, const char *pszName, + RTUINTPTR ImageBase, size_t cbImage, PDMLDRCTX enmCtx, void *pvArg)); +/** Pointer to a FNPDMR3ENUM() function. */ +typedef FNPDMR3ENUM *PFNPDMR3ENUM; +VMMR3DECL(int) PDMR3LdrEnumModules(PVM pVM, PFNPDMR3ENUM pfnCallback, void *pvArg); +VMMR3_INT_DECL(void) PDMR3LdrRelocateU(PUVM pUVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) PDMR3LdrLoadR0(PUVM pUVM, const char *pszModule, const char *pszSearchPath); +VMMR3_INT_DECL(int) PDMR3LdrGetSymbolR3(PVM pVM, const char *pszModule, const char *pszSymbol, void **ppvValue); +VMMR3DECL(int) PDMR3LdrGetSymbolR0(PVM pVM, const char *pszModule, const char *pszSymbol, PRTR0PTR ppvValue); +VMMR3DECL(int) PDMR3LdrGetSymbolR0Lazy(PVM pVM, const char *pszModule, const char *pszSearchPath, const char *pszSymbol, PRTR0PTR ppvValue); +VMMR3DECL(int) PDMR3LdrLoadRC(PVM pVM, const char *pszFilename, const char *pszName); +VMMR3DECL(int) PDMR3LdrGetSymbolRC(PVM pVM, const char *pszModule, const char *pszSymbol, PRTRCPTR pRCPtrValue); +VMMR3DECL(int) PDMR3LdrGetSymbolRCLazy(PVM pVM, const char *pszModule, const char *pszSearchPath, const char *pszSymbol, + PRTRCPTR pRCPtrValue); +VMMR3_INT_DECL(int) PDMR3LdrQueryRCModFromPC(PVM pVM, RTRCPTR uPC, + char *pszModName, size_t cchModName, PRTRCPTR pMod, + char *pszNearSym1, size_t cchNearSym1, PRTRCPTR pNearSym1, + char *pszNearSym2, size_t cchNearSym2, PRTRCPTR pNearSym2); +VMMR3_INT_DECL(int) PDMR3LdrQueryR0ModFromPC(PVM pVM, RTR0PTR uPC, + char *pszModName, size_t cchModName, PRTR0PTR pMod, + char *pszNearSym1, size_t cchNearSym1, PRTR0PTR pNearSym1, + char *pszNearSym2, size_t cchNearSym2, PRTR0PTR pNearSym2); +VMMR3_INT_DECL(int) PDMR3LdrGetInterfaceSymbols(PVM pVM, void *pvInterface, size_t cbInterface, + const char *pszModule, const char *pszSearchPath, + const char *pszSymPrefix, const char *pszSymList, + bool fRing0OrRC); + +VMMR3DECL(int) PDMR3QueryDevice(PUVM pUVM, const char *pszDevice, unsigned iInstance, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3QueryDeviceLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3QueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3QueryDriverOnLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, + const char *pszDriver, PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3DeviceAttach(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags, + PPDMIBASE *ppBase); +VMMR3DECL(int) PDMR3DeviceDetach(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, uint32_t fFlags); +VMMR3_INT_DECL(PPDMCRITSECT) PDMR3DevGetCritSect(PVM pVM, PPDMDEVINS pDevIns); +VMMR3DECL(int) PDMR3DriverAttach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, uint32_t fFlags, + PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3DriverDetach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, + const char *pszDriver, unsigned iOccurrence, uint32_t fFlags); +VMMR3DECL(int) PDMR3DriverReattach(PUVM pVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, + const char *pszDriver, unsigned iOccurrence, uint32_t fFlags, PCFGMNODE pCfg, + PPPDMIBASE ppBase); +VMMR3DECL(void) PDMR3DmaRun(PVM pVM); + +VMMR3_INT_DECL(int) PDMR3VmmDevHeapAlloc(PVM pVM, size_t cbSize, PFNPDMVMMDEVHEAPNOTIFY pfnNotify, RTR3PTR *ppv); +VMMR3_INT_DECL(int) PDMR3VmmDevHeapFree(PVM pVM, RTR3PTR pv); +VMMR3_INT_DECL(int) PDMR3TracingConfig(PVM pVM, const char *pszName, size_t cchName, bool fEnable, bool fApply); +VMMR3_INT_DECL(bool) PDMR3TracingAreAll(PVM pVM, bool fEnabled); +VMMR3_INT_DECL(int) PDMR3TracingQueryConfig(PVM pVM, char *pszConfig, size_t cbConfig); +/** @} */ +#endif /* IN_RING3 */ + + + +/** @defgroup grp_pdm_rc The PDM Raw-Mode Context API + * @{ + */ +/** @} */ + + + +/** @defgroup grp_pdm_r0 The PDM Ring-0 Context API + * @{ + */ +VMMR0_INT_DECL(void) PDMR0Init(void *hMod); +VMMR0DECL(int) PDMR0DeviceRegisterModule(void *hMod, struct PDMDEVMODREGR0 *pModReg); +VMMR0DECL(int) PDMR0DeviceDeregisterModule(void *hMod, struct PDMDEVMODREGR0 *pModReg); + +VMMR0_INT_DECL(void) PDMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(void) PDMR0CleanupVM(PGVM pGVM); + +/** + * Request buffer for PDMR0DriverCallReqHandler / VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER. + * @see PDMR0DriverCallReqHandler. + */ +typedef struct PDMDRIVERCALLREQHANDLERREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The driver instance. */ + PPDMDRVINSR0 pDrvInsR0; + /** The operation. */ + uint32_t uOperation; + /** Explicit alignment padding. */ + uint32_t u32Alignment; + /** Optional 64-bit integer argument. */ + uint64_t u64Arg; +} PDMDRIVERCALLREQHANDLERREQ; +/** Pointer to a PDMR0DriverCallReqHandler / VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER + * request buffer. */ +typedef PDMDRIVERCALLREQHANDLERREQ *PPDMDRIVERCALLREQHANDLERREQ; + +VMMR0_INT_DECL(int) PDMR0DriverCallReqHandler(PGVM pGVM, PPDMDRIVERCALLREQHANDLERREQ pReq); + + +/** + * Request buffer for PDMR0DeviceCreateReqHandler / VMMR0_DO_PDM_DEVICE_CREATE. + * @see PDMR0DeviceCreateReqHandler. + */ +typedef struct PDMDEVICECREATEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** Out: Where to return the address of the ring-3 device instance. */ + PPDMDEVINSR3 pDevInsR3; + + /** Copy of PDMDEVREGR3::fFlags for matching with PDMDEVREGR0::fFlags. */ + uint32_t fFlags; + /** Copy of PDMDEVREGR3::fClass for matching with PDMDEVREGR0::fFlags. */ + uint32_t fClass; + /** Copy of PDMDEVREGR3::cMaxInstances for matching with + * PDMDEVREGR0::cMaxInstances. */ + uint32_t cMaxInstances; + /** Copy of PDMDEVREGR3::uSharedVersion for matching with + * PDMDEVREGR0::uSharedVersion. */ + uint32_t uSharedVersion; + /** Copy of PDMDEVREGR3::cbInstanceShared for matching with + * PDMDEVREGR0::cbInstanceShared. */ + uint32_t cbInstanceShared; + /** Copy of PDMDEVREGR3::cbInstanceCC. */ + uint32_t cbInstanceR3; + /** Copy of PDMDEVREGR3::cbInstanceRC for matching with + * PDMDEVREGR0::cbInstanceRC. */ + uint32_t cbInstanceRC; + /** Copy of PDMDEVREGR3::cMaxPciDevices for matching with + * PDMDEVREGR0::cMaxPciDevices. */ + uint16_t cMaxPciDevices; + /** Copy of PDMDEVREGR3::cMaxMsixVectors for matching with + * PDMDEVREGR0::cMaxMsixVectors. */ + uint16_t cMaxMsixVectors; + + /** The device instance ordinal. */ + uint32_t iInstance; + /** Set if the raw-mode component is desired. */ + bool fRCEnabled; + /** Explicit padding. */ + bool afReserved[3]; + /** DBGF tracer event source handle if configured. */ + DBGFTRACEREVTSRC hDbgfTracerEvtSrc; + + /** In: Device name. */ + char szDevName[32]; + /** In: The module name (no path). */ + char szModName[32]; +} PDMDEVICECREATEREQ; +/** Pointer to a PDMR0DeviceCreate / VMMR0_DO_PDM_DEVICE_CREATE request buffer. */ +typedef PDMDEVICECREATEREQ *PPDMDEVICECREATEREQ; + +VMMR0_INT_DECL(int) PDMR0DeviceCreateReqHandler(PGVM pGVM, PPDMDEVICECREATEREQ pReq); + +/** + * The ring-0 device call to make. + */ +typedef enum PDMDEVICEGENCALL +{ + PDMDEVICEGENCALL_INVALID = 0, + PDMDEVICEGENCALL_CONSTRUCT, + PDMDEVICEGENCALL_DESTRUCT, + PDMDEVICEGENCALL_REQUEST, + PDMDEVICEGENCALL_END, + PDMDEVICEGENCALL_32BIT_HACK = 0x7fffffff +} PDMDEVICEGENCALL; + +/** + * Request buffer for PDMR0DeviceGenCallReqHandler / VMMR0_DO_PDM_DEVICE_GEN_CALL. + * @see PDMR0DeviceGenCallReqHandler. + */ +typedef struct PDMDEVICEGENCALLREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The ring-3 device instance. */ + PPDMDEVINSR3 pDevInsR3; + /** The ring-0 device handle. */ + uint32_t idxR0Device; + /** The call to make. */ + PDMDEVICEGENCALL enmCall; + union + { + /** PDMDEVICEGENCALL_REQUEST: */ + struct + { + /** The request argument. */ + uint64_t uArg; + /** The request number. */ + uint32_t uReq; + } Req; + /** Size padding. */ + uint64_t au64[3]; + } Params; +} PDMDEVICEGENCALLREQ; +/** Pointer to a PDMR0DeviceGenCallReqHandler / VMMR0_DO_PDM_DEVICE_GEN_CALL request buffer. */ +typedef PDMDEVICEGENCALLREQ *PPDMDEVICEGENCALLREQ; + +VMMR0_INT_DECL(int) PDMR0DeviceGenCallReqHandler(PGVM pGVM, PPDMDEVICEGENCALLREQ pReq, VMCPUID idCpu); + +/** + * Request buffer for PDMR0DeviceCompatSetCritSectReqHandler / VMMR0_DO_PDM_DEVICE_COMPAT_SET_CRITSECT + * @see PDMR0DeviceCompatSetCritSectReqHandler. + */ +typedef struct PDMDEVICECOMPATSETCRITSECTREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + /** The ring-3 device instance. */ + PPDMDEVINSR3 pDevInsR3; + /** The ring-0 device handle. */ + uint32_t idxR0Device; + /** The critical section address (ring-3). */ + R3PTRTYPE(PPDMCRITSECT) pCritSectR3; +} PDMDEVICECOMPATSETCRITSECTREQ; +/** Pointer to a PDMR0DeviceGenCallReqHandler / VMMR0_DO_PDM_DEVICE_GEN_CALL request buffer. */ +typedef PDMDEVICECOMPATSETCRITSECTREQ *PPDMDEVICECOMPATSETCRITSECTREQ; + +VMMR0_INT_DECL(int) PDMR0DeviceCompatSetCritSectReqHandler(PGVM pGVM, PPDMDEVICECOMPATSETCRITSECTREQ pReq); + + +/** + * Request buffer for PDMR0QueueCreateReqHandler / VMMR0_DO_PDM_QUEUE_CREATE. + * @see PDMR0QueueCreateReqHandler. + */ +typedef struct PDMQUEUECREATEREQ +{ + /** The header. */ + SUPVMMR0REQHDR Hdr; + + /** Number of queue items. */ + uint32_t cItems; + /** Queue item size. */ + uint32_t cbItem; + /** Owner type (PDMQUEUETYPE). */ + uint32_t enmType; + /** The ring-3 owner pointer. */ + RTR3PTR pvOwner; + /** The ring-3 callback function address. */ + RTR3PTR pfnCallback; + /** The queue name. */ + char szName[40]; + + /** Output: The queue handle. */ + PDMQUEUEHANDLE hQueue; +} PDMQUEUECREATEREQ; +/** Pointer to a PDMR0QueueCreateReqHandler / VMMR0_DO_PDM_QUEUE_CREATE request buffer. */ +typedef PDMQUEUECREATEREQ *PPDMQUEUECREATEREQ; + +VMMR0_INT_DECL(int) PDMR0QueueCreateReqHandler(PGVM pGVM, PPDMQUEUECREATEREQ pReq); + +/** @} */ + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmapi_h */ diff --git a/include/VBox/vmm/pdmasynccompletion.h b/include/VBox/vmm/pdmasynccompletion.h new file mode 100644 index 00000000..f46d7910 --- /dev/null +++ b/include/VBox/vmm/pdmasynccompletion.h @@ -0,0 +1,160 @@ +/** @file + * PDM - Pluggable Device Manager, Async I/O Completion. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmasynccompletion_h +#define VBOX_INCLUDED_vmm_pdmasynccompletion_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_async_completion The PDM Async I/O Completion API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM async completion template handle. */ +typedef struct PDMASYNCCOMPLETIONTEMPLATE *PPDMASYNCCOMPLETIONTEMPLATE; +/** Pointer to a PDM async completion template handle pointer. */ +typedef PPDMASYNCCOMPLETIONTEMPLATE *PPPDMASYNCCOMPLETIONTEMPLATE; + +/** Pointer to a PDM async completion task handle. */ +typedef struct PDMASYNCCOMPLETIONTASK *PPDMASYNCCOMPLETIONTASK; +/** Pointer to a PDM async completion task handle pointer. */ +typedef PPDMASYNCCOMPLETIONTASK *PPPDMASYNCCOMPLETIONTASK; + +/** Pointer to a PDM async completion endpoint handle. */ +typedef struct PDMASYNCCOMPLETIONENDPOINT *PPDMASYNCCOMPLETIONENDPOINT; +/** Pointer to a PDM async completion endpoint handle pointer. */ +typedef PPDMASYNCCOMPLETIONENDPOINT *PPPDMASYNCCOMPLETIONENDPOINT; + + +/** + * Completion callback for devices. + * + * @param pDevIns The device instance. + * @param pvUser User argument. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMASYNCCOMPLETEDEV,(PPDMDEVINS pDevIns, void *pvUser, int rc)); +/** Pointer to a FNPDMASYNCCOMPLETEDEV(). */ +typedef FNPDMASYNCCOMPLETEDEV *PFNPDMASYNCCOMPLETEDEV; + + +/** + * Completion callback for drivers. + * + * @param pDrvIns The driver instance. + * @param pvTemplateUser User argument given when creating the template. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMASYNCCOMPLETEDRV,(PPDMDRVINS pDrvIns, void *pvTemplateUser, void *pvUser, int rc)); +/** Pointer to a FNPDMASYNCCOMPLETEDRV(). */ +typedef FNPDMASYNCCOMPLETEDRV *PFNPDMASYNCCOMPLETEDRV; + + +/** + * Completion callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param pvUser User argument. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMASYNCCOMPLETEUSB,(PPDMUSBINS pUsbIns, void *pvUser, int rc)); +/** Pointer to a FNPDMASYNCCOMPLETEUSB(). */ +typedef FNPDMASYNCCOMPLETEUSB *PFNPDMASYNCCOMPLETEUSB; + + +/** + * Completion callback for internal. + * + * @param pVM The cross context VM structure. + * @param pvUser User argument for the task. + * @param pvUser2 User argument for the template. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMASYNCCOMPLETEINT,(PVM pVM, void *pvUser, void *pvUser2, int rc)); +/** Pointer to a FNPDMASYNCCOMPLETEINT(). */ +typedef FNPDMASYNCCOMPLETEINT *PFNPDMASYNCCOMPLETEINT; + +VMMR3DECL(int) PDMR3AsyncCompletionTemplateCreateInternal(PVM pVM, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, + PFNPDMASYNCCOMPLETEINT pfnCompleted, void *pvUser2, const char *pszDesc); +VMMR3DECL(int) PDMR3AsyncCompletionTemplateDestroy(PPDMASYNCCOMPLETIONTEMPLATE pTemplate); +VMMR3DECL(int) PDMR3AsyncCompletionEpCreateForFile(PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint, + const char *pszFilename, uint32_t fFlags, + PPDMASYNCCOMPLETIONTEMPLATE pTemplate); + +/** @defgroup grp_pdmacep_file_flags Flags for PDMR3AsyncCompletionEpCreateForFile + * @{ */ +/** Open the file in read-only mode. */ +#define PDMACEP_FILE_FLAGS_READ_ONLY RT_BIT_32(0) +/** Whether the file should not be write protected. + * The default is to protect the file against writes by other processes + * when opened in read/write mode to prevent data corruption by + * concurrent access which can occur if the local writeback cache is enabled. + */ +#define PDMACEP_FILE_FLAGS_DONT_LOCK RT_BIT_32(2) +/** Open the endpoint with the host cache enabled. */ +#define PDMACEP_FILE_FLAGS_HOST_CACHE_ENABLED RT_BIT_32(3) +/** @} */ + +VMMR3DECL(void) PDMR3AsyncCompletionEpClose(PPDMASYNCCOMPLETIONENDPOINT pEndpoint); +VMMR3DECL(int) PDMR3AsyncCompletionEpRead(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbRead, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask); +VMMR3DECL(int) PDMR3AsyncCompletionEpWrite(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbWrite, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask); +VMMR3DECL(int) PDMR3AsyncCompletionEpFlush(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser, PPPDMASYNCCOMPLETIONTASK ppTask); +VMMR3DECL(int) PDMR3AsyncCompletionEpGetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t *pcbSize); +VMMR3DECL(int) PDMR3AsyncCompletionEpSetSize(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize); +VMMR3DECL(int) PDMR3AsyncCompletionEpSetBwMgr(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr); +VMMR3DECL(int) PDMR3AsyncCompletionTaskCancel(PPDMASYNCCOMPLETIONTASK pTask); +VMMR3DECL(int) PDMR3AsyncCompletionBwMgrSetMaxForFile(PUVM pUVM, const char *pszBwMgr, uint32_t cbMaxNew); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmasynccompletion_h */ + diff --git a/include/VBox/vmm/pdmasynctask.h b/include/VBox/vmm/pdmasynctask.h new file mode 100644 index 00000000..422f9727 --- /dev/null +++ b/include/VBox/vmm/pdmasynctask.h @@ -0,0 +1,74 @@ +/** @file + * PDM - Pluggable Device Manager, Async Task. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmasynctask_h +#define VBOX_INCLUDED_vmm_pdmasynctask_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_async_task The PDM Async Task API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM async task template handle. */ +typedef struct PDMASYNCTASKTEMPLATE *PPDMASYNCTASKTEMPLATE; +/** Pointer to a PDM async task template handle pointer. */ +typedef PPDMASYNCTASKTEMPLATE *PPPDMASYNCTASKTEMPLATE; + +/** Pointer to a PDM async task handle. */ +typedef struct PDMASYNCTASK *PPDMASYNCTASK; +/** Pointer to a PDM async task handle pointer. */ +typedef PPDMASYNCTASK *PPPDMASYNCTASK; + +/* This should be similar to VMReq, only difference there will be a pool + of worker threads instead of EMT. The actual implementation should be + made in IPRT so we can reuse it for other stuff later. The reason why + it should be put in PDM is because we need to manage it wrt to VM + state changes (need exception - add a flag for this). */ + +/** @} */ + + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmasynctask_h */ + diff --git a/include/VBox/vmm/pdmaudiohostenuminline.h b/include/VBox/vmm/pdmaudiohostenuminline.h new file mode 100644 index 00000000..538c3bd6 --- /dev/null +++ b/include/VBox/vmm/pdmaudiohostenuminline.h @@ -0,0 +1,463 @@ +/* $Id: pdmaudiohostenuminline.h $ */ +/** @file + * PDM - Audio Helpers for host audio device enumeration, Inlined Code. (DEV,++) + * + * This is all inlined because it's too tedious to create a couple libraries to + * contain it all (same bad excuse as for intnetinline.h & pdmnetinline.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmaudiohostenuminline_h +#define VBOX_INCLUDED_vmm_pdmaudiohostenuminline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include +#include +#include +#include + +#include +#include +#include + + +/** @defgroup grp_pdm_audio_host_enum_inline The PDM Host Audio Enumeration Helper APIs + * @ingroup grp_pdm + * @{ + */ + + +/** + * Allocates a host audio device for an enumeration result. + * + * @returns Newly allocated audio device, or NULL on failure. + * @param cb The total device structure size. This must be at least the + * size of PDMAUDIOHOSTDEV. The idea is that the caller extends + * the PDMAUDIOHOSTDEV structure and appends additional data + * after it in its private structure. + * @param cbName The number of bytes to allocate for the name field + * (including the terminator). Pass zero if RTStrAlloc and + * friends will be used. + * @param cbId The number of bytes to allocate for the ID field. Pass + * zero if RTStrAlloc and friends will be used. + */ +DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioHostDevAlloc(size_t cb, size_t cbName, size_t cbId) +{ + AssertReturn(cb >= sizeof(PDMAUDIOHOSTDEV), NULL); + AssertReturn(cb < _4M, NULL); + AssertReturn(cbName < _4K, NULL); + AssertReturn(cbId < _16K, NULL); + + PPDMAUDIOHOSTDEV pDev = (PPDMAUDIOHOSTDEV)RTMemAllocZ(RT_ALIGN_Z(cb + cbName + cbId, 64)); + if (pDev) + { + pDev->uMagic = PDMAUDIOHOSTDEV_MAGIC; + pDev->cbSelf = (uint32_t)cb; + RTListInit(&pDev->ListEntry); + if (cbName) + pDev->pszName = (char *)pDev + cb; + if (cbId) + pDev->pszId = (char *)pDev + cb + cbName; + } + return pDev; +} + +/** + * Frees a host audio device allocated by PDMAudioHostDevAlloc. + * + * @param pDev The device to free. NULL is ignored. + */ +DECLINLINE(void) PDMAudioHostDevFree(PPDMAUDIOHOSTDEV pDev) +{ + if (pDev) + { + Assert(pDev->uMagic == PDMAUDIOHOSTDEV_MAGIC); + pDev->uMagic = ~PDMAUDIOHOSTDEV_MAGIC; + pDev->cbSelf = 0; + + if (pDev->fFlags & PDMAUDIOHOSTDEV_F_NAME_ALLOC) + { + RTStrFree(pDev->pszName); + pDev->pszName = NULL; + } + + if (pDev->fFlags & PDMAUDIOHOSTDEV_F_ID_ALLOC) + { + RTStrFree(pDev->pszId); + pDev->pszId = NULL; + } + + RTMemFree(pDev); + } +} + +/** + * Duplicates a host audio device enumeration entry. + * + * @returns Duplicated audio device entry on success, or NULL on failure. + * @param pDev The audio device enum entry to duplicate. + * @param fOnlyCoreData + */ +DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioHostDevDup(PCPDMAUDIOHOSTDEV pDev, bool fOnlyCoreData) +{ + AssertPtrReturn(pDev, NULL); + Assert(pDev->uMagic == PDMAUDIOHOSTDEV_MAGIC); + Assert(fOnlyCoreData || !(pDev->fFlags & PDMAUDIOHOSTDEV_F_NO_DUP)); + + uint32_t cbToDup = fOnlyCoreData ? sizeof(PDMAUDIOHOSTDEV) : pDev->cbSelf; + AssertReturn(cbToDup >= sizeof(*pDev), NULL); + + PPDMAUDIOHOSTDEV pDevDup = PDMAudioHostDevAlloc(cbToDup, 0, 0); + if (pDevDup) + { + memcpy(pDevDup, pDev, cbToDup); + RTListInit(&pDevDup->ListEntry); + pDevDup->cbSelf = cbToDup; + + if (pDev->pszName) + { + uintptr_t off; + if ( (pDevDup->fFlags & PDMAUDIOHOSTDEV_F_NAME_ALLOC) + || (off = (uintptr_t)pDev->pszName - (uintptr_t)pDev) >= pDevDup->cbSelf) + { + pDevDup->fFlags |= PDMAUDIOHOSTDEV_F_NAME_ALLOC; + pDevDup->pszName = RTStrDup(pDev->pszName); + AssertReturnStmt(pDevDup->pszName, PDMAudioHostDevFree(pDevDup), NULL); + } + else + pDevDup->pszName = (char *)pDevDup + off; + } + + if (pDev->pszId) + { + uintptr_t off; + if ( (pDevDup->fFlags & PDMAUDIOHOSTDEV_F_ID_ALLOC) + || (off = (uintptr_t)pDev->pszId - (uintptr_t)pDev) >= pDevDup->cbSelf) + { + pDevDup->fFlags |= PDMAUDIOHOSTDEV_F_ID_ALLOC; + pDevDup->pszId = RTStrDup(pDev->pszId); + AssertReturnStmt(pDevDup->pszId, PDMAudioHostDevFree(pDevDup), NULL); + } + else + pDevDup->pszId = (char *)pDevDup + off; + } + } + + return pDevDup; +} + +/** + * Initializes a host audio device enumeration. + * + * @param pDevEnm The enumeration to initialize. + */ +DECLINLINE(void) PDMAudioHostEnumInit(PPDMAUDIOHOSTENUM pDevEnm) +{ + AssertPtr(pDevEnm); + + pDevEnm->uMagic = PDMAUDIOHOSTENUM_MAGIC; + pDevEnm->cDevices = 0; + RTListInit(&pDevEnm->LstDevices); +} + +/** + * Deletes the host audio device enumeration and frees all device entries + * associated with it. + * + * The user must call PDMAudioHostEnumInit again to use it again. + * + * @param pDevEnm The host audio device enumeration to delete. + */ +DECLINLINE(void) PDMAudioHostEnumDelete(PPDMAUDIOHOSTENUM pDevEnm) +{ + if (pDevEnm) + { + AssertPtr(pDevEnm); + AssertReturnVoid(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC); + + PPDMAUDIOHOSTDEV pDev, pDevNext; + RTListForEachSafe(&pDevEnm->LstDevices, pDev, pDevNext, PDMAUDIOHOSTDEV, ListEntry) + { + RTListNodeRemove(&pDev->ListEntry); + + PDMAudioHostDevFree(pDev); + + pDevEnm->cDevices--; + } + + /* Sanity. */ + Assert(RTListIsEmpty(&pDevEnm->LstDevices)); + Assert(pDevEnm->cDevices == 0); + + pDevEnm->uMagic = ~PDMAUDIOHOSTENUM_MAGIC; + } +} + +/** + * Adds an audio device to a device enumeration. + * + * @param pDevEnm Device enumeration to add device to. + * @param pDev Device to add. The pointer will be owned by the device enumeration then. + */ +DECLINLINE(void) PDMAudioHostEnumAppend(PPDMAUDIOHOSTENUM pDevEnm, PPDMAUDIOHOSTDEV pDev) +{ + AssertPtr(pDevEnm); + AssertPtr(pDev); + Assert(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC); + + RTListAppend(&pDevEnm->LstDevices, &pDev->ListEntry); + pDevEnm->cDevices++; +} + +/** + * Appends copies of matching host device entries from one to another enumeration. + * + * @returns VBox status code. + * @param pDstDevEnm The target to append copies of matching device to. + * @param pSrcDevEnm The source to copy matching devices from. + * @param enmUsage The usage to match for copying. + * Use PDMAUDIODIR_INVALID to match all entries. + * @param fOnlyCoreData Set this to only copy the PDMAUDIOHOSTDEV part. + * Careful with passing @c false here as not all + * backends have data that can be copied. + */ +DECLINLINE(int) PDMAudioHostEnumCopy(PPDMAUDIOHOSTENUM pDstDevEnm, PCPDMAUDIOHOSTENUM pSrcDevEnm, + PDMAUDIODIR enmUsage, bool fOnlyCoreData) +{ + AssertPtrReturn(pDstDevEnm, VERR_INVALID_POINTER); + AssertReturn(pDstDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER); + + AssertPtrReturn(pSrcDevEnm, VERR_INVALID_POINTER); + AssertReturn(pSrcDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER); + + PPDMAUDIOHOSTDEV pSrcDev; + RTListForEach(&pSrcDevEnm->LstDevices, pSrcDev, PDMAUDIOHOSTDEV, ListEntry) + { + if ( enmUsage == pSrcDev->enmUsage + || enmUsage == PDMAUDIODIR_INVALID /*all*/) + { + PPDMAUDIOHOSTDEV pDstDev = PDMAudioHostDevDup(pSrcDev, fOnlyCoreData); + AssertReturn(pDstDev, VERR_NO_MEMORY); + + PDMAudioHostEnumAppend(pDstDevEnm, pDstDev); + } + } + + return VINF_SUCCESS; +} + +/** + * Moves all the device entries from one enumeration to another, destroying the + * former. + * + * @returns VBox status code. + * @param pDstDevEnm The target to put move @a pSrcDevEnm to. This + * does not need to be initialized, but if it is it + * must not have any device entries. + * @param pSrcDevEnm The source to move from. This will be empty + * upon successful return. + */ +DECLINLINE(int) PDMAudioHostEnumMove(PPDMAUDIOHOSTENUM pDstDevEnm, PPDMAUDIOHOSTENUM pSrcDevEnm) +{ + AssertPtrReturn(pDstDevEnm, VERR_INVALID_POINTER); + AssertReturn(pDstDevEnm->uMagic != PDMAUDIOHOSTENUM_MAGIC || pDstDevEnm->cDevices == 0, VERR_WRONG_ORDER); + + AssertPtrReturn(pSrcDevEnm, VERR_INVALID_POINTER); + AssertReturn(pSrcDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, VERR_WRONG_ORDER); + + pDstDevEnm->uMagic = PDMAUDIOHOSTENUM_MAGIC; + RTListInit(&pDstDevEnm->LstDevices); + pDstDevEnm->cDevices = pSrcDevEnm->cDevices; + if (pSrcDevEnm->cDevices) + { + PPDMAUDIOHOSTDEV pCur; + while ((pCur = RTListRemoveFirst(&pSrcDevEnm->LstDevices, PDMAUDIOHOSTDEV, ListEntry)) != NULL) + RTListAppend(&pDstDevEnm->LstDevices, &pCur->ListEntry); + } + return VINF_SUCCESS; +} + +/** + * Get the default device with the given usage. + * + * This assumes that only one default device per usage is set, if there should + * be more than one, the first one is returned. + * + * @returns Default device if found, or NULL if not. + * @param pDevEnm Device enumeration to get default device for. + * @param enmUsage Usage to get default device for. + * Pass PDMAUDIODIR_INVALID to get the first device with + * either PDMAUDIOHOSTDEV_F_DEFAULT_OUT or + * PDMAUDIOHOSTDEV_F_DEFAULT_IN set. + */ +DECLINLINE(PPDMAUDIOHOSTDEV) PDMAudioHostEnumGetDefault(PCPDMAUDIOHOSTENUM pDevEnm, PDMAUDIODIR enmUsage) +{ + AssertPtrReturn(pDevEnm, NULL); + AssertReturn(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, NULL); + + Assert(enmUsage == PDMAUDIODIR_IN || enmUsage == PDMAUDIODIR_OUT || enmUsage == PDMAUDIODIR_INVALID); + uint32_t const fFlags = enmUsage == PDMAUDIODIR_IN ? PDMAUDIOHOSTDEV_F_DEFAULT_IN + : enmUsage == PDMAUDIODIR_OUT ? PDMAUDIOHOSTDEV_F_DEFAULT_OUT + : enmUsage == PDMAUDIODIR_INVALID ? PDMAUDIOHOSTDEV_F_DEFAULT_IN | PDMAUDIOHOSTDEV_F_DEFAULT_OUT + : 0; + + PPDMAUDIOHOSTDEV pDev; + RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry) + { + if (pDev->fFlags & fFlags) + { + Assert(pDev->enmUsage == enmUsage || pDev->enmUsage == PDMAUDIODIR_DUPLEX || enmUsage == PDMAUDIODIR_INVALID); + return pDev; + } + } + + return NULL; +} + +/** + * Get the number of device with the given usage. + * + * @returns Number of matching devices. + * @param pDevEnm Device enumeration to get default device for. + * @param enmUsage Usage to count devices for. + * Pass PDMAUDIODIR_INVALID to get the total number of devices. + */ +DECLINLINE(uint32_t) PDMAudioHostEnumCountMatching(PCPDMAUDIOHOSTENUM pDevEnm, PDMAUDIODIR enmUsage) +{ + AssertPtrReturn(pDevEnm, 0); + AssertReturn(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC, 0); + + if (enmUsage == PDMAUDIODIR_INVALID) + return pDevEnm->cDevices; + + uint32_t cDevs = 0; + PPDMAUDIOHOSTDEV pDev; + RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry) + { + if (enmUsage == pDev->enmUsage) + cDevs++; + } + + return cDevs; +} + +/** The max string length for all PDMAUDIOHOSTDEV_F_XXX. + * @sa PDMAudioHostDevFlagsToString */ +#define PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN sizeof("DEFAULT_OUT DEFAULT_IN HOTPLUG BUGGY IGNORE LOCKED DEAD NAME_ALLOC ID_ALLOC NO_DUP ") + +/** + * Converts an audio device flags to a string. + * + * @returns + * @param pszDst Destination buffer with a size of at least + * PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN bytes (including + * the string terminator). + * @param fFlags Audio flags (PDMAUDIOHOSTDEV_F_XXX) to convert. + */ +DECLINLINE(const char *) PDMAudioHostDevFlagsToString(char pszDst[PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN], uint32_t fFlags) +{ + static const struct { const char *pszMnemonic; uint32_t cchMnemonic; uint32_t fFlag; } s_aFlags[] = + { + { RT_STR_TUPLE("DEFAULT_OUT "), PDMAUDIOHOSTDEV_F_DEFAULT_OUT }, + { RT_STR_TUPLE("DEFAULT_IN "), PDMAUDIOHOSTDEV_F_DEFAULT_IN }, + { RT_STR_TUPLE("HOTPLUG "), PDMAUDIOHOSTDEV_F_HOTPLUG }, + { RT_STR_TUPLE("BUGGY "), PDMAUDIOHOSTDEV_F_BUGGY }, + { RT_STR_TUPLE("IGNORE "), PDMAUDIOHOSTDEV_F_IGNORE }, + { RT_STR_TUPLE("LOCKED "), PDMAUDIOHOSTDEV_F_LOCKED }, + { RT_STR_TUPLE("DEAD "), PDMAUDIOHOSTDEV_F_DEAD }, + { RT_STR_TUPLE("NAME_ALLOC "), PDMAUDIOHOSTDEV_F_NAME_ALLOC }, + { RT_STR_TUPLE("ID_ALLOC "), PDMAUDIOHOSTDEV_F_ID_ALLOC }, + { RT_STR_TUPLE("NO_DUP "), PDMAUDIOHOSTDEV_F_NO_DUP }, + }; + size_t offDst = 0; + for (uint32_t i = 0; i < RT_ELEMENTS(s_aFlags); i++) + if (fFlags & s_aFlags[i].fFlag) + { + fFlags &= ~s_aFlags[i].fFlag; + memcpy(&pszDst[offDst], s_aFlags[i].pszMnemonic, s_aFlags[i].cchMnemonic); + offDst += s_aFlags[i].cchMnemonic; + } + Assert(fFlags == 0); + Assert(offDst < PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN); + + if (offDst) + pszDst[offDst - 1] = '\0'; + else + memcpy(pszDst, "NONE", sizeof("NONE")); + return pszDst; +} + +/** + * Logs an audio device enumeration. + * + * @param pDevEnm Device enumeration to log. + * @param pszDesc Logging description (prefix). + */ +DECLINLINE(void) PDMAudioHostEnumLog(PCPDMAUDIOHOSTENUM pDevEnm, const char *pszDesc) +{ +#ifdef LOG_ENABLED + AssertPtrReturnVoid(pDevEnm); + AssertPtrReturnVoid(pszDesc); + AssertReturnVoid(pDevEnm->uMagic == PDMAUDIOHOSTENUM_MAGIC); + + if (LogIsEnabled()) + { + LogFunc(("%s: %RU32 devices\n", pszDesc, pDevEnm->cDevices)); + + PPDMAUDIOHOSTDEV pDev; + RTListForEach(&pDevEnm->LstDevices, pDev, PDMAUDIOHOSTDEV, ListEntry) + { + char szFlags[PDMAUDIOHOSTDEV_MAX_FLAGS_STRING_LEN]; + LogFunc(("Device '%s':\n", pDev->pszName)); + LogFunc((" ID = %s\n", pDev->pszId ? pDev->pszId : "")); + LogFunc((" Usage = %s\n", PDMAudioDirGetName(pDev->enmUsage))); + LogFunc((" Flags = %s\n", PDMAudioHostDevFlagsToString(szFlags, pDev->fFlags))); + LogFunc((" Input channels = %RU8\n", pDev->cMaxInputChannels)); + LogFunc((" Output channels = %RU8\n", pDev->cMaxOutputChannels)); + LogFunc((" cbExtra = %RU32 bytes\n", pDev->cbSelf - sizeof(PDMAUDIOHOSTDEV))); + } + } +#else + RT_NOREF(pDevEnm, pszDesc); +#endif +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmaudiohostenuminline_h */ diff --git a/include/VBox/vmm/pdmaudioifs.h b/include/VBox/vmm/pdmaudioifs.h new file mode 100644 index 00000000..11735f25 --- /dev/null +++ b/include/VBox/vmm/pdmaudioifs.h @@ -0,0 +1,1567 @@ +/** @file + * PDM - Pluggable Device Manager, Audio interfaces. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/** @page pg_pdm_audio PDM Audio + * + * PDM provides audio device emulations and their driver chains with the + * interfaces they need to communicate with each other. + * + * + * @section sec_pdm_audio_overview Overview + * +@startuml +skinparam componentStyle rectangle + +node VM { + [Music Player App] --> [Guest Audio Driver] + [Recording App] <-- [Guest Audio Driver] +} + +component "DevAudio (DevHda / DevIchAc97 / DevSB16)" as DevAudio { + [Output DMA Engine] + [Input DMA Engine] + () LUN0 + () LUN1 + + component "AudioMixer" { + component "Output Sink" { + () "Output Stream #0" as DrvStreamOut0 + () "Output Stream #1" as DrvStreamOut1 + [Output Mixer Buffer] --> DrvStreamOut0 + [Output Mixer Buffer] --> DrvStreamOut1 + [Output DMA Engine] --> [Output Mixer Buffer] + DrvStreamOut0 --> LUN0 + DrvStreamOut1 --> LUN1 + } + component "Input Sink" { + () "Input Stream #2" as DrvStreamIn0 + () "Input Stream #3" as DrvStreamIn1 + [Input Mixer Buffer] <-- DrvStreamIn0 + [Input Mixer Buffer] <-- DrvStreamIn1 + [Input DMA Engine] --> [Input Mixer Buffer] + DrvStreamIn0 <-- LUN0 + DrvStreamIn1 <-- LUN1 + } + } +} +[Guest Audio Driver] <..> DevAudio : " MMIO or Port I/O, DMA" + +node "Driver Chain #0" { + component "DrvAudio#0" { + () PDMIHOSTAUDIOPORT0 + () PDMIAUDIOCONNECTOR0 + } + component "DrvHostAudioWasApi" { + () PDMIHOSTAUDIO0 + } +} +PDMIHOSTAUDIOPORT0 <--> PDMIHOSTAUDIO0 + +node "Driver Chain #1" { + component "DrvAudio#1" { + () PDMIAUDIOCONNECTOR1 + () PDMIHOSTAUDIOPORT1 + } + component "DrvAudioVRDE" { + () PDMIHOSTAUDIO1 + } +} +note bottom of DrvAudioVRDE + The backend driver is sometimes not configured if the component it represents + is not configured for the VM. However, Main will still set up the LUN but + with just DrvAudio attached to simplify runtime activation of the component. + In the meanwhile, the DrvAudio instance works as if DrvHostAudioNull were attached. +end note + +LUN1 <--> PDMIAUDIOCONNECTOR1 +LUN0 <--> PDMIAUDIOCONNECTOR0 + +PDMIHOSTAUDIOPORT1 <--> PDMIHOSTAUDIO1 + +@enduml + * + * Actors: + * - An audio device implementation: "DevAudio" + * - Mixer instance (AudioMixer.cpp) with one or more mixer + * sinks: "Output Sink", "Input Sink" + * - One DMA engine teamed up with each mixer sink: "Output DMA + * Engine", "Input DMA Engine" + * - The audio driver "DrvAudio" instances attached to LUN0 and LUN1 + * respectively: "DrvAudio#0", "DrvAudio#1" + * - The Windows host audio driver attached to "DrvAudio0": "DrvHostAudioWas" + * - The VRDE/VRDP host audio driver attached to "DrvAudio1": "DrvAudioVRDE" + * + * Both "Output Sink" and "Input Sink" talks to all the attached driver chains + * ("DrvAudio #0" and "DrvAudio #1"), but using different PDMAUDIOSTREAM + * instances. There can be an arbritrary number of driver chains attached to an + * audio device, the mixer sinks will multiplex output to each of them and blend + * input from all of them, taking care of format and rate conversions. The + * mixer and mixer sinks does not fit into the PDM device/driver model, because + * a driver can only have exactly one or zero other drivers attached, so it is + * implemented as a separate component that all the audio devices share (see + * AudioMixer.h, AudioMixer.cpp, AudioMixBuffer.h and AudioMixBuffer.cpp). + * + * The driver chains attached to LUN0, LUN1, ... LUNn typically have two + * drivers attached, first DrvAudio and then a backend driver like + * DrvHostAudioWasApi, DrvHostAudioPulseAudio, or DrvAudioVRDE. DrvAudio + * exposes PDMIAUDIOCONNECTOR upwards towards the device and mixer component, + * and PDMIHOSTAUDIOPORT downwards towards DrvHostAudioWasApi and the other + * backends. + * + * The backend exposes the PDMIHOSTAUDIO upwards towards DrvAudio. It is + * possible, though, to only have the DrvAudio instance and not backend, in + * which case DrvAudio works as if the NULL backend was attached. Main does + * such setups when the main component we're interfacing with isn't currently + * active, as this simplifies runtime activation. + * + * The purpose of DrvAudio is to make the work of the backend as simple as + * possible and try avoid needing to write the same code over and over again for + * each backend. It takes care of: + * - Stream creation, operation, re-initialization and destruction. + * - Pre-buffering. + * - Thread pool. + * + * The purpose of a host audio driver (aka backend) is to interface with the + * host audio system (or other audio systems like VRDP and video recording). + * The backend will optionally provide a list of host audio devices, switch + * between them, and monitor changes to them. By default our host backends use + * the default host device and will trigger stream re-initialization if this + * changes while we're using it. + * + * + * @section sec_pdm_audio_device Virtual Audio Device + * + * The virtual device translates the settings of the emulated device into mixing + * sinks with sample format, sample rate, volume control, and whatnot. + * + * It also implements a DMA engine for transfering samples to (input) or from + * (output) the guest memory. The starting and stopping of the DMA engines are + * communicated to the associated mixing sinks and by then onto the + * PDMAUDIOSTREAM instance for each driver chain. A RTCIRCBUF is used as an + * intermediary between the DMA engine and the asynchronous worker thread of the + * mixing sink. + * + * + * @section sec_pdm_audio_mixing Audio Mixing + * + * The audio mixer is a mandatory component in an audio device. It consists of + * a mixer and one or more sinks with mixer buffers. The sinks are typically + * one per virtual output/input connector, so for instance you could have a + * device with a "PCM Output" sink and a "PCM Input" sink. + * + * The audio mixer takes care of: + * - Much of the driver chain (LUN) management work. + * - Multiplexing output to each active driver chain. + * - Blending input from each active driver chain into a single audio + * stream. + * - Do format conversion (it uses signed 32-bit PCM internally) between + * the audio device and all of the LUNs (no common format needed). + * - Do sample rate conversions between the device rate and that of the + * individual driver chains. + * - Apply the volume settings of the device to the audio stream. + * - Provide the asynchronous thread that pushes data from the device's + * internal DMA buffer and all the way to the backend for output sinks, + * and vice versa for input. + * + * The term active LUNs above means that not all LUNs will actually produce + * (input) or consume (output) audio. The mixer checks the return of + * PDMIHOSTAUDIO::pfnStreamGetState each time it's processing samples to see + * which streams are currently active and which aren't. Inactive streams are + * ignored. + * + * For more info: @ref pg_audio_mixer, @ref pg_audio_mixing_buffers + * + * The AudioMixer API reference can be found here: + * - @ref grp_pdm_ifs_audio_mixing + * - @ref grp_pdm_ifs_audio_mixing_buffers + * + * + * @section sec_pdm_audio_timing Timing + * + * Handling audio data in a virtual environment is hard, as the human perception + * is very sensitive to the slightest cracks and stutters in the audible data, + * and the task of playing back and recording audio is in the real-time domain. + * + * The virtual machine is not executed with any real-time guarentees, only best + * effort, mainly because it is subject to preemptive scheduling on the host + * side. The audio processing done on the guest side is typically also subject + * to preemptive scheduling on the guest side and available CPU processing power + * there. + * + * Thus, the guest may be lagging behind because the host prioritizes other + * processes/threads over the virtual machine. This will, if it's too servere, + * cause the virtual machine to speed up it's time sense while it's trying to + * catch up. So, we can easily have a bit of a seesaw execution going on here, + * where in the playback case, the guest produces data too slowly for while and + * then switches to producing it too quickly for a while to catch up. + * + * Our working principle is that the backends and the guest are producing and + * consuming samples at the same rate, but we have to deal with the uneven + * execution. + * + * To deal with this we employ (by default) 300ms of backend buffer and + * pre-buffer 150ms of that for both input and output audio streams. This means + * we have about 150ms worth of samples to feed to the host audio device should + * the virtual machine be starving and lagging behind. Likewise, we have about + * 150ms of buffer space will can fill when the VM is in a catch-up mode. Now, + * 300ms and 150 ms isn't much for the purpose of glossing over + * scheduling/timing differences here, but we can't do too much more or the lag + * will grow rather annoying. The pre-buffering is implemented by DrvAudio. + * + * In addition to the backend buffer that defaults to 300ms, we have the + * internal DMA buffer of the device and the mixing buffer of the mixing sink. + * The latter two are typically rather small, sized to fit the anticipated DMA + * period currently in use by the guest. + */ + +#ifndef VBOX_INCLUDED_vmm_pdmaudioifs_h +#define VBOX_INCLUDED_vmm_pdmaudioifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include + +#include +#include +#include + +RT_C_DECLS_BEGIN + + +/** @defgroup grp_pdm_ifs_audio PDM Audio Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + +/** The maximum number of channels PDM supports. */ +#define PDMAUDIO_MAX_CHANNELS 12 + +/** + * Audio direction. + */ +typedef enum PDMAUDIODIR +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIODIR_INVALID = 0, + /** Unknown direction. */ + PDMAUDIODIR_UNKNOWN, + /** Input. */ + PDMAUDIODIR_IN, + /** Output. */ + PDMAUDIODIR_OUT, + /** Duplex handling. */ + PDMAUDIODIR_DUPLEX, + /** End of valid values. */ + PDMAUDIODIR_END, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIODIR_32BIT_HACK = 0x7fffffff +} PDMAUDIODIR; + + +/** @name PDMAUDIOHOSTDEV_F_XXX + * @{ */ +/** No flags set. */ +#define PDMAUDIOHOSTDEV_F_NONE UINT32_C(0) +/** The default input (capture/recording) device (for the user). */ +#define PDMAUDIOHOSTDEV_F_DEFAULT_IN RT_BIT_32(0) +/** The default output (playback) device (for the user). */ +#define PDMAUDIOHOSTDEV_F_DEFAULT_OUT RT_BIT_32(1) +/** The device can be removed at any time and we have to deal with it. */ +#define PDMAUDIOHOSTDEV_F_HOTPLUG RT_BIT_32(2) +/** The device is known to be buggy and needs special treatment. */ +#define PDMAUDIOHOSTDEV_F_BUGGY RT_BIT_32(3) +/** Ignore the device, no matter what. */ +#define PDMAUDIOHOSTDEV_F_IGNORE RT_BIT_32(4) +/** The device is present but marked as locked by some other application. */ +#define PDMAUDIOHOSTDEV_F_LOCKED RT_BIT_32(5) +/** The device is present but not in an alive state (dead). */ +#define PDMAUDIOHOSTDEV_F_DEAD RT_BIT_32(6) +/** Set if the PDMAUDIOHOSTDEV::pszName is allocated. */ +#define PDMAUDIOHOSTDEV_F_NAME_ALLOC RT_BIT_32(29) +/** Set if the PDMAUDIOHOSTDEV::pszId is allocated. */ +#define PDMAUDIOHOSTDEV_F_ID_ALLOC RT_BIT_32(30) +/** Set if the extra backend specific data cannot be duplicated. */ +#define PDMAUDIOHOSTDEV_F_NO_DUP RT_BIT_32(31) +/** @} */ + +/** + * Audio device type. + */ +typedef enum PDMAUDIODEVICETYPE +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIODEVICETYPE_INVALID = 0, + /** Unknown device type. This is the default. */ + PDMAUDIODEVICETYPE_UNKNOWN, + /** Dummy device; for backends which are not able to report + * actual device information (yet). */ + PDMAUDIODEVICETYPE_DUMMY, + /** The device is built into the host (non-removable). */ + PDMAUDIODEVICETYPE_BUILTIN, + /** The device is an (external) USB device. */ + PDMAUDIODEVICETYPE_USB, + /** End of valid values. */ + PDMAUDIODEVICETYPE_END, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIODEVICETYPE_32BIT_HACK = 0x7fffffff +} PDMAUDIODEVICETYPE; + +/** + * Host audio device info, part of enumeration result. + * + * @sa PDMAUDIOHOSTENUM, PDMIHOSTAUDIO::pfnGetDevices + */ +typedef struct PDMAUDIOHOSTDEV +{ + /** List entry (like PDMAUDIOHOSTENUM::LstDevices). */ + RTLISTNODE ListEntry; + /** Magic value (PDMAUDIOHOSTDEV_MAGIC). */ + uint32_t uMagic; + /** Size of this structure and whatever backend specific data that follows it. */ + uint32_t cbSelf; + /** The device type. */ + PDMAUDIODEVICETYPE enmType; + /** Usage of the device. */ + PDMAUDIODIR enmUsage; + /** Device flags, PDMAUDIOHOSTDEV_F_XXX. */ + uint32_t fFlags; + /** Maximum number of input audio channels the device supports. */ + uint8_t cMaxInputChannels; + /** Maximum number of output audio channels the device supports. */ + uint8_t cMaxOutputChannels; + uint8_t abAlignment[ARCH_BITS == 32 ? 2 + 8 : 2 + 8]; + /** Backend specific device identifier, can be NULL, used to select device. + * This can either point into some non-public part of this structure or to a + * RTStrAlloc allocation. PDMAUDIOHOSTDEV_F_ID_ALLOC is set in the latter + * case. + * @sa PDMIHOSTAUDIO::pfnSetDevice */ + char *pszId; + /** The friendly device name. */ + char *pszName; +} PDMAUDIOHOSTDEV; +AssertCompileSizeAlignment(PDMAUDIOHOSTDEV, 16); +/** Pointer to audio device info (enumeration result). */ +typedef PDMAUDIOHOSTDEV *PPDMAUDIOHOSTDEV; +/** Pointer to a const audio device info (enumeration result). */ +typedef PDMAUDIOHOSTDEV const *PCPDMAUDIOHOSTDEV; + +/** Magic value for PDMAUDIOHOSTDEV. */ +#define PDMAUDIOHOSTDEV_MAGIC PDM_VERSION_MAKE(0xa0d0, 3, 0) + + +/** + * A host audio device enumeration result. + * + * @sa PDMIHOSTAUDIO::pfnGetDevices + */ +typedef struct PDMAUDIOHOSTENUM +{ + /** Magic value (PDMAUDIOHOSTENUM_MAGIC). */ + uint32_t uMagic; + /** Number of audio devices in the list. */ + uint32_t cDevices; + /** List of audio devices (PDMAUDIOHOSTDEV). */ + RTLISTANCHOR LstDevices; +} PDMAUDIOHOSTENUM; +/** Pointer to an audio device enumeration result. */ +typedef PDMAUDIOHOSTENUM *PPDMAUDIOHOSTENUM; +/** Pointer to a const audio device enumeration result. */ +typedef PDMAUDIOHOSTENUM const *PCPDMAUDIOHOSTENUM; + +/** Magic for the host audio device enumeration. */ +#define PDMAUDIOHOSTENUM_MAGIC PDM_VERSION_MAKE(0xa0d1, 1, 0) + + +/** + * Audio configuration (static) of an audio host backend. + */ +typedef struct PDMAUDIOBACKENDCFG +{ + /** The backend's friendly name. */ + char szName[32]; + /** The size of the backend specific stream data (in bytes). */ + uint32_t cbStream; + /** PDMAUDIOBACKEND_F_XXX. */ + uint32_t fFlags; + /** Number of concurrent output (playback) streams supported on the host. + * UINT32_MAX for unlimited concurrent streams, 0 if no concurrent input streams are supported. */ + uint32_t cMaxStreamsOut; + /** Number of concurrent input (recording) streams supported on the host. + * UINT32_MAX for unlimited concurrent streams, 0 if no concurrent input streams are supported. */ + uint32_t cMaxStreamsIn; +} PDMAUDIOBACKENDCFG; +/** Pointer to a static host audio audio configuration. */ +typedef PDMAUDIOBACKENDCFG *PPDMAUDIOBACKENDCFG; + +/** @name PDMAUDIOBACKEND_F_XXX - PDMAUDIOBACKENDCFG::fFlags + * @{ */ +/** PDMIHOSTAUDIO::pfnStreamConfigHint should preferably be called on a + * worker thread rather than EMT as it may take a good while. */ +#define PDMAUDIOBACKEND_F_ASYNC_HINT RT_BIT_32(0) +/** PDMIHOSTAUDIO::pfnStreamDestroy and any preceeding + * PDMIHOSTAUDIO::pfnStreamControl/DISABLE should be preferably be called on a + * worker thread rather than EMT as it may take a good while. */ +#define PDMAUDIOBACKEND_F_ASYNC_STREAM_DESTROY RT_BIT_32(1) +/** @} */ + + +/** + * Audio path: input sources and playback destinations. + * + * Think of this as the name of the socket you plug the virtual audio stream + * jack into. + * + * @note Not quite sure what the purpose of this type is. It used to be two + * separate enums (PDMAUDIOPLAYBACKDST & PDMAUDIORECSRC) without overlapping + * values and most commonly used in a union (PDMAUDIODSTSRCUNION). The output + * values were designated "channel" (e.g. "Front channel"), whereas this was not + * done to the input ones. So, I'm (bird) a little confused what the actual + * meaning was. + */ +typedef enum PDMAUDIOPATH +{ + /** Customary invalid zero value. */ + PDMAUDIOPATH_INVALID = 0, + + /** Unknown path / Doesn't care. */ + PDMAUDIOPATH_UNKNOWN, + + /** First output value. */ + PDMAUDIOPATH_OUT_FIRST, + /** Output: Front. */ + PDMAUDIOPATH_OUT_FRONT = PDMAUDIOPATH_OUT_FIRST, + /** Output: Center / LFE (Subwoofer). */ + PDMAUDIOPATH_OUT_CENTER_LFE, + /** Output: Rear. */ + PDMAUDIOPATH_OUT_REAR, + /** Last output value (inclusive) */ + PDMAUDIOPATH_OUT_END = PDMAUDIOPATH_OUT_REAR, + + /** First input value. */ + PDMAUDIOPATH_IN_FIRST, + /** Input: Microphone. */ + PDMAUDIOPATH_IN_MIC = PDMAUDIOPATH_IN_FIRST, + /** Input: CD. */ + PDMAUDIOPATH_IN_CD, + /** Input: Video-In. */ + PDMAUDIOPATH_IN_VIDEO, + /** Input: AUX. */ + PDMAUDIOPATH_IN_AUX, + /** Input: Line-In. */ + PDMAUDIOPATH_IN_LINE, + /** Input: Phone-In. */ + PDMAUDIOPATH_IN_PHONE, + /** Last intput value (inclusive). */ + PDMAUDIOPATH_IN_LAST = PDMAUDIOPATH_IN_PHONE, + + /** End of valid values. */ + PDMAUDIOPATH_END, + /** Hack to blow the typ up to 32 bits. */ + PDMAUDIOPATH_32BIT_HACK = 0x7fffffff +} PDMAUDIOPATH; + + +/** + * Standard speaker channel IDs. + */ +typedef enum PDMAUDIOCHANNELID +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIOCHANNELID_INVALID = 0, + + /** Unused channel - fill with zero when encoding, ignore when decoding. */ + PDMAUDIOCHANNELID_UNUSED_ZERO, + /** Unused channel - fill with silence when encoding, ignore when decoding. */ + PDMAUDIOCHANNELID_UNUSED_SILENCE, + + /** Unknown channel ID (unable to map to PDM terms). */ + PDMAUDIOCHANNELID_UNKNOWN, + + /** The first ID in the standard WAV-file assignment block. */ + PDMAUDIOCHANNELID_FIRST_STANDARD, + /** Front left channel (FR). */ + PDMAUDIOCHANNELID_FRONT_LEFT = PDMAUDIOCHANNELID_FIRST_STANDARD, + /** Front right channel (FR). */ + PDMAUDIOCHANNELID_FRONT_RIGHT, + /** Front center channel (FC). */ + PDMAUDIOCHANNELID_FRONT_CENTER, + /** Mono channel (alias for front center). */ + PDMAUDIOCHANNELID_MONO = PDMAUDIOCHANNELID_FRONT_CENTER, + /** Low frequency effects (subwoofer) channel. */ + PDMAUDIOCHANNELID_LFE, + /** Rear left channel (BL). */ + PDMAUDIOCHANNELID_REAR_LEFT, + /** Rear right channel (BR). */ + PDMAUDIOCHANNELID_REAR_RIGHT, + /** Front left of center channel (FLC). */ + PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER, + /** Front right of center channel (FLR). */ + PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER, + /** Rear center channel (BC). */ + PDMAUDIOCHANNELID_REAR_CENTER, + /** Side left channel (SL). */ + PDMAUDIOCHANNELID_SIDE_LEFT, + /** Side right channel (SR). */ + PDMAUDIOCHANNELID_SIDE_RIGHT, + /** Top center (TC). */ + PDMAUDIOCHANNELID_TOP_CENTER, + /** Front left height channel (TFL). */ + PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT, + /** Front center height channel (TFC). */ + PDMAUDIOCHANNELID_FRONT_CENTER_HEIGHT, + /** Front right height channel (TFR). */ + PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT, + /** Rear left height channel (TBL). */ + PDMAUDIOCHANNELID_REAR_LEFT_HEIGHT, + /** Rear center height channel (TBC). */ + PDMAUDIOCHANNELID_REAR_CENTER_HEIGHT, + /** Rear right height channel (TBR). */ + PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT, + /** The end of the standard WAV-file assignment block. */ + PDMAUDIOCHANNELID_END_STANDARD, + + /** End of valid values. */ + PDMAUDIOCHANNELID_END = PDMAUDIOCHANNELID_END_STANDARD, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIOCHANNELID_32BIT_HACK = 0x7fffffff +} PDMAUDIOCHANNELID; +AssertCompile(PDMAUDIOCHANNELID_FRONT_LEFT - PDMAUDIOCHANNELID_FIRST_STANDARD == 0); +AssertCompile(PDMAUDIOCHANNELID_LFE - PDMAUDIOCHANNELID_FIRST_STANDARD == 3); +AssertCompile(PDMAUDIOCHANNELID_REAR_CENTER - PDMAUDIOCHANNELID_FIRST_STANDARD == 8); +AssertCompile(PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT - PDMAUDIOCHANNELID_FIRST_STANDARD == 17); + + +/** + * Properties of audio streams for host/guest for in or out directions. + */ +typedef struct PDMAUDIOPCMPROPS +{ + /** The frame size. */ + uint8_t cbFrame; + /** Shift count used with PDMAUDIOPCMPROPS_F2B and PDMAUDIOPCMPROPS_B2F. + * Depends on number of stream channels and the stream format being used, calc + * value using PDMAUDIOPCMPROPS_MAKE_SHIFT. + * @sa PDMAUDIOSTREAMCFG_B2F, PDMAUDIOSTREAMCFG_F2B */ + uint8_t cShiftX; + /** Sample width (in bytes). */ + RT_GCC_EXTENSION + uint8_t cbSampleX : 4; + /** Number of audio channels. */ + RT_GCC_EXTENSION + uint8_t cChannelsX : 4; + /** Signed or unsigned sample. */ + bool fSigned : 1; + /** Whether the endianness is swapped or not. */ + bool fSwapEndian : 1; + /** Raw mixer frames, only applicable for signed 64-bit samples. + * The raw mixer samples are really just signed 32-bit samples stored as 64-bit + * integers without any change in the value. + * + * @todo Get rid of this, only VRDE needs it an it should use the common + * mixer code rather than cooking its own stuff. */ + bool fRaw : 1; + /** Sample frequency in Hertz (Hz). */ + uint32_t uHz; + /** PDMAUDIOCHANNELID mappings for each channel. + * This ASSUMES all channels uses the same sample size. */ + uint8_t aidChannels[PDMAUDIO_MAX_CHANNELS]; + /** Padding the structure up to 32 bytes. */ + uint32_t auPadding[3]; +} PDMAUDIOPCMPROPS; +AssertCompileSize(PDMAUDIOPCMPROPS, 32); +AssertCompileSizeAlignment(PDMAUDIOPCMPROPS, 8); +/** Pointer to audio stream properties. */ +typedef PDMAUDIOPCMPROPS *PPDMAUDIOPCMPROPS; +/** Pointer to const audio stream properties. */ +typedef PDMAUDIOPCMPROPS const *PCPDMAUDIOPCMPROPS; + +/** @name Macros for use with PDMAUDIOPCMPROPS + * @{ */ +/** Initializer for PDMAUDIOPCMPROPS. + * @note The default channel mapping here is very simple and doesn't always + * match that of PDMAudioPropsInit and PDMAudioPropsInitEx. */ +#define PDMAUDIOPCMPROPS_INITIALIZER(a_cbSample, a_fSigned, a_cChannels, a_uHz, a_fSwapEndian) \ + { \ + (uint8_t)((a_cbSample) * (a_cChannels)), PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(a_cbSample, a_cChannels), \ + (uint8_t)(a_cbSample), (uint8_t)(a_cChannels), a_fSigned, a_fSwapEndian, false /*fRaw*/, a_uHz, \ + /*aidChannels =*/ { \ + (a_cChannels) > 1 ? PDMAUDIOCHANNELID_FRONT_LEFT : PDMAUDIOCHANNELID_MONO, \ + (a_cChannels) >= 2 ? PDMAUDIOCHANNELID_FRONT_RIGHT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 3 ? PDMAUDIOCHANNELID_FRONT_CENTER : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 4 ? PDMAUDIOCHANNELID_LFE : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 5 ? PDMAUDIOCHANNELID_REAR_LEFT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 6 ? PDMAUDIOCHANNELID_REAR_RIGHT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 7 ? PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 8 ? PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 9 ? PDMAUDIOCHANNELID_REAR_CENTER : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 10 ? PDMAUDIOCHANNELID_SIDE_LEFT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 11 ? PDMAUDIOCHANNELID_SIDE_RIGHT : PDMAUDIOCHANNELID_INVALID, \ + (a_cChannels) >= 12 ? PDMAUDIOCHANNELID_UNKNOWN : PDMAUDIOCHANNELID_INVALID, \ + }, \ + /* auPadding = */ { 0, 0, 0 } \ + } + +/** Calculates the cShift value of given sample bits and audio channels. + * @note Does only support mono/stereo channels for now, for non-stereo/mono we + * returns a special value which the two conversion functions detect + * and make them fall back on cbSample * cChannels. */ +#define PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels) \ + ( RT_IS_POWER_OF_TWO((unsigned)((cChannels) * (cbSample))) \ + ? (uint8_t)(ASMBitFirstSetU32((unsigned)((cChannels) * (cbSample))) - 1) : (uint8_t)UINT8_MAX ) +/** Calculates the cShift value of a PDMAUDIOPCMPROPS structure. */ +#define PDMAUDIOPCMPROPS_MAKE_SHIFT(pProps) \ + PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS((pProps)->cbSampleX, (pProps)->cChannelsX) +/** Converts (audio) frames to bytes. + * @note Requires properly initialized properties, i.e. cbFrames correctly calculated + * and cShift set using PDMAUDIOPCMPROPS_MAKE_SHIFT. */ +#define PDMAUDIOPCMPROPS_F2B(pProps, cFrames) \ + ( (pProps)->cShiftX != UINT8_MAX ? (cFrames) << (pProps)->cShiftX : (cFrames) * (pProps)->cbFrame ) +/** Converts bytes to (audio) frames. + * @note Requires properly initialized properties, i.e. cbFrames correctly calculated + * and cShift set using PDMAUDIOPCMPROPS_MAKE_SHIFT. */ +#define PDMAUDIOPCMPROPS_B2F(pProps, cb) \ + ( (pProps)->cShiftX != UINT8_MAX ? (cb) >> (pProps)->cShiftX : (cb) / (pProps)->cbFrame ) +/** @} */ + +/** + * An audio stream configuration. + */ +typedef struct PDMAUDIOSTREAMCFG +{ + /** The stream's PCM properties. */ + PDMAUDIOPCMPROPS Props; + /** Direction of the stream. */ + PDMAUDIODIR enmDir; + /** Destination / source path. */ + PDMAUDIOPATH enmPath; + /** Device emulation-specific data needed for the audio connector. */ + struct + { + /** Scheduling hint set by the device emulation about when this stream is being served on average (in ms). + * Can be 0 if not hint given or some other mechanism (e.g. callbacks) is being used. */ + uint32_t cMsSchedulingHint; + } Device; + /** + * Backend-specific data for the stream. + * On input (requested configuration) those values are set by the audio connector to let the backend know what we expect. + * On output (acquired configuration) those values reflect the values set and used by the backend. + * Set by the backend on return. Not all backends support all values / features. + */ + struct + { + /** Period size of the stream (in audio frames). + * This value reflects the number of audio frames in between each hardware interrupt on the + * backend (host) side. 0 if not set / available by the backend. */ + uint32_t cFramesPeriod; + /** (Ring) buffer size (in audio frames). Often is a multiple of cFramesPeriod. + * 0 if not set / available by the backend. */ + uint32_t cFramesBufferSize; + /** Pre-buffering size (in audio frames). Frames needed in buffer before the stream becomes active (pre buffering). + * The bigger this value is, the more latency for the stream will occur. + * 0 if not set / available by the backend. UINT32_MAX if not defined (yet). */ + uint32_t cFramesPreBuffering; + } Backend; + /** Friendly name of the stream. */ + char szName[64]; +} PDMAUDIOSTREAMCFG; +AssertCompileSizeAlignment(PDMAUDIOSTREAMCFG, 8); +/** Pointer to audio stream configuration keeper. */ +typedef PDMAUDIOSTREAMCFG *PPDMAUDIOSTREAMCFG; +/** Pointer to a const audio stream configuration keeper. */ +typedef PDMAUDIOSTREAMCFG const *PCPDMAUDIOSTREAMCFG; + +/** Converts (audio) frames to bytes. */ +#define PDMAUDIOSTREAMCFG_F2B(pCfg, frames) PDMAUDIOPCMPROPS_F2B(&(pCfg)->Props, (frames)) +/** Converts bytes to (audio) frames. */ +#define PDMAUDIOSTREAMCFG_B2F(pCfg, cb) PDMAUDIOPCMPROPS_B2F(&(pCfg)->Props, (cb)) + +/** + * Audio stream commands. + * + * Used in the audio connector as well as in the actual host backends. + */ +typedef enum PDMAUDIOSTREAMCMD +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIOSTREAMCMD_INVALID = 0, + /** Enables the stream. */ + PDMAUDIOSTREAMCMD_ENABLE, + /** Pauses the stream. + * This is currently only issued when the VM is suspended (paused). + * @remarks This is issued by DrvAudio, never by the mixer or devices. */ + PDMAUDIOSTREAMCMD_PAUSE, + /** Resumes the stream. + * This is currently only issued when the VM is resumed. + * @remarks This is issued by DrvAudio, never by the mixer or devices. */ + PDMAUDIOSTREAMCMD_RESUME, + /** Drain the stream, that is, play what's in the buffers and then stop. + * + * There will be no more samples written after this command is issued. + * PDMIAUDIOCONNECTOR::pfnStreamIterate will drive progress for DrvAudio and + * calls to PDMIHOSTAUDIO::pfnStreamPlay with a zero sized buffer will provide + * the backend with a way to drive it forwards. These calls will come at a + * frequency set by the device and be on an asynchronous I/O thread. + * + * A DISABLE command maybe submitted if the device/mixer wants to re-enable the + * stream while it's still draining or if it gets impatient and thinks the + * draining has been going on too long, in which case the stream should stop + * immediately. + * + * @note This should not wait for the stream to finish draining, just change + * the state. (The caller could be an EMT and it must not block for + * hundreds of milliseconds of buffer to finish draining.) + * + * @note Does not apply to input streams. Backends should refuse such requests. */ + PDMAUDIOSTREAMCMD_DRAIN, + /** Stops the stream immediately w/o any draining. */ + PDMAUDIOSTREAMCMD_DISABLE, + /** End of valid values. */ + PDMAUDIOSTREAMCMD_END, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIOSTREAMCMD_32BIT_HACK = 0x7fffffff +} PDMAUDIOSTREAMCMD; + +/** + * Backend status. + */ +typedef enum PDMAUDIOBACKENDSTS +{ + /** Unknown/invalid status. */ + PDMAUDIOBACKENDSTS_UNKNOWN = 0, + /** No backend attached. */ + PDMAUDIOBACKENDSTS_NOT_ATTACHED, + /** The backend is in its initialization phase. + * Not all backends support this status. */ + PDMAUDIOBACKENDSTS_INITIALIZING, + /** The backend has stopped its operation. */ + PDMAUDIOBACKENDSTS_STOPPED, + /** The backend is up and running. */ + PDMAUDIOBACKENDSTS_RUNNING, + /** The backend ran into an error and is unable to recover. + * A manual re-initialization might help. */ + PDMAUDIOBACKENDSTS_ERROR, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIOBACKENDSTS_32BIT_HACK = 0x7fffffff +} PDMAUDIOBACKENDSTS; + +/** + * PDM audio stream state. + * + * This is all the mixer/device needs. The PDMAUDIOSTREAM_STS_XXX stuff will + * become DrvAudio internal state once the backend stuff is destilled out of it. + * + * @note The value order is significant, don't change it willy-nilly. + */ +typedef enum PDMAUDIOSTREAMSTATE +{ + /** Invalid state value. */ + PDMAUDIOSTREAMSTATE_INVALID = 0, + /** The stream is not operative and cannot be enabled. */ + PDMAUDIOSTREAMSTATE_NOT_WORKING, + /** The stream needs to be re-initialized by the device/mixer + * (i.e. call PDMIAUDIOCONNECTOR::pfnStreamReInit). */ + PDMAUDIOSTREAMSTATE_NEED_REINIT, + /** The stream is inactive (not enabled). */ + PDMAUDIOSTREAMSTATE_INACTIVE, + /** The stream is enabled but nothing to read/write. + * @todo not sure if we need this variant... */ + PDMAUDIOSTREAMSTATE_ENABLED, + /** The stream is enabled and captured samples can be read. */ + PDMAUDIOSTREAMSTATE_ENABLED_READABLE, + /** The stream is enabled and samples can be written for playback. */ + PDMAUDIOSTREAMSTATE_ENABLED_WRITABLE, + /** End of valid states. */ + PDMAUDIOSTREAMSTATE_END, + /** Make sure the type is 32-bit wide. */ + PDMAUDIOSTREAMSTATE_32BIT_HACK = 0x7fffffff +} PDMAUDIOSTREAMSTATE; + +/** @name PDMAUDIOSTREAM_CREATE_F_XXX + * @{ */ +/** Does not need any mixing buffers, the device takes care of all conversion. + * @note this is now default and assumed always set. */ +#define PDMAUDIOSTREAM_CREATE_F_NO_MIXBUF RT_BIT_32(0) +/** @} */ + +/** @name PDMAUDIOSTREAM_WARN_FLAGS_XXX + * @{ */ +/** No stream warning flags set. */ +#define PDMAUDIOSTREAM_WARN_FLAGS_NONE 0 +/** Warned about a disabled stream. */ +#define PDMAUDIOSTREAM_WARN_FLAGS_DISABLED RT_BIT(0) +/** @} */ + +/** + * An input or output audio stream. + */ +typedef struct PDMAUDIOSTREAM +{ + /** Critical section protecting the stream. + * + * When not otherwise stated, DrvAudio will enter this before calling the + * backend. The backend and device/mixer can normally safely enter it prior to + * a DrvAudio call, however not to pfnStreamDestroy, pfnStreamRelease or + * anything that may access the stream list. + * + * @note Lock ordering: + * - After DRVAUDIO::CritSectGlobals. + * - Before DRVAUDIO::CritSectHotPlug. */ + RTCRITSECT CritSect; + /** Stream configuration. */ + PDMAUDIOSTREAMCFG Cfg; + /** Magic value (PDMAUDIOSTREAM_MAGIC). */ + uint32_t uMagic; + /** Size (in bytes) of the backend-specific stream data. */ + uint32_t cbBackend; + /** Warnings shown already in the release log. + * See PDMAUDIOSTREAM_WARN_FLAGS_XXX. */ + uint32_t fWarningsShown; +} PDMAUDIOSTREAM; +/** Pointer to an audio stream. */ +typedef struct PDMAUDIOSTREAM *PPDMAUDIOSTREAM; +/** Pointer to a const audio stream. */ +typedef struct PDMAUDIOSTREAM const *PCPDMAUDIOSTREAM; + +/** Magic value for PDMAUDIOSTREAM. */ +#define PDMAUDIOSTREAM_MAGIC PDM_VERSION_MAKE(0xa0d3, 5, 0) + + + +/** Pointer to a audio connector interface. */ +typedef struct PDMIAUDIOCONNECTOR *PPDMIAUDIOCONNECTOR; + +/** + * Audio connector interface (up). + */ +typedef struct PDMIAUDIOCONNECTOR +{ + /** + * Enables or disables the given audio direction for this driver. + * + * When disabled, assiociated output streams consume written audio without passing them further down to the backends. + * Associated input streams then return silence when read from those. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmDir Audio direction to enable or disable driver for. + * @param fEnable Whether to enable or disable the specified audio direction. + * + * @note Be very careful when using this function, as this could + * violate / run against the (global) VM settings. See @bugref{9882}. + */ + DECLR3CALLBACKMEMBER(int, pfnEnable, (PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir, bool fEnable)); + + /** + * Returns whether the given audio direction for this driver is enabled or not. + * + * @returns True if audio is enabled for the given direction, false if not. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmDir Audio direction to retrieve enabled status for. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsEnabled, (PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir)); + + /** + * Retrieves the current configuration of the host audio backend. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pCfg Where to store the host audio backend configuration data. + */ + DECLR3CALLBACKMEMBER(int, pfnGetConfig, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOBACKENDCFG pCfg)); + + /** + * Retrieves the current status of the host audio backend. + * + * @returns Status of the host audio backend. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmDir Audio direction to check host audio backend for. Specify PDMAUDIODIR_DUPLEX for the overall + * backend status. + */ + DECLR3CALLBACKMEMBER(PDMAUDIOBACKENDSTS, pfnGetStatus, (PPDMIAUDIOCONNECTOR pInterface, PDMAUDIODIR enmDir)); + + /** + * Gives the audio drivers a hint about a typical configuration. + * + * This is a little hack for windows (and maybe other hosts) where stream + * creation can take a relatively long time, making it very unsuitable for EMT. + * The audio backend can use this hint to cache pre-configured stream setups, + * so that when the guest actually wants to play something EMT won't be blocked + * configuring host audio. + * + * @param pInterface Pointer to this interface. + * @param pCfg The typical configuration. Can be modified by the + * drivers in unspecified ways. + */ + DECLR3CALLBACKMEMBER(void, pfnStreamConfigHint, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAMCFG pCfg)); + + /** + * Creates an audio stream. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param fFlags PDMAUDIOSTREAM_CREATE_F_XXX. + * @param pCfgReq The requested stream configuration. The actual stream + * configuration can be found in pStream->Cfg on success. + * @param ppStream Pointer where to return the created audio stream on + * success. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamCreate, (PPDMIAUDIOCONNECTOR pInterface, uint32_t fFlags, PCPDMAUDIOSTREAMCFG pCfgReq, + PPDMAUDIOSTREAM *ppStream)); + + + /** + * Destroys an audio stream. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + * @param fImmediate Whether to immdiately stop and destroy a draining + * stream (@c true), or to allow it to complete + * draining first (@c false) if that's feasable. + * The latter depends on the draining stage and what + * the backend is capable of. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamDestroy, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, bool fImmediate)); + + /** + * Re-initializes the stream in response to PDMAUDIOSTREAM_STS_NEED_REINIT. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream The audio stream needing re-initialization. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamReInit, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Adds a reference to the specified audio stream. + * + * @returns New reference count. UINT32_MAX on error. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream adding the reference to. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamRetain, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Releases a reference from the specified stream. + * + * @returns New reference count. UINT32_MAX on error. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream releasing a reference from. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamRelease, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Controls a specific audio stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + * @param enmStreamCmd The stream command to issue. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamControl, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, + PDMAUDIOSTREAMCMD enmStreamCmd)); + + /** + * Processes stream data. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamIterate, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Returns the state of a specific audio stream (destilled status). + * + * @returns PDMAUDIOSTREAMSTATE value. + * @retval PDMAUDIOSTREAMSTATE_INVALID if the input isn't valid (w/ assertion). + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(PDMAUDIOSTREAMSTATE, pfnStreamGetState, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Returns the number of bytes that can be written to an audio output stream. + * + * @returns Number of bytes writable data. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetWritable, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Plays (writes to) an audio output stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream to read from. + * @param pvBuf Audio data to be written. + * @param cbBuf Number of bytes to be written. + * @param pcbWritten Bytes of audio data written. Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamPlay, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, + const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)); + + /** + * Returns the number of bytes that can be read from an input stream. + * + * @returns Number of bytes of readable data. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetReadable, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream)); + + /** + * Captures (reads) samples from an audio input stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream to write to. + * @param pvBuf Where to store the read data. + * @param cbBuf Number of bytes to read. + * @param pcbRead Bytes of audio data read. Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamCapture, (PPDMIAUDIOCONNECTOR pInterface, PPDMAUDIOSTREAM pStream, + void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)); +} PDMIAUDIOCONNECTOR; + +/** PDMIAUDIOCONNECTOR interface ID. */ +#define PDMIAUDIOCONNECTOR_IID "2900fe2a-6aeb-4953-ac12-f8965612f446" + + +/** + * Host audio backend specific stream data. + * + * The backend will put this as the first member of it's own data structure. + */ +typedef struct PDMAUDIOBACKENDSTREAM +{ + /** Magic value (PDMAUDIOBACKENDSTREAM_MAGIC). */ + uint32_t uMagic; + /** Explicit zero padding - do not touch! */ + uint32_t uReserved; + /** Pointer to the stream this backend data is associated with. */ + PPDMAUDIOSTREAM pStream; + /** Reserved for future use (zeroed) - do not touch. */ + void *apvReserved[2]; +} PDMAUDIOBACKENDSTREAM; +/** Pointer to host audio specific stream data! */ +typedef PDMAUDIOBACKENDSTREAM *PPDMAUDIOBACKENDSTREAM; + +/** Magic value for PDMAUDIOBACKENDSTREAM. */ +#define PDMAUDIOBACKENDSTREAM_MAGIC PDM_VERSION_MAKE(0xa0d4, 1, 0) + +/** + * Host audio (backend) stream state returned by PDMIHOSTAUDIO::pfnStreamGetState. + */ +typedef enum PDMHOSTAUDIOSTREAMSTATE +{ + /** Invalid zero value, as per usual. */ + PDMHOSTAUDIOSTREAMSTATE_INVALID = 0, + /** The stream is being initialized. + * This should also be used when switching to a new device and the stream + * stops to work with the old device while the new one being configured. */ + PDMHOSTAUDIOSTREAMSTATE_INITIALIZING, + /** The stream does not work (async init failed, audio subsystem gone + * fishing, or similar). */ + PDMHOSTAUDIOSTREAMSTATE_NOT_WORKING, + /** Backend is working okay. */ + PDMHOSTAUDIOSTREAMSTATE_OKAY, + /** Backend is working okay, but currently draining the stream. */ + PDMHOSTAUDIOSTREAMSTATE_DRAINING, + /** Backend is working but doesn't want any commands or data reads/writes. */ + PDMHOSTAUDIOSTREAMSTATE_INACTIVE, + /** End of valid values. */ + PDMHOSTAUDIOSTREAMSTATE_END, + /** Blow the type up to 32 bits. */ + PDMHOSTAUDIOSTREAMSTATE_32BIT_HACK = 0x7fffffff +} PDMHOSTAUDIOSTREAMSTATE; + + +/** Pointer to a host audio interface. */ +typedef struct PDMIHOSTAUDIO *PPDMIHOSTAUDIO; + +/** + * PDM host audio interface. + */ +typedef struct PDMIHOSTAUDIO +{ + /** + * Returns the host backend's configuration (backend). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pBackendCfg Where to store the backend audio configuration to. + */ + DECLR3CALLBACKMEMBER(int, pfnGetConfig, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDCFG pBackendCfg)); + + /** + * Returns (enumerates) host audio device information (optional). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pDeviceEnum Where to return the enumerated audio devices. + */ + DECLR3CALLBACKMEMBER(int, pfnGetDevices, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOHOSTENUM pDeviceEnum)); + + /** + * Changes the output or input device. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param enmDir The direction to set the device for: PDMAUDIODIR_IN, + * PDMAUDIODIR_OUT or PDMAUDIODIR_DUPLEX (both the + * previous). + * @param pszId The PDMAUDIOHOSTDEV::pszId value of the device to + * use, or NULL / empty string for the default device. + */ + DECLR3CALLBACKMEMBER(int, pfnSetDevice, (PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir, const char *pszId)); + + /** + * Returns the current status from the audio backend (optional). + * + * @returns PDMAUDIOBACKENDSTS enum. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmDir Audio direction to get status for. Pass PDMAUDIODIR_DUPLEX for overall status. + */ + DECLR3CALLBACKMEMBER(PDMAUDIOBACKENDSTS, pfnGetStatus, (PPDMIHOSTAUDIO pInterface, PDMAUDIODIR enmDir)); + + /** + * Callback for genric on-worker-thread requests initiated by the backend itself. + * + * This is the counterpart to PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread that will + * be invoked on a worker thread when the backend requests it - optional. + * + * This does not return a value, so the backend must keep track of + * failure/success on its own. + * + * This method is optional. A non-NULL will, together with pfnStreamInitAsync + * and PDMAUDIOBACKEND_F_ASYNC_HINT, force DrvAudio to create the thread pool. + * + * @param pInterface Pointer to this interface. + * @param pStream Optionally a backend stream if specified in the + * PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread() call. + * @param uUser User specific value as specified in the + * PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread() call. + * @param pvUser User specific pointer as specified in the + * PDMIHOSTAUDIOPORT::pfnDoOnWorkerThread() call. + */ + DECLR3CALLBACKMEMBER(void, pfnDoOnWorkerThread,(PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + uintptr_t uUser, void *pvUser)); + + /** + * Gives the audio backend a hint about a typical configuration (optional). + * + * This is a little hack for windows (and maybe other hosts) where stream + * creation can take a relatively long time, making it very unsuitable for EMT. + * The audio backend can use this hint to cache pre-configured stream setups, + * so that when the guest actually wants to play something EMT won't be blocked + * configuring host audio. + * + * The backend can return PDMAUDIOBACKEND_F_ASYNC_HINT in + * PDMIHOSTAUDIO::pfnGetConfig to avoid having EMT making this call and thereby + * speeding up VM construction. + * + * @param pInterface Pointer to this interface. + * @param pCfg The typical configuration. (Feel free to change it + * to the actual stream config that would be used, + * however caller will probably ignore this.) + */ + DECLR3CALLBACKMEMBER(void, pfnStreamConfigHint, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOSTREAMCFG pCfg)); + + /** + * Creates an audio stream using the requested stream configuration. + * + * If a backend is not able to create this configuration, it will return its + * best match in the acquired configuration structure on success. + * + * @returns VBox status code. + * @retval VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED if + * PDMIHOSTAUDIO::pfnStreamInitAsync should be called. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream. + * @param pCfgReq The requested stream configuration. + * @param pCfgAcq The acquired stream configuration - output. This is + * the same as @a *pCfgReq when called, the + * implementation will adjust it to make the actual + * stream configuration as needed. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamCreate, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + PCPDMAUDIOSTREAMCFG pCfgReq, PPDMAUDIOSTREAMCFG pCfgAcq)); + + /** + * Asynchronous stream initialization step, optional. + * + * This is called on a worker thread iff the PDMIHOSTAUDIO::pfnStreamCreate + * method returns VINF_AUDIO_STREAM_ASYNC_INIT_NEEDED. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to audio stream to continue + * initialization of. + * @param fDestroyed Set to @c true if the stream has been destroyed + * before the worker thread got to making this + * call. The backend should just ready the stream + * for destruction in that case. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamInitAsync, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, bool fDestroyed)); + + /** + * Destroys an audio stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface containing the called function. + * @param pStream Pointer to audio stream. + * @param fImmediate Whether to immdiately stop and destroy a draining + * stream (@c true), or to allow it to complete + * draining first (@c false) if that's feasable. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamDestroy, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, bool fImmediate)); + + /** + * Called from PDMIHOSTAUDIOPORT::pfnNotifyDeviceChanged so the backend can start + * the device change for a stream. + * + * This is mainly to avoid the need for a list of streams in the backend. + * + * @param pInterface Pointer to this interface. + * @param pStream Pointer to audio stream (locked). + * @param pvUser Backend specific parameter from the call to + * PDMIHOSTAUDIOPORT::pfnNotifyDeviceChanged. + */ + DECLR3CALLBACKMEMBER(void, pfnStreamNotifyDeviceChanged,(PPDMIHOSTAUDIO pInterface, + PPDMAUDIOBACKENDSTREAM pStream, void *pvUser)); + + /** + * Enables (starts) the stream. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to enable. + * @sa PDMAUDIOSTREAMCMD_ENABLE + */ + DECLR3CALLBACKMEMBER(int, pfnStreamEnable, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Disables (stops) the stream immediately. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to disable. + * @sa PDMAUDIOSTREAMCMD_DISABLE + */ + DECLR3CALLBACKMEMBER(int, pfnStreamDisable, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Pauses the stream - called when the VM is suspended. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to pause. + * @sa PDMAUDIOSTREAMCMD_PAUSE + */ + DECLR3CALLBACKMEMBER(int, pfnStreamPause, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Resumes a paused stream - called when the VM is resumed. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to resume. + * @sa PDMAUDIOSTREAMCMD_RESUME + */ + DECLR3CALLBACKMEMBER(int, pfnStreamResume, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Drain the stream, that is, play what's in the buffers and then stop. + * + * There will be no more samples written after this command is issued. + * PDMIHOSTAUDIO::pfnStreamPlay with a zero sized buffer will provide the + * backend with a way to drive it forwards. These calls will come at a + * frequency set by the device and be on an asynchronous I/O thread. + * + * The PDMIHOSTAUDIO::pfnStreamDisable method maybe called if the device/mixer + * wants to re-enable the stream while it's still draining or if it gets + * impatient and thinks the draining has been going on too long, in which case + * the stream should stop immediately. + * + * @note This should not wait for the stream to finish draining, just change + * the state. (The caller could be an EMT and it must not block for + * hundreds of milliseconds of buffer to finish draining.) + * + * @note Does not apply to input streams. Backends should refuse such + * requests. + * + * @returns VBox status code. + * @retval VERR_WRONG_ORDER if not output stream. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream to drain. + * @sa PDMAUDIOSTREAMCMD_DRAIN + */ + DECLR3CALLBACKMEMBER(int, pfnStreamDrain, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Returns the current state of the given backend stream. + * + * @returns PDMHOSTAUDIOSTREAMSTATE value. + * @retval PDMHOSTAUDIOSTREAMSTATE_INVALID if invalid stream. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(PDMHOSTAUDIOSTREAMSTATE, pfnStreamGetState, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Returns the number of buffered bytes that hasn't been played yet (optional). + * + * Is not valid on an input stream, implementions shall assert and return zero. + * + * @returns Number of pending bytes. + * @param pInterface Pointer to this interface. + * @param pStream Pointer to the audio stream. + * + * @todo This is no longer not used by DrvAudio and can probably be removed. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetPending, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Returns the amount which is writable to the audio (output) stream. + * + * @returns Number of writable bytes. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetWritable, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Plays (writes to) an audio (output) stream. + * + * This is always called with data in the buffer, except after + * PDMAUDIOSTREAMCMD_DRAIN is issued when it's called every so often to assist + * the backend with moving the draining operation forward (kind of like + * PDMIAUDIOCONNECTOR::pfnStreamIterate). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + * @param pvBuf Pointer to audio data buffer to play. This will be NULL + * when called to assist draining the stream. + * @param cbBuf The number of bytes of audio data to play. This will be + * zero when called to assist draining the stream. + * @param pcbWritten Where to return the actual number of bytes played. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamPlay, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + const void *pvBuf, uint32_t cbBuf, uint32_t *pcbWritten)); + + /** + * Returns the amount which is readable from the audio (input) stream. + * + * @returns For non-raw layout streams: Number of readable bytes. + * for raw layout streams : Number of readable audio frames. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnStreamGetReadable, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * Captures (reads from) an audio (input) stream. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pStream Pointer to audio stream. + * @param pvBuf Buffer where to store read audio data. + * @param cbBuf Size of the audio data buffer in bytes. + * @param pcbRead Where to return the number of bytes actually captured. + */ + DECLR3CALLBACKMEMBER(int, pfnStreamCapture, (PPDMIHOSTAUDIO pInterface, PPDMAUDIOBACKENDSTREAM pStream, + void *pvBuf, uint32_t cbBuf, uint32_t *pcbRead)); +} PDMIHOSTAUDIO; + +/** PDMIHOSTAUDIO interface ID. */ +#define PDMIHOSTAUDIO_IID "c0875b91-a4f9-48be-8595-31d27048432d" + + +/** Pointer to a audio notify from host interface. */ +typedef struct PDMIHOSTAUDIOPORT *PPDMIHOSTAUDIOPORT; + +/** + * PDM host audio port interface, upwards sibling of PDMIHOSTAUDIO. + */ +typedef struct PDMIHOSTAUDIOPORT +{ + /** + * Ask DrvAudio to call PDMIHOSTAUDIO::pfnDoOnWorkerThread on a worker thread. + * + * Generic method for doing asynchronous work using the DrvAudio thread pool. + * + * This function will not wait for PDMIHOSTAUDIO::pfnDoOnWorkerThread to + * complete, but returns immediately after submitting the request to the thread + * pool. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pStream Optional backend stream structure to pass along. The + * reference count will be increased till the call + * completes to make sure the stream stays valid. + * @param uUser User specific value. + * @param pvUser User specific pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnDoOnWorkerThread,(PPDMIHOSTAUDIOPORT pInterface, PPDMAUDIOBACKENDSTREAM pStream, + uintptr_t uUser, void *pvUser)); + + /** + * The device for the given direction changed. + * + * The driver above backend (DrvAudio) will call the backend back + * (PDMIHOSTAUDIO::pfnStreamNotifyDeviceChanged) for all open streams in the + * given direction. (This ASSUMES the backend uses one output device and one + * input devices for all streams.) + * + * @param pInterface Pointer to this interface. + * @param enmDir The audio direction. + * @param pvUser Backend specific parameter for + * PDMIHOSTAUDIO::pfnStreamNotifyDeviceChanged. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyDeviceChanged,(PPDMIHOSTAUDIOPORT pInterface, PDMAUDIODIR enmDir, void *pvUser)); + + /** + * Notification that the stream is about to change device in a bit. + * + * This will assume PDMAUDIOSTREAM_STS_PREPARING_SWITCH will be set when + * PDMIHOSTAUDIO::pfnStreamGetStatus is next called and change the stream state + * accordingly. + * + * @param pInterface Pointer to this interface. + * @param pStream The stream that changed device (backend variant). + */ + DECLR3CALLBACKMEMBER(void, pfnStreamNotifyPreparingDeviceSwitch,(PPDMIHOSTAUDIOPORT pInterface, + PPDMAUDIOBACKENDSTREAM pStream)); + + /** + * The stream has changed its device and left the + * PDMAUDIOSTREAM_STS_PREPARING_SWITCH state (if it entered it at all). + * + * @param pInterface Pointer to this interface. + * @param pStream The stream that changed device (backend variant). + * @param fReInit Set if a re-init is required, clear if not. + */ + DECLR3CALLBACKMEMBER(void, pfnStreamNotifyDeviceChanged,(PPDMIHOSTAUDIOPORT pInterface, + PPDMAUDIOBACKENDSTREAM pStream, bool fReInit)); + + /** + * One or more audio devices have changed in some way. + * + * The upstream driver/device should re-evaluate the devices they're using. + * + * @todo r=bird: The upstream driver/device does not know which host audio + * devices they are using. This is mainly for triggering enumeration and + * logging of the audio devices. + * + * @param pInterface Pointer to this interface. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyDevicesChanged,(PPDMIHOSTAUDIOPORT pInterface)); +} PDMIHOSTAUDIOPORT; + +/** PDMIHOSTAUDIOPORT interface ID. */ +#define PDMIHOSTAUDIOPORT_IID "92ea5169-8271-402d-99a7-9de26a52acaf" + + +/** + * Audio mixer controls. + * + * @note This isn't part of any official PDM interface as such, it's more of a + * common thing that all the devices seem to need. + */ +typedef enum PDMAUDIOMIXERCTL +{ + /** Invalid zero value as per usual (guards against using unintialized values). */ + PDMAUDIOMIXERCTL_INVALID = 0, + /** Unknown mixer control. */ + PDMAUDIOMIXERCTL_UNKNOWN, + /** Master volume. */ + PDMAUDIOMIXERCTL_VOLUME_MASTER, + /** Front. */ + PDMAUDIOMIXERCTL_FRONT, + /** Center / LFE (Subwoofer). */ + PDMAUDIOMIXERCTL_CENTER_LFE, + /** Rear. */ + PDMAUDIOMIXERCTL_REAR, + /** Line-In. */ + PDMAUDIOMIXERCTL_LINE_IN, + /** Microphone-In. */ + PDMAUDIOMIXERCTL_MIC_IN, + /** End of valid values. */ + PDMAUDIOMIXERCTL_END, + /** Hack to blow the type up to 32-bit. */ + PDMAUDIOMIXERCTL_32BIT_HACK = 0x7fffffff +} PDMAUDIOMIXERCTL; + +/** + * Audio volume parameters. + * + * @note This isn't part of any official PDM interface any more (it used to be + * used to PDMIAUDIOCONNECTOR). It's currently only used by the mixer API. + */ +typedef struct PDMAUDIOVOLUME +{ + /** Set to @c true if this stream is muted, @c false if not. */ + bool fMuted; + /** The volume for each channel. + * The values zero is the most silent one (although not quite muted), and 255 + * the loudest. */ + uint8_t auChannels[PDMAUDIO_MAX_CHANNELS]; +} PDMAUDIOVOLUME; +/** Pointer to audio volume settings. */ +typedef PDMAUDIOVOLUME *PPDMAUDIOVOLUME; +/** Pointer to const audio volume settings. */ +typedef PDMAUDIOVOLUME const *PCPDMAUDIOVOLUME; + +/** Defines the minimum volume allowed. */ +#define PDMAUDIO_VOLUME_MIN (0) +/** Defines the maximum volume allowed. */ +#define PDMAUDIO_VOLUME_MAX (255) +/** Initializator for max volume on all channels. */ +#define PDMAUDIOVOLUME_INITIALIZER_MAX \ + { /* .fMuted = */ false, \ + /* .auChannels = */ { 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255 } } + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmaudioifs_h */ + diff --git a/include/VBox/vmm/pdmaudioinline.h b/include/VBox/vmm/pdmaudioinline.h new file mode 100644 index 00000000..5d3175c0 --- /dev/null +++ b/include/VBox/vmm/pdmaudioinline.h @@ -0,0 +1,1507 @@ +/* $Id: pdmaudioinline.h $ */ +/** @file + * PDM - Audio Helpers, Inlined Code. (DEV,++) + * + * This is all inlined because it's too tedious to create a couple libraries to + * contain it all (same bad excuse as for intnetinline.h & pdmnetinline.h). + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmaudioinline_h +#define VBOX_INCLUDED_vmm_pdmaudioinline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/********************************************************************************************************************************* +* Header Files * +*********************************************************************************************************************************/ +#include +#include +#include + +#include +#include +#include +#include +#include + + +/** @defgroup grp_pdm_audio_inline The PDM Audio Helper APIs + * @ingroup grp_pdm + * @{ + */ + + +/** + * Gets the name of an audio direction enum value. + * + * @returns Pointer to read-only name string on success, "bad" if passed an + * invalid enum value. + * @param enmDir The audio direction value to name. + */ +DECLINLINE(const char *) PDMAudioDirGetName(PDMAUDIODIR enmDir) +{ + switch (enmDir) + { + case PDMAUDIODIR_INVALID: return "invalid"; + case PDMAUDIODIR_UNKNOWN: return "unknown"; + case PDMAUDIODIR_IN: return "input"; + case PDMAUDIODIR_OUT: return "output"; + case PDMAUDIODIR_DUPLEX: return "duplex"; + + /* no default */ + case PDMAUDIODIR_END: + case PDMAUDIODIR_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Invalid audio direction %d\n", enmDir), "bad"); +} + +/** + * Gets the name of an audio mixer control enum value. + * + * @returns Pointer to read-only name, "bad" if invalid input. + * @param enmMixerCtl The audio mixer control value. + */ +DECLINLINE(const char *) PDMAudioMixerCtlGetName(PDMAUDIOMIXERCTL enmMixerCtl) +{ + switch (enmMixerCtl) + { + case PDMAUDIOMIXERCTL_INVALID: return "Invalid"; + case PDMAUDIOMIXERCTL_UNKNOWN: return "Unknown"; + case PDMAUDIOMIXERCTL_VOLUME_MASTER: return "Master Volume"; + case PDMAUDIOMIXERCTL_FRONT: return "Front"; + case PDMAUDIOMIXERCTL_CENTER_LFE: return "Center / LFE"; + case PDMAUDIOMIXERCTL_REAR: return "Rear"; + case PDMAUDIOMIXERCTL_LINE_IN: return "Line-In"; + case PDMAUDIOMIXERCTL_MIC_IN: return "Microphone-In"; + + /* no default */ + case PDMAUDIOMIXERCTL_END: + case PDMAUDIOMIXERCTL_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Invalid mixer control %ld\n", enmMixerCtl), "bad"); +} + +/** + * Gets the name of a path enum value. + * + * @returns Pointer to read-only name, "bad" if invalid input. + * @param enmPath The path value to name. + */ +DECLINLINE(const char *) PDMAudioPathGetName(PDMAUDIOPATH enmPath) +{ + switch (enmPath) + { + case PDMAUDIOPATH_INVALID: return "invalid"; + case PDMAUDIOPATH_UNKNOWN: return "unknown"; + + case PDMAUDIOPATH_OUT_FRONT: return "front"; + case PDMAUDIOPATH_OUT_CENTER_LFE: return "center-lfe"; + case PDMAUDIOPATH_OUT_REAR: return "rear"; + + case PDMAUDIOPATH_IN_MIC: return "mic"; + case PDMAUDIOPATH_IN_CD: return "cd"; + case PDMAUDIOPATH_IN_VIDEO: return "video-in"; + case PDMAUDIOPATH_IN_AUX: return "aux-in"; + case PDMAUDIOPATH_IN_LINE: return "line-in"; + case PDMAUDIOPATH_IN_PHONE: return "phone"; + + /* no default */ + case PDMAUDIOPATH_END: + case PDMAUDIOPATH_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Unknown enmPath=%d\n", enmPath), "bad"); +} + +/** + * Gets the name of a channel. + * + * @returns Pointer to read-only name, "bad" if invalid input. + * @param enmChannelId The channel ID to name. + */ +DECLINLINE(const char *) PDMAudioChannelIdGetName(PDMAUDIOCHANNELID enmChannelId) +{ + switch (enmChannelId) + { + case PDMAUDIOCHANNELID_INVALID: return "invalid"; + case PDMAUDIOCHANNELID_UNUSED_ZERO: return "unused-zero"; + case PDMAUDIOCHANNELID_UNUSED_SILENCE: return "unused-silence"; + case PDMAUDIOCHANNELID_UNKNOWN: return "unknown"; + + case PDMAUDIOCHANNELID_FRONT_LEFT: return "FL"; + case PDMAUDIOCHANNELID_FRONT_RIGHT: return "FR"; + case PDMAUDIOCHANNELID_FRONT_CENTER: return "FC"; + case PDMAUDIOCHANNELID_LFE: return "LFE"; + case PDMAUDIOCHANNELID_REAR_LEFT: return "BL"; + case PDMAUDIOCHANNELID_REAR_RIGHT: return "BR"; + case PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER: return "FLC"; + case PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER: return "FRC"; + case PDMAUDIOCHANNELID_REAR_CENTER: return "BC"; + case PDMAUDIOCHANNELID_SIDE_LEFT: return "SL"; + case PDMAUDIOCHANNELID_SIDE_RIGHT: return "SR"; + case PDMAUDIOCHANNELID_TOP_CENTER: return "TC"; + case PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT: return "TFL"; + case PDMAUDIOCHANNELID_FRONT_CENTER_HEIGHT: return "TFC"; + case PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT: return "TFR"; + case PDMAUDIOCHANNELID_REAR_LEFT_HEIGHT: return "TBL"; + case PDMAUDIOCHANNELID_REAR_CENTER_HEIGHT: return "TBC"; + case PDMAUDIOCHANNELID_REAR_RIGHT_HEIGHT: return "TBR"; + + /* no default */ + case PDMAUDIOCHANNELID_END: + case PDMAUDIOCHANNELID_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Unknown enmChannelId=%d\n", enmChannelId), "bad"); +} + + +/********************************************************************************************************************************* +* Volume Helpers * +*********************************************************************************************************************************/ + +/** + * Initializes a PDMAUDIOVOLUME structure to max. + * + * @param pVol The structure to initialize. + */ +DECLINLINE(void) PDMAudioVolumeInitMax(PPDMAUDIOVOLUME pVol) +{ + pVol->fMuted = false; + for (uintptr_t i = 0; i < RT_ELEMENTS(pVol->auChannels); i++) + pVol->auChannels[i] = PDMAUDIO_VOLUME_MAX; +} + + +/** + * Initializes a PDMAUDIOVOLUME structure from a simple stereo setting. + * + * The additional channels will simply be assigned the higer of the two. + * + * @param pVol The structure to initialize. + * @param fMuted Muted. + * @param bLeft The left channel volume. + * @param bRight The right channel volume. + */ +DECLINLINE(void) PDMAudioVolumeInitFromStereo(PPDMAUDIOVOLUME pVol, bool fMuted, uint8_t bLeft, uint8_t bRight) +{ + pVol->fMuted = fMuted; + pVol->auChannels[0] = bLeft; + pVol->auChannels[1] = bRight; + + uint8_t const bOther = RT_MAX(bLeft, bRight); + for (uintptr_t i = 2; i < RT_ELEMENTS(pVol->auChannels); i++) + pVol->auChannels[i] = bOther; +} + + +/** + * Combines two volume settings (typically master and sink). + * + * @param pVol Where to return the combined volume + * @param pVol1 The first volume settings to combine. + * @param pVol2 The second volume settings. + */ +DECLINLINE(void) PDMAudioVolumeCombine(PPDMAUDIOVOLUME pVol, PCPDMAUDIOVOLUME pVol1, PCPDMAUDIOVOLUME pVol2) +{ + if (pVol1->fMuted || pVol2->fMuted) + { + pVol->fMuted = true; + for (uintptr_t i = 0; i < RT_ELEMENTS(pVol->auChannels); i++) + pVol->auChannels[i] = 0; + } + else + { + pVol->fMuted = false; + /** @todo Very crude implementation for now -- needs more work! (At least + * when used in audioMixerSinkUpdateVolume it was considered as such.) */ + for (uintptr_t i = 0; i < RT_ELEMENTS(pVol->auChannels); i++) + { +#if 0 /* bird: I think the shift variant should produce the exact same result, w/o two conditionals per iteration. */ + /* 255 * 255 / 255 = 0xFF (255) */ + /* 17 * 127 / 255 = 8 */ + /* 39 * 39 / 255 = 5 */ + pVol->auChannels[i] = (uint8_t)( (RT_MAX(pVol1->auChannels[i], 1U) * RT_MAX(pVol2->auChannels[i], 1U)) + / PDMAUDIO_VOLUME_MAX); +#else + /* (((255 + 1) * (255 + 1)) >> 8) - 1 = 0xFF (255) */ + /* ((( 17 + 1) * (127 + 1)) >> 8) - 1 = 0x8 (8) */ + /* ((( 39 + 1) * ( 39 + 1)) >> 8) - 1 = 0x5 (5) */ + pVol->auChannels[i] = (uint8_t)((((1U + pVol1->auChannels[i]) * (1U + pVol2->auChannels[i])) >> 8) - 1U); +#endif + } + } +} + + +/********************************************************************************************************************************* +* PCM Property Helpers * +*********************************************************************************************************************************/ + +/** + * Assigns default channel IDs according to the channel count. + * + * The assignments are taken from the standard speaker channel layouts table + * in the wikipedia article on surround sound: + * https://en.wikipedia.org/wiki/Surround_sound#Standard_speaker_channels + */ +DECLINLINE(void) PDMAudioPropsSetDefaultChannelIds(PPDMAUDIOPCMPROPS pProps) +{ + unsigned cChannels = pProps->cChannelsX; + switch (cChannels) + { + case 1: + pProps->aidChannels[0] = PDMAUDIOCHANNELID_MONO; + break; + case 2: + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + break; + case 3: /* 2.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_LFE; + break; + case 4: /* 4.0 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_REAR_RIGHT; + break; + case 5: /* 4.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_CENTER; + break; + case 6: /* 5.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + break; + case 7: /* 6.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_REAR_CENTER; + break; + case 8: /* 7.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER; + break; + case 9: /* 9.0 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_SIDE_LEFT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_SIDE_RIGHT; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT; + pProps->aidChannels[8] = PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT; + break; + case 10: /* 9.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_SIDE_LEFT; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_SIDE_RIGHT; + pProps->aidChannels[8] = PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT; + pProps->aidChannels[9] = PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT; + break; + case 11: /* 11.0 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_SIDE_LEFT; + pProps->aidChannels[8] = PDMAUDIOCHANNELID_SIDE_RIGHT; + pProps->aidChannels[9] = PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT; + pProps->aidChannels[10]= PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT; + break; + default: + AssertFailed(); + cChannels = 12; + RT_FALL_THROUGH(); + case 12: /* 11.1 */ + pProps->aidChannels[0] = PDMAUDIOCHANNELID_FRONT_LEFT; + pProps->aidChannels[1] = PDMAUDIOCHANNELID_FRONT_RIGHT; + pProps->aidChannels[2] = PDMAUDIOCHANNELID_FRONT_CENTER; + pProps->aidChannels[3] = PDMAUDIOCHANNELID_LFE; + pProps->aidChannels[4] = PDMAUDIOCHANNELID_REAR_LEFT; + pProps->aidChannels[5] = PDMAUDIOCHANNELID_REAR_RIGHT; + pProps->aidChannels[6] = PDMAUDIOCHANNELID_FRONT_LEFT_OF_CENTER; + pProps->aidChannels[7] = PDMAUDIOCHANNELID_FRONT_RIGHT_OF_CENTER; + pProps->aidChannels[8] = PDMAUDIOCHANNELID_SIDE_LEFT; + pProps->aidChannels[9] = PDMAUDIOCHANNELID_SIDE_RIGHT; + pProps->aidChannels[10]= PDMAUDIOCHANNELID_FRONT_LEFT_HEIGHT; + pProps->aidChannels[11]= PDMAUDIOCHANNELID_FRONT_RIGHT_HEIGHT; + break; + case 0: + break; + } + AssertCompile(RT_ELEMENTS(pProps->aidChannels) >= 12); + + while (cChannels < RT_ELEMENTS(pProps->aidChannels)) + pProps->aidChannels[cChannels++] = PDMAUDIOCHANNELID_INVALID; +} + + +/** + * Initialize PCM audio properties. + */ +DECLINLINE(void) PDMAudioPropsInit(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz) +{ + pProps->cbFrame = cbSample * cChannels; + pProps->cbSampleX = cbSample; + pProps->cChannelsX = cChannels; + pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels); + pProps->fSigned = fSigned; + pProps->fSwapEndian = false; + pProps->fRaw = false; + pProps->uHz = uHz; + + Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels); + Assert(pProps->cbSampleX == cbSample); + Assert(pProps->cChannelsX == cChannels); + + PDMAudioPropsSetDefaultChannelIds(pProps); +} + +/** + * Initialize PCM audio properties, extended version. + */ +DECLINLINE(void) PDMAudioPropsInitEx(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample, bool fSigned, uint8_t cChannels, uint32_t uHz, + bool fLittleEndian, bool fRaw) +{ + Assert(!fRaw || cbSample == sizeof(int64_t)); + pProps->cbFrame = cbSample * cChannels; + pProps->cbSampleX = cbSample; + pProps->cChannelsX = cChannels; + pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, cChannels); + pProps->fSigned = fSigned; +#ifdef RT_LITTLE_ENDIAN + pProps->fSwapEndian = !fLittleEndian; +#else + pProps->fSwapEndian = fLittleEndian; +#endif + pProps->fRaw = fRaw; + pProps->uHz = uHz; + + Assert(pProps->cbFrame == (uint32_t)cbSample * cChannels); + Assert(pProps->cbSampleX == cbSample); + Assert(pProps->cChannelsX == cChannels); + + PDMAudioPropsSetDefaultChannelIds(pProps); +} + +/** + * Modifies the channel count. + * + * @note This will reset the channel IDs to defaults. + * + * @param pProps The PCM properties to update. + * @param cChannels The new channel count. + */ +DECLINLINE(void) PDMAudioPropsSetChannels(PPDMAUDIOPCMPROPS pProps, uint8_t cChannels) +{ + Assert(cChannels > 0); Assert(cChannels < 16); + pProps->cChannelsX = cChannels; + pProps->cbFrame = pProps->cbSampleX * cChannels; + pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(pProps->cbSampleX, cChannels); + + PDMAudioPropsSetDefaultChannelIds(pProps); +} + +/** + * Modifies the sample size. + * + * @param pProps The PCM properties to update. + * @param cbSample The new sample size (in bytes). + */ +DECLINLINE(void) PDMAudioPropsSetSampleSize(PPDMAUDIOPCMPROPS pProps, uint8_t cbSample) +{ + Assert(cbSample == 1 || cbSample == 2 || cbSample == 4 || cbSample == 8); + pProps->cbSampleX = cbSample; + pProps->cbFrame = cbSample * pProps->cChannelsX; + pProps->cShiftX = PDMAUDIOPCMPROPS_MAKE_SHIFT_PARMS(cbSample, pProps->cChannelsX); +} + +/** + * Gets the bitrate. + * + * Divide the result by 8 to get the byte rate. + * + * @returns Bit rate. + * @param pProps PCM properties to calculate bitrate for. + */ +DECLINLINE(uint32_t) PDMAudioPropsGetBitrate(PCPDMAUDIOPCMPROPS pProps) +{ + Assert(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX); + return pProps->cbFrame * pProps->uHz * 8; +} + +/** + * Gets the number of channels. + * @returns The channel count. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(uint8_t) PDMAudioPropsChannels(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->cChannelsX; +} + +/** + * Gets the sample size in bytes. + * @returns Number of bytes per sample. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(uint8_t) PDMAudioPropsSampleSize(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->cbSampleX; +} + +/** + * Gets the sample size in bits. + * @returns Number of bits per sample. + * @param pProps The PCM properties. + */ +DECLINLINE(uint8_t) PDMAudioPropsSampleBits(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->cbSampleX * 8; +} + +/** + * Gets the frame size in bytes. + * @returns Number of bytes per frame. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(uint8_t) PDMAudioPropsFrameSize(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->cbFrame; +} + +/** + * Gets the frequency. + * @returns Frequency. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(uint32_t) PDMAudioPropsHz(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->uHz; +} + +/** + * Checks if the format is signed or unsigned. + * @returns true if signed, false if unsigned. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(bool) PDMAudioPropsIsSigned(PCPDMAUDIOPCMPROPS pProps) +{ + return pProps->fSigned; +} + +/** + * Checks if the format is little-endian or not. + * @returns true if little-endian (or if 8-bit), false if big-endian. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(bool) PDMAudioPropsIsLittleEndian(PCPDMAUDIOPCMPROPS pProps) +{ +#ifdef RT_LITTLE_ENDIAN + return !pProps->fSwapEndian || pProps->cbSampleX < 2; +#else + return pProps->fSwapEndian || pProps->cbSampleX < 2; +#endif +} + +/** + * Checks if the format is big-endian or not. + * @returns true if big-endian (or if 8-bit), false if little-endian. + * @param pProps The PCM properties. + */ +DECL_FORCE_INLINE(bool) PDMAudioPropsIsBigEndian(PCPDMAUDIOPCMPROPS pProps) +{ +#ifdef RT_LITTLE_ENDIAN + return pProps->fSwapEndian || pProps->cbSampleX < 2; +#else + return !pProps->fSwapEndian || pProps->cbSampleX < 2; +#endif +} + +/** + * Rounds down the given byte amount to the nearest frame boundrary. + * + * @returns Rounded byte amount. + * @param pProps PCM properties to use. + * @param cb The size (in bytes) to round. + */ +DECLINLINE(uint32_t) PDMAudioPropsFloorBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb)); +} + +/** + * Rounds up the given byte amount to the nearest frame boundrary. + * + * @returns Rounded byte amount. + * @param pProps PCM properties to use. + * @param cb The size (in bytes) to round. + */ +DECLINLINE(uint32_t) PDMAudioPropsRoundUpBytesToFrame(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + uint32_t const cbFrame = PDMAudioPropsFrameSize(pProps); + AssertReturn(cbFrame, 0); + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAUDIOPCMPROPS_B2F(pProps, cb + cbFrame - 1)); +} + +/** + * Checks if the given size is aligned on a frame boundrary. + * + * @returns @c true if properly aligned, @c false if not. + * @param pProps PCM properties to use. + * @param cb The size (in bytes) to check. + */ +DECLINLINE(bool) PDMAudioPropsIsSizeAligned(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, false); + uint32_t const cbFrame = PDMAudioPropsFrameSize(pProps); + AssertReturn(cbFrame, false); + return cb % cbFrame == 0; +} + +/** + * Converts bytes to frames (rounding down of course). + * + * @returns Number of frames. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert. + */ +DECLINLINE(uint32_t) PDMAudioPropsBytesToFrames(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + return PDMAUDIOPCMPROPS_B2F(pProps, cb); +} + +/** + * Converts bytes to milliseconds. + * + * @return Number milliseconds @a cb takes to play or record. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert. + * + * @note Rounds up the result. + */ +DECLINLINE(uint64_t) PDMAudioPropsBytesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + + /* Check parameters to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + const unsigned cbFrame = PDMAudioPropsFrameSize(pProps); + if (cbFrame) + { + /* Round cb up to closest frame size: */ + cb = (cb + cbFrame - 1) / cbFrame; + + /* Convert to milliseconds. */ + return (cb * (uint64_t)RT_MS_1SEC + uHz - 1) / uHz; + } + } + return 0; +} + +/** + * Converts bytes to microseconds. + * + * @return Number microseconds @a cb takes to play or record. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert. + * + * @note Rounds up the result. + */ +DECLINLINE(uint64_t) PDMAudioPropsBytesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + + /* Check parameters to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + const unsigned cbFrame = PDMAudioPropsFrameSize(pProps); + if (cbFrame) + { + /* Round cb up to closest frame size: */ + cb = (cb + cbFrame - 1) / cbFrame; + + /* Convert to microseconds. */ + return (cb * (uint64_t)RT_US_1SEC + uHz - 1) / uHz; + } + } + return 0; +} + +/** + * Converts bytes to nanoseconds. + * + * @return Number nanoseconds @a cb takes to play or record. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert. + * + * @note Rounds up the result. + */ +DECLINLINE(uint64_t) PDMAudioPropsBytesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cb) +{ + AssertPtrReturn(pProps, 0); + + /* Check parameters to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + const unsigned cbFrame = PDMAudioPropsFrameSize(pProps); + if (cbFrame) + { + /* Round cb up to closest frame size: */ + cb = (cb + cbFrame - 1) / cbFrame; + + /* Convert to nanoseconds. */ + return (cb * (uint64_t)RT_NS_1SEC + uHz - 1) / uHz; + } + } + return 0; +} + +/** + * Converts bytes to nanoseconds, 64-bit version. + * + * @return Number nanoseconds @a cb takes to play or record. + * @param pProps PCM properties to use. + * @param cb The number of bytes to convert (64-bit). + * + * @note Rounds up the result. + */ +DECLINLINE(uint64_t) PDMAudioPropsBytesToNano64(PCPDMAUDIOPCMPROPS pProps, uint64_t cb) +{ + AssertPtrReturn(pProps, 0); + + /* Check parameters to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + const unsigned cbFrame = PDMAudioPropsFrameSize(pProps); + if (cbFrame) + { + /* Round cb up to closest frame size: */ + cb = (cb + cbFrame - 1) / cbFrame; + + /* Convert to nanoseconds. */ + return (cb * RT_NS_1SEC + uHz - 1) / uHz; + } + } + return 0; +} + +/** + * Converts frames to bytes. + * + * @returns Number of bytes. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @sa PDMAUDIOPCMPROPS_F2B + */ +DECLINLINE(uint32_t) PDMAudioPropsFramesToBytes(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + return PDMAUDIOPCMPROPS_F2B(pProps, cFrames); +} + +/** + * Converts frames to milliseconds. + * + * @returns milliseconds. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @note No rounding here, result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsFramesToMilli(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + return ASMMultU32ByU32DivByU32(cFrames, RT_MS_1SEC, uHz); + return 0; +} + +/** + * Converts frames to milliseconds, but not returning more than @a cMsMax + * + * This is a convenience for logging and such. + * + * @returns milliseconds (32-bit). + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @param cMsMax Max return value (32-bit). + * @note No rounding here, result is floored. + */ +DECLINLINE(uint32_t) PDMAudioPropsFramesToMilliMax(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames, uint32_t cMsMax) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + { + uint32_t const cMsResult = ASMMultU32ByU32DivByU32(cFrames, RT_MS_1SEC, uHz); + return RT_MIN(cMsResult, cMsMax); + } + return 0; +} + +/** + * Converts frames to microseconds. + * + * @returns microseconds. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @note No rounding here, result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsFramesToMicro(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + return ASMMultU32ByU32DivByU32(cFrames, RT_US_1SEC, uHz); + return 0; +} + +/** + * Converts frames to nanoseconds. + * + * @returns Nanoseconds. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @note No rounding here, result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsFramesToNano(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC, uHz); + return 0; +} + +/** + * Converts frames to NT ticks (100 ns units). + * + * @returns NT ticks. + * @param pProps The PCM properties to use. + * @param cFrames Number of audio frames to convert. + * @note No rounding here, result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsFramesToNtTicks(PCPDMAUDIOPCMPROPS pProps, uint32_t cFrames) +{ + AssertPtrReturn(pProps, 0); + + /* Check input to prevent division by chainsaw: */ + uint32_t const uHz = pProps->uHz; + if (uHz) + return ASMMultU32ByU32DivByU32(cFrames, RT_NS_1SEC / 100, uHz); + return 0; +} + +/** + * Converts milliseconds to frames. + * + * @returns Number of frames + * @param pProps The PCM properties to use. + * @param cMs The number of milliseconds to convert. + * + * @note The result is rounded rather than floored (hysterical raisins). + */ +DECLINLINE(uint32_t) PDMAudioPropsMilliToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs) +{ + AssertPtrReturn(pProps, 0); + + uint32_t const uHz = pProps->uHz; + uint32_t cFrames; + if (cMs < RT_MS_1SEC) + cFrames = 0; + else + { + cFrames = cMs / RT_MS_1SEC * uHz; + cMs %= RT_MS_1SEC; + } + cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cMs) + RT_MS_1SEC - 1) / RT_MS_1SEC; + return cFrames; +} + +/** + * Converts milliseconds to bytes. + * + * @returns Number of bytes (frame aligned). + * @param pProps The PCM properties to use. + * @param cMs The number of milliseconds to convert. + * + * @note The result is rounded rather than floored (hysterical raisins). + */ +DECLINLINE(uint32_t) PDMAudioPropsMilliToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cMs) +{ + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsMilliToFrames(pProps, cMs)); +} + +/** + * Converts nanoseconds to frames. + * + * @returns Number of frames. + * @param pProps The PCM properties to use. + * @param cNs The number of nanoseconds to convert. + * + * @note The result is rounded rather than floored (hysterical raisins). + */ +DECLINLINE(uint32_t) PDMAudioPropsNanoToFrames(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) +{ + AssertPtrReturn(pProps, 0); + + uint32_t const uHz = pProps->uHz; + uint32_t cFrames; + if (cNs < RT_NS_1SEC) + cFrames = 0; + else + { + cFrames = cNs / RT_NS_1SEC * uHz; + cNs %= RT_NS_1SEC; + } + cFrames += (ASMMult2xU32RetU64(uHz, (uint32_t)cNs) + RT_NS_1SEC - 1) / RT_NS_1SEC; + return cFrames; +} + +/** + * Converts nanoseconds to frames, 64-bit return. + * + * @returns Number of frames (64-bit). + * @param pProps The PCM properties to use. + * @param cNs The number of nanoseconds to convert. + * + * @note The result is floored! + */ +DECLINLINE(uint64_t) PDMAudioPropsNanoToFrames64(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) +{ + AssertPtrReturn(pProps, 0); + + uint32_t const uHz = pProps->uHz; + uint64_t cFrames; + if (cNs < RT_NS_1SEC) + cFrames = 0; + else + { + cFrames = cNs / RT_NS_1SEC * uHz; + cNs %= RT_NS_1SEC; + } + cFrames += ASMMult2xU32RetU64(uHz, (uint32_t)cNs) / RT_NS_1SEC; + return cFrames; +} + +/** + * Converts nanoseconds to bytes. + * + * @returns Number of bytes (frame aligned). + * @param pProps The PCM properties to use. + * @param cNs The number of nanoseconds to convert. + * + * @note The result is rounded rather than floored (hysterical raisins). + */ +DECLINLINE(uint32_t) PDMAudioPropsNanoToBytes(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) +{ + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs)); +} + +/** + * Converts nanoseconds to bytes, 64-bit version. + * + * @returns Number of bytes (frame aligned), 64-bit. + * @param pProps The PCM properties to use. + * @param cNs The number of nanoseconds to convert. + * + * @note The result is floored. + */ +DECLINLINE(uint64_t) PDMAudioPropsNanoToBytes64(PCPDMAUDIOPCMPROPS pProps, uint64_t cNs) +{ + return PDMAUDIOPCMPROPS_F2B(pProps, PDMAudioPropsNanoToFrames(pProps, cNs)); +} + +/** + * Clears a sample buffer by the given amount of audio frames with silence (according to the format + * given by the PCM properties). + * + * @param pProps The PCM properties to apply. + * @param pvBuf The buffer to clear. + * @param cbBuf The buffer size in bytes. + * @param cFrames The number of audio frames to clear. Capped at @a cbBuf + * if exceeding the buffer. If the size is an unaligned + * number of frames, the extra bytes may be left + * uninitialized in some configurations. + */ +DECLINLINE(void) PDMAudioPropsClearBuffer(PCPDMAUDIOPCMPROPS pProps, void *pvBuf, size_t cbBuf, uint32_t cFrames) +{ + /* + * Validate input + */ + AssertPtrReturnVoid(pProps); + Assert(pProps->cbSampleX); + if (!cbBuf || !cFrames) + return; + AssertPtrReturnVoid(pvBuf); + + /* + * Decide how much needs clearing. + */ + size_t cbToClear = PDMAudioPropsFramesToBytes(pProps, cFrames); + AssertStmt(cbToClear <= cbBuf, cbToClear = cbBuf); + + Log2Func(("pProps=%p, pvBuf=%p, cFrames=%RU32, fSigned=%RTbool, cbSample=%RU8\n", + pProps, pvBuf, cFrames, pProps->fSigned, pProps->cbSampleX)); + + /* + * Do the job. + */ + if (pProps->fSigned) + RT_BZERO(pvBuf, cbToClear); + else /* Unsigned formats. */ + { + switch (pProps->cbSampleX) + { + case 1: /* 8 bit */ + memset(pvBuf, 0x80, cbToClear); + break; + + case 2: /* 16 bit */ + { + uint16_t *pu16Dst = (uint16_t *)pvBuf; + uint16_t const u16Offset = !pProps->fSwapEndian ? UINT16_C(0x8000) : UINT16_C(0x80); + cbBuf /= sizeof(*pu16Dst); + while (cbBuf-- > 0) + *pu16Dst++ = u16Offset; + break; + } + + case 4: /* 32 bit */ + ASMMemFill32(pvBuf, cbToClear & ~(size_t)(sizeof(uint32_t) - 1), + !pProps->fSwapEndian ? UINT32_C(0x80000000) : UINT32_C(0x80)); + break; + + default: + AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pProps->cbSampleX)); + } + } +} + +/** + * Checks if the given buffer is silence. + * + * @param pProps The PCM properties to use checking the buffer. + * @param pvBuf The buffer to check. + * @param cbBuf The number of bytes to check (must be frame aligned). + */ +DECLINLINE(bool) PDMAudioPropsIsBufferSilence(PCPDMAUDIOPCMPROPS pProps, void const *pvBuf, size_t cbBuf) +{ + /* + * Validate input + */ + AssertPtrReturn(pProps, false); + if (!cbBuf) + return false; + AssertPtrReturn(pvBuf, false); + + /* + * Do the job. + */ + if (pProps->fSigned) + return ASMMemIsZero(pvBuf, cbBuf); + + switch (pProps->cbSampleX) + { + case 1: /* 8 bit */ + return ASMMemIsAllU8(pvBuf, cbBuf, 0x80); + + case 2: /* 16 bit */ + { + uint16_t const *pu16 = (uint16_t const *)pvBuf; + uint16_t const u16Offset = !pProps->fSwapEndian ? UINT16_C(0x8000) : UINT16_C(0x80); + cbBuf /= sizeof(*pu16); + while (cbBuf-- > 0) + if (*pu16 != u16Offset) + return false; + return true; + } + + case 4: /* 32 bit */ + { + uint32_t const *pu32 = (uint32_t const *)pvBuf; + uint32_t const u32Offset = !pProps->fSwapEndian ? UINT32_C(0x80000000) : UINT32_C(0x80); + cbBuf /= sizeof(*pu32); + while (cbBuf-- > 0) + if (*pu32 != u32Offset) + return false; + return true; + } + + default: + AssertMsgFailed(("Invalid bytes per sample: %RU8\n", pProps->cbSampleX)); + return false; + } +} + +/** + * Compares two sets of PCM properties. + * + * @returns @c true if the same, @c false if not. + * @param pProps1 The first set of properties to compare. + * @param pProps2 The second set of properties to compare. + */ +DECLINLINE(bool) PDMAudioPropsAreEqual(PCPDMAUDIOPCMPROPS pProps1, PCPDMAUDIOPCMPROPS pProps2) +{ + uintptr_t idxCh; + AssertPtrReturn(pProps1, false); + AssertPtrReturn(pProps2, false); + + if (pProps1 == pProps2) /* If the pointers match, take a shortcut. */ + return true; + + if (pProps1->uHz != pProps2->uHz) + return false; + if (pProps1->cChannelsX != pProps2->cChannelsX) + return false; + if (pProps1->cbSampleX != pProps2->cbSampleX) + return false; + if (pProps1->fSigned != pProps2->fSigned) + return false; + if (pProps1->fSwapEndian != pProps2->fSwapEndian) + return false; + if (pProps1->fRaw != pProps2->fRaw) + return false; + + idxCh = pProps1->cChannelsX; + while (idxCh-- > 0) + if (pProps1->aidChannels[idxCh] != pProps2->aidChannels[idxCh]) + return false; + + return true; +} + +/** + * Checks whether the given PCM properties are valid or not. + * + * @returns true/false accordingly. + * @param pProps The PCM properties to check. + * + * @remarks This just performs a generic check of value ranges. + * + * @sa PDMAudioStrmCfgIsValid + */ +DECLINLINE(bool) PDMAudioPropsAreValid(PCPDMAUDIOPCMPROPS pProps) +{ + AssertPtrReturn(pProps, false); + + /* Channels. */ + if ( pProps->cChannelsX != 0 + && pProps->cChannelsX <= PDMAUDIO_MAX_CHANNELS + /* Sample size. */ + && ( pProps->cbSampleX == 1 + || pProps->cbSampleX == 2 + || pProps->cbSampleX == 4 + || (pProps->cbSampleX == 8 && pProps->fRaw)) + /* Hertz rate. */ + && pProps->uHz >= 1000 + && pProps->uHz < 1000000 + /* Raw format: Here we only support int64_t as sample size currently, if enabled. */ + && ( !pProps->fRaw + || (pProps->fSigned && pProps->cbSampleX == sizeof(int64_t))) + ) + { + /* A few more sanity checks to see if the structure has been properly initialized (via PDMAudioPropsInit[Ex]). */ + AssertMsgReturn(pProps->cShiftX == PDMAUDIOPCMPROPS_MAKE_SHIFT(pProps), + ("cShift=%u cbSample=%u cChannels=%u\n", pProps->cShiftX, pProps->cbSampleX, pProps->cChannelsX), + false); + AssertMsgReturn(pProps->cbFrame == pProps->cbSampleX * pProps->cChannelsX, + ("cbFrame=%u cbSample=%u cChannels=%u\n", pProps->cbFrame, pProps->cbSampleX, pProps->cChannelsX), + false); + + return true; + } + + return false; +} + +/** + * Get number of bytes per frame. + * + * @returns Number of bytes per audio frame. + * @param pProps PCM properties to use. + * @sa PDMAUDIOPCMPROPS_F2B + */ +DECLINLINE(uint32_t) PDMAudioPropsBytesPerFrame(PCPDMAUDIOPCMPROPS pProps) +{ + return PDMAUDIOPCMPROPS_F2B(pProps, 1 /*cFrames*/); +} + +/** + * Prints PCM properties to the debug log. + * + * @param pProps PCM properties to use. + */ +DECLINLINE(void) PDMAudioPropsLog(PCPDMAUDIOPCMPROPS pProps) +{ + AssertPtrReturnVoid(pProps); + + Log(("uHz=%RU32, cChannels=%RU8, cBits=%RU8%s", + pProps->uHz, pProps->cChannelsX, pProps->cbSampleX * 8, pProps->fSigned ? "S" : "U")); +} + +/** Max necessary buffer space for PDMAudioPropsToString */ +#define PDMAUDIOPROPSTOSTRING_MAX sizeof("16ch S64 4294967296Hz swap raw") + +/** + * Formats the PCM audio properties into a string buffer. + * + * @returns pszDst + * @param pProps PCM properties to use. + * @param pszDst The destination buffer. + * @param cchDst The size of the destination buffer. Recommended to be at + * least PDMAUDIOPROPSTOSTRING_MAX bytes. + */ +DECLINLINE(char *) PDMAudioPropsToString(PCPDMAUDIOPCMPROPS pProps, char *pszDst, size_t cchDst) +{ + /* 2ch S64 44100Hz swap raw */ + RTStrPrintf(pszDst, cchDst, "%uch %c%u %RU32Hz%s%s", + PDMAudioPropsChannels(pProps), PDMAudioPropsIsSigned(pProps) ? 'S' : 'U', PDMAudioPropsSampleBits(pProps), + PDMAudioPropsHz(pProps), pProps->fSwapEndian ? " swap" : "", pProps->fRaw ? " raw" : ""); + return pszDst; +} + + +/********************************************************************************************************************************* +* Stream Configuration Helpers * +*********************************************************************************************************************************/ + +/** + * Initializes a stream configuration from PCM properties. + * + * @returns VBox status code. + * @param pCfg The stream configuration to initialize. + * @param pProps The PCM properties to use. + */ +DECLINLINE(int) PDMAudioStrmCfgInitWithProps(PPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps) +{ + AssertPtrReturn(pProps, VERR_INVALID_POINTER); + AssertPtrReturn(pCfg, VERR_INVALID_POINTER); + + RT_ZERO(*pCfg); + pCfg->Backend.cFramesPreBuffering = UINT32_MAX; /* Explicitly set to "undefined". */ + + memcpy(&pCfg->Props, pProps, sizeof(PDMAUDIOPCMPROPS)); + + return VINF_SUCCESS; +} + +/** + * Checks whether stream configuration matches the given PCM properties. + * + * @returns @c true if equal, @c false if not. + * @param pCfg The stream configuration. + * @param pProps The PCM properties to match with. + */ +DECLINLINE(bool) PDMAudioStrmCfgMatchesProps(PCPDMAUDIOSTREAMCFG pCfg, PCPDMAUDIOPCMPROPS pProps) +{ + AssertPtrReturn(pCfg, false); + return PDMAudioPropsAreEqual(pProps, &pCfg->Props); +} + +/** + * Checks whether two stream configuration matches. + * + * @returns @c true if equal, @c false if not. + * @param pCfg1 The first stream configuration. + * @param pCfg2 The second stream configuration. + */ +DECLINLINE(bool) PDMAudioStrmCfgEquals(PCPDMAUDIOSTREAMCFG pCfg1, PCPDMAUDIOSTREAMCFG pCfg2) +{ + if (!pCfg1 || !pCfg2) + return false; + if (pCfg1 == pCfg2) + return pCfg1 != NULL; + if (PDMAudioPropsAreEqual(&pCfg1->Props, &pCfg2->Props)) + return pCfg1->enmDir == pCfg2->enmDir + && pCfg1->enmPath == pCfg2->enmPath + && pCfg1->Device.cMsSchedulingHint == pCfg2->Device.cMsSchedulingHint + && pCfg1->Backend.cFramesPeriod == pCfg2->Backend.cFramesPeriod + && pCfg1->Backend.cFramesBufferSize == pCfg2->Backend.cFramesBufferSize + && pCfg1->Backend.cFramesPreBuffering == pCfg2->Backend.cFramesPreBuffering + && strcmp(pCfg1->szName, pCfg2->szName) == 0; + return false; +} + +/** + * Frees an audio stream allocated by PDMAudioStrmCfgDup(). + * + * @param pCfg The stream configuration to free. + */ +DECLINLINE(void) PDMAudioStrmCfgFree(PPDMAUDIOSTREAMCFG pCfg) +{ + if (pCfg) + RTMemFree(pCfg); +} + +/** + * Checks whether the given stream configuration is valid or not. + * + * @returns true/false accordingly. + * @param pCfg Stream configuration to check. + * + * @remarks This just performs a generic check of value ranges. Further, it + * will assert if the input is invalid. + * + * @sa PDMAudioPropsAreValid + */ +DECLINLINE(bool) PDMAudioStrmCfgIsValid(PCPDMAUDIOSTREAMCFG pCfg) +{ + AssertPtrReturn(pCfg, false); + AssertMsgReturn(pCfg->enmDir >= PDMAUDIODIR_UNKNOWN && pCfg->enmDir < PDMAUDIODIR_END, ("%d\n", pCfg->enmDir), false); + return PDMAudioPropsAreValid(&pCfg->Props); +} + +/** + * Copies one stream configuration to another. + * + * @returns VBox status code. + * @param pDstCfg The destination stream configuration. + * @param pSrcCfg The source stream configuration. + */ +DECLINLINE(int) PDMAudioStrmCfgCopy(PPDMAUDIOSTREAMCFG pDstCfg, PCPDMAUDIOSTREAMCFG pSrcCfg) +{ + AssertPtrReturn(pDstCfg, VERR_INVALID_POINTER); + AssertPtrReturn(pSrcCfg, VERR_INVALID_POINTER); + + /* This used to be VBOX_STRICT only and return VERR_INVALID_PARAMETER, but + that's making release builds work differently from debug & strict builds, + which is a terrible idea: */ + Assert(PDMAudioStrmCfgIsValid(pSrcCfg)); + + memcpy(pDstCfg, pSrcCfg, sizeof(PDMAUDIOSTREAMCFG)); + + return VINF_SUCCESS; +} + +/** + * Duplicates an audio stream configuration. + * + * @returns Pointer to duplicate on success, NULL on failure. Must be freed + * using PDMAudioStrmCfgFree(). + * + * @param pCfg The audio stream configuration to duplicate. + */ +DECLINLINE(PPDMAUDIOSTREAMCFG) PDMAudioStrmCfgDup(PCPDMAUDIOSTREAMCFG pCfg) +{ + AssertPtrReturn(pCfg, NULL); + + PPDMAUDIOSTREAMCFG pDst = (PPDMAUDIOSTREAMCFG)RTMemAllocZ(sizeof(PDMAUDIOSTREAMCFG)); + if (pDst) + { + int rc = PDMAudioStrmCfgCopy(pDst, pCfg); + if (RT_SUCCESS(rc)) + return pDst; + + PDMAudioStrmCfgFree(pDst); + } + return NULL; +} + +/** + * Logs an audio stream configuration. + * + * @param pCfg The stream configuration to log. + */ +DECLINLINE(void) PDMAudioStrmCfgLog(PCPDMAUDIOSTREAMCFG pCfg) +{ + if (pCfg) + LogFunc(("szName=%s enmDir=%RU32 uHz=%RU32 cBits=%RU8%s cChannels=%RU8\n", pCfg->szName, pCfg->enmDir, + pCfg->Props.uHz, pCfg->Props.cbSampleX * 8, pCfg->Props.fSigned ? "S" : "U", pCfg->Props.cChannelsX)); +} + +/** + * Converts a stream command enum value to a string. + * + * @returns Pointer to read-only stream command name on success, + * "bad" if invalid command value. + * @param enmCmd The stream command to name. + */ +DECLINLINE(const char *) PDMAudioStrmCmdGetName(PDMAUDIOSTREAMCMD enmCmd) +{ + switch (enmCmd) + { + case PDMAUDIOSTREAMCMD_INVALID: return "Invalid"; + case PDMAUDIOSTREAMCMD_ENABLE: return "Enable"; + case PDMAUDIOSTREAMCMD_DISABLE: return "Disable"; + case PDMAUDIOSTREAMCMD_PAUSE: return "Pause"; + case PDMAUDIOSTREAMCMD_RESUME: return "Resume"; + case PDMAUDIOSTREAMCMD_DRAIN: return "Drain"; + case PDMAUDIOSTREAMCMD_END: + case PDMAUDIOSTREAMCMD_32BIT_HACK: + break; + /* no default! */ + } + AssertMsgFailedReturn(("Invalid stream command %d\n", enmCmd), "bad"); +} + +/** Max necessary buffer space for PDMAudioStrmCfgToString */ +#define PDMAUDIOSTRMCFGTOSTRING_MAX \ + sizeof("'01234567890123456789012345678901234567890123456789012345678901234' unknown 16ch S64 4294967295Hz swap raw, 9999999ms buffer, 9999999ms period, 9999999ms pre-buffer, 4294967295ms sched, center-lfe") + +/** + * Formats an audio stream configuration. + * + * @param pCfg The stream configuration to stringify. + * @param pszDst The destination buffer. + * @param cbDst The size of the destination buffer. Recommend this be + * at least PDMAUDIOSTRMCFGTOSTRING_MAX bytes. + */ +DECLINLINE(const char *) PDMAudioStrmCfgToString(PCPDMAUDIOSTREAMCFG pCfg, char *pszDst, size_t cbDst) +{ + /* 'front' output 2ch 44100Hz raw, 300ms buffer, 75ms period, 150ms pre-buffer, 10ms sched */ + RTStrPrintf(pszDst, cbDst, + "'%s' %s %uch %c%u %RU32Hz%s%s, %RU32ms buffer, %RU32ms period, %RU32ms pre-buffer, %RU32ms sched%s%s", + pCfg->szName, PDMAudioDirGetName(pCfg->enmDir), PDMAudioPropsChannels(&pCfg->Props), + PDMAudioPropsIsSigned(&pCfg->Props) ? 'S' : 'U', PDMAudioPropsSampleBits(&pCfg->Props), + PDMAudioPropsHz(&pCfg->Props), pCfg->Props.fSwapEndian ? " swap" : "", pCfg->Props.fRaw ? " raw" : "", + PDMAudioPropsFramesToMilliMax(&pCfg->Props, pCfg->Backend.cFramesBufferSize, 9999999), + PDMAudioPropsFramesToMilliMax(&pCfg->Props, pCfg->Backend.cFramesPeriod, 9999999), + PDMAudioPropsFramesToMilliMax(&pCfg->Props, pCfg->Backend.cFramesPreBuffering, 9999999), + pCfg->Device.cMsSchedulingHint, + pCfg->enmPath == PDMAUDIOPATH_UNKNOWN ? "" : ", ", + pCfg->enmPath == PDMAUDIOPATH_UNKNOWN ? "" : PDMAudioPathGetName(pCfg->enmPath) ); + return pszDst; +} + + +/********************************************************************************************************************************* +* Stream Status Helpers * +*********************************************************************************************************************************/ + +/** + * Converts a audio stream state enum value to a string. + * + * @returns Pointer to read-only audio stream state string on success, + * "illegal" if invalid command value. + * @param enmStreamState The state to convert. + */ +DECLINLINE(const char *) PDMAudioStreamStateGetName(PDMAUDIOSTREAMSTATE enmStreamState) +{ + switch (enmStreamState) + { + case PDMAUDIOSTREAMSTATE_INVALID: return "invalid"; + case PDMAUDIOSTREAMSTATE_NOT_WORKING: return "not-working"; + case PDMAUDIOSTREAMSTATE_NEED_REINIT: return "need-reinit"; + case PDMAUDIOSTREAMSTATE_INACTIVE: return "inactive"; + case PDMAUDIOSTREAMSTATE_ENABLED: return "enabled"; + case PDMAUDIOSTREAMSTATE_ENABLED_READABLE: return "enabled-readable"; + case PDMAUDIOSTREAMSTATE_ENABLED_WRITABLE: return "enabled-writable"; + /* no default: */ + case PDMAUDIOSTREAMSTATE_END: + case PDMAUDIOSTREAMSTATE_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Invalid audio stream state: %d\n", enmStreamState), "illegal"); +} + +/** + * Converts a host audio (backend) stream state enum value to a string. + * + * @returns Pointer to read-only host audio stream state string on success, + * "illegal" if invalid command value. + * @param enmHostAudioStreamState The state to convert. + */ +DECLINLINE(const char *) PDMHostAudioStreamStateGetName(PDMHOSTAUDIOSTREAMSTATE enmHostAudioStreamState) +{ + switch (enmHostAudioStreamState) + { + case PDMHOSTAUDIOSTREAMSTATE_INVALID: return "invalid"; + case PDMHOSTAUDIOSTREAMSTATE_INITIALIZING: return "initializing"; + case PDMHOSTAUDIOSTREAMSTATE_NOT_WORKING: return "not-working"; + case PDMHOSTAUDIOSTREAMSTATE_OKAY: return "okay"; + case PDMHOSTAUDIOSTREAMSTATE_DRAINING: return "draining"; + case PDMHOSTAUDIOSTREAMSTATE_INACTIVE: return "inactive"; + /* no default: */ + case PDMHOSTAUDIOSTREAMSTATE_END: + case PDMHOSTAUDIOSTREAMSTATE_32BIT_HACK: + break; + } + AssertMsgFailedReturn(("Invalid host audio stream state: %d\n", enmHostAudioStreamState), "illegal"); +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmaudioinline_h */ diff --git a/include/VBox/vmm/pdmblkcache.h b/include/VBox/vmm/pdmblkcache.h new file mode 100644 index 00000000..c9ff51d1 --- /dev/null +++ b/include/VBox/vmm/pdmblkcache.h @@ -0,0 +1,432 @@ +/** @file + * PDM - Pluggable Device Manager, Block cache. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmblkcache_h +#define VBOX_INCLUDED_vmm_pdmblkcache_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_blk_cache The PDM Block Cache API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM block cache. */ +typedef struct PDMBLKCACHE *PPDMBLKCACHE; +/** Pointer to a PDM block cache pointer. */ +typedef PPDMBLKCACHE *PPPDMBLKCACHE; + +/** I/O transfer handle. */ +typedef struct PDMBLKCACHEIOXFER *PPDMBLKCACHEIOXFER; + +/** + * Block cache I/O request transfer direction. + */ +typedef enum PDMBLKCACHEXFERDIR +{ + /** Read */ + PDMBLKCACHEXFERDIR_READ = 0, + /** Write */ + PDMBLKCACHEXFERDIR_WRITE, + /** Flush */ + PDMBLKCACHEXFERDIR_FLUSH, + /** Discard */ + PDMBLKCACHEXFERDIR_DISCARD +} PDMBLKCACHEXFERDIR; + +/** + * Completion callback for drivers. + * + * @param pDrvIns The driver instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMBLKCACHEXFERCOMPLETEDRV,(PPDMDRVINS pDrvIns, void *pvUser, int rc)); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEDRV(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEDRV *PFNPDMBLKCACHEXFERCOMPLETEDRV; + +/** + * I/O enqueue callback for drivers. + * + * @param pDrvIns The driver instance. + * @param enmXferDir Transfer direction. + * @param off Transfer offset. + * @param cbXfer Transfer size. + * @param pSgBuf Scather / gather buffer for the transfer. + * @param hIoXfer I/O transfer handle to ping on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDRV,(PPDMDRVINS pDrvIns, PDMBLKCACHEXFERDIR enmXferDir, uint64_t off, + size_t cbXfer, PCRTSGBUF pSgBuf, PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDRV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDRV *PFNPDMBLKCACHEXFERENQUEUEDRV; + +/** + * Discard enqueue callback for drivers. + * + * @param pDrvIns The driver instance. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDISCARDDRV,(PPDMDRVINS pDrvIns, PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDDRV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDDRV *PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV; + +/** + * Completion callback for devices. + * + * @param pDevIns The device instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMBLKCACHEXFERCOMPLETEDEV,(PPDMDEVINS pDevIns, void *pvUser, int rc)); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEDEV(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEDEV *PFNPDMBLKCACHEXFERCOMPLETEDEV; + +/** + * I/O enqueue callback for devices. + * + * @param pDevIns The device instance. + * @param enmXferDir Transfer direction. + * @param off Transfer offset. + * @param cbXfer Transfer size. + * @param pSgBuf Scather / gather buffer for the transfer. + * @param hIoXfer I/O transfer handle to ping on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDEV,(PPDMDEVINS pDevIns, PDMBLKCACHEXFERDIR enmXferDir, uint64_t off, + size_t cbXfer, PCRTSGBUF pSgBuf, PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDEV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDEV *PFNPDMBLKCACHEXFERENQUEUEDEV; + +/** + * Discard enqueue callback for devices. + * + * @param pDevIns The device instance. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDISCARDDEV,(PPDMDEVINS pDevIns, PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDDEV(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDDEV *PFNPDMBLKCACHEXFERENQUEUEDISCARDDEV; + +/** + * Completion callback for drivers. + * + * @param pvUserInt User argument given to PDMR3BlkCacheRetainInt. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMBLKCACHEXFERCOMPLETEINT,(void *pvUserInt, void *pvUser, int rc)); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEINT(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEINT *PFNPDMBLKCACHEXFERCOMPLETEINT; + +/** + * I/O enqueue callback for internal users. + * + * @param pvUser User data. + * @param enmXferDir Transfer direction. + * @param off Transfer offset. + * @param cbXfer Transfer size. + * @param pSgBuf Scather / gather buffer for the transfer. + * @param hIoXfer I/O transfer handle to ping on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEINT,(void *pvUser, PDMBLKCACHEXFERDIR enmXferDir, uint64_t off, + size_t cbXfer, PCRTSGBUF pSgBuf, PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEINT(). */ +typedef FNPDMBLKCACHEXFERENQUEUEINT *PFNPDMBLKCACHEXFERENQUEUEINT; + +/** + * Discard enqueue callback for VMM internal users. + * + * @param pvUser User data. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDISCARDINT,(void *pvUser, PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDINT(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDINT *PFNPDMBLKCACHEXFERENQUEUEDISCARDINT; + +/** + * Completion callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param pvUser User argument given during request initiation. + * @param rc The status code of the completed request. + */ +typedef DECLCALLBACKTYPE(void, FNPDMBLKCACHEXFERCOMPLETEUSB,(PPDMUSBINS pUsbIns, void *pvUser, int rc)); +/** Pointer to a FNPDMBLKCACHEXFERCOMPLETEUSB(). */ +typedef FNPDMBLKCACHEXFERCOMPLETEUSB *PFNPDMBLKCACHEXFERCOMPLETEUSB; + +/** + * I/O enqueue callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param enmXferDir Transfer direction. + * @param off Transfer offset. + * @param cbXfer Transfer size. + * @param pSgBuf Scather / gather buffer for the transfer. + * @param hIoXfer I/O transfer handle to ping on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEUSB,(PPDMUSBINS pUsbIns, PDMBLKCACHEXFERDIR enmXferDir, uint64_t off, + size_t cbXfer, PCRTSGBUF pSgBuf, PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEUSB(). */ +typedef FNPDMBLKCACHEXFERENQUEUEUSB *PFNPDMBLKCACHEXFERENQUEUEUSB; + +/** + * Discard enqueue callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param paRanges Ranges to discard. + * @param cRanges Number of range entries. + * @param hIoXfer I/O handle to return on completion. + */ +typedef DECLCALLBACKTYPE(int, FNPDMBLKCACHEXFERENQUEUEDISCARDUSB,(PPDMUSBINS pUsbIns, PCRTRANGE paRanges, unsigned cRanges, + PPDMBLKCACHEIOXFER hIoXfer)); +/** Pointer to a FNPDMBLKCACHEXFERENQUEUEDISCARDUSB(). */ +typedef FNPDMBLKCACHEXFERENQUEUEDISCARDUSB *PFNPDMBLKCACHEXFERENQUEUEDISCARDUSB; + +/** + * Create a block cache user for a driver instance. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pDrvIns The driver instance. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ +VMMR3DECL(int) PDMR3BlkCacheRetainDriver(PVM pVM, PPDMDRVINS pDrvIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard, + const char *pcszId); + +/** + * Create a block cache user for a device instance. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pDevIns The device instance. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ +VMMR3DECL(int) PDMR3BlkCacheRetainDevice(PVM pVM, PPDMDEVINS pDevIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEDEV pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEDEV pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDDEV pfnXferEnqueueDiscard, + const char *pcszId); + +/** + * Create a block cache user for a USB instance. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pUsbIns The USB device instance. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ +VMMR3DECL(int) PDMR3BlkCacheRetainUsb(PVM pVM, PPDMUSBINS pUsbIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEUSB pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEUSB pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDUSB pfnXferEnqueueDiscard, + const char *pcszId); + +/** + * Create a block cache user for internal use by VMM. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pvUser Opaque user data. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ +VMMR3DECL(int) PDMR3BlkCacheRetainInt(PVM pVM, void *pvUser, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEINT pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEINT pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDINT pfnXferEnqueueDiscard, + const char *pcszId); + +/** + * Releases a block cache handle. + * + * @returns nothing. + * @param pBlkCache Block cache handle. + */ +VMMR3DECL(void) PDMR3BlkCacheRelease(PPDMBLKCACHE pBlkCache); + +/** + * Releases all block cache handles for a device instance. + * + * @returns nothing. + * @param pVM The cross context VM structure. + * @param pDevIns The device instance. + */ +VMMR3DECL(void) PDMR3BlkCacheReleaseDevice(PVM pVM, PPDMDEVINS pDevIns); + +/** + * Releases all block cache handles for a driver instance. + * + * @returns nothing. + * @param pVM The cross context VM structure. + * @param pDrvIns The driver instance. + */ +VMMR3DECL(void) PDMR3BlkCacheReleaseDriver(PVM pVM, PPDMDRVINS pDrvIns); + +/** + * Releases all block cache handles for a USB device instance. + * + * @returns nothing. + * @param pVM The cross context VM structure. + * @param pUsbIns The USB device instance. + */ +VMMR3DECL(void) PDMR3BlkCacheReleaseUsb(PVM pVM, PPDMUSBINS pUsbIns); + +/** + * Creates a read task on the given endpoint. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + * @param off Where to start reading from. + * @param pSgBuf Scatter gather buffer store the data in. + * @param cbRead The overall number of bytes to read. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the read. + */ +VMMR3DECL(int) PDMR3BlkCacheRead(PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser); + +/** + * Creates a write task on the given endpoint. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + * @param off Where to start writing at. + * @param pSgBuf Scatter gather buffer gather the data from. + * @param cbWrite The overall number of bytes to write. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the task. + */ +VMMR3DECL(int) PDMR3BlkCacheWrite(PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbWrite, void *pvUser); + +/** + * Creates a flush task on the given endpoint. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the task. + */ +VMMR3DECL(int) PDMR3BlkCacheFlush(PPDMBLKCACHE pBlkCache, void *pvUser); + +/** + * Discards the given ranges from the cache. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + * @param paRanges Array of ranges to discard. + * @param cRanges Number of ranges in the array. + * @param pvUser Opaque user data returned in the completion callback + * upon completion of the task. + */ +VMMR3DECL(int) PDMR3BlkCacheDiscard(PPDMBLKCACHE pBlkCache, PCRTRANGE paRanges, unsigned cRanges, void *pvUser); + +/** + * Notify the cache of a complete I/O transfer. + * + * @returns nothing. + * @param pBlkCache The cache instance. + * @param hIoXfer The I/O transfer handle which completed. + * @param rcIoXfer The status code of the completed request. + */ +VMMR3DECL(void) PDMR3BlkCacheIoXferComplete(PPDMBLKCACHE pBlkCache, PPDMBLKCACHEIOXFER hIoXfer, int rcIoXfer); + +/** + * Suspends the block cache. + * + * The cache waits until all I/O transfers completed and stops to enqueue new + * requests after the call returned but will not accept reads, write or flushes + * either. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + */ +VMMR3DECL(int) PDMR3BlkCacheSuspend(PPDMBLKCACHE pBlkCache); + +/** + * Resumes operation of the block cache. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + */ +VMMR3DECL(int) PDMR3BlkCacheResume(PPDMBLKCACHE pBlkCache); + +/** + * Clears the block cache and removes all entries. + * + * The cache waits until all I/O transfers completed. + * + * @returns VBox status code. + * @param pBlkCache The cache instance. + */ +VMMR3DECL(int) PDMR3BlkCacheClear(PPDMBLKCACHE pBlkCache); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmblkcache_h */ + diff --git a/include/VBox/vmm/pdmcardreaderinfs.h b/include/VBox/vmm/pdmcardreaderinfs.h new file mode 100644 index 00000000..c0949c9d --- /dev/null +++ b/include/VBox/vmm/pdmcardreaderinfs.h @@ -0,0 +1,136 @@ +/* $Id: pdmcardreaderinfs.h $ */ +/** @file + * cardreaderinfs - interface between USB Card Reader device and its driver. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmcardreaderinfs_h +#define VBOX_INCLUDED_vmm_pdmcardreaderinfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/** @defgroup grp_pdm_ifs_cardreader PDM USB Card Reader Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +typedef struct PDMICARDREADER_IO_REQUEST +{ + uint32_t u32Protocol; /**< Protocol identifier */ + uint32_t cbPciLength; /**< Protocol Control Information Length */ + /* 'cbPciLength - 8' bytes of control info may follow. */ +} PDMICARDREADER_IO_REQUEST; + +typedef struct PDMICARDREADER_READERSTATE +{ + char *pszReaderName; + uint32_t u32CurrentState; /**< Current state of reader at time of call. */ + uint32_t u32EventState; /**< State of reader after state change */ + uint32_t cbAtr; /**< Number of bytes in the returned ATR. */ + uint8_t au8Atr[36]; /**< Atr of inserted card, (extra alignment bytes) */ +} PDMICARDREADER_READERSTATE; + + +#define PDMICARDREADERDOWN_IID "78d65378-889c-4418-8bc2-7a89a5af2817" +typedef struct PDMICARDREADERDOWN PDMICARDREADERDOWN; +typedef PDMICARDREADERDOWN *PPDMICARDREADERDOWN; +struct PDMICARDREADERDOWN +{ + DECLR3CALLBACKMEMBER(int, pfnEstablishContext,(PPDMICARDREADERDOWN pInterface)); + DECLR3CALLBACKMEMBER(int, pfnConnect,(PPDMICARDREADERDOWN pInterface, void *pvUser, const char *pszCardReaderName, + uint32_t u32ShareMode, uint32_t u32PreferredProtocols)); + DECLR3CALLBACKMEMBER(int, pfnDisconnect,(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32Disposition)); + DECLR3CALLBACKMEMBER(int, pfnStatus,(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t cchReaderName, uint32_t cbAtrLen)); + DECLR3CALLBACKMEMBER(int, pfnReleaseContext,(PPDMICARDREADERDOWN pInterface, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnGetStatusChange,(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32Timeout, + PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats)); + DECLR3CALLBACKMEMBER(int, pfnBeginTransaction,(PPDMICARDREADERDOWN pInterface, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnEndTransaction,(PPDMICARDREADERDOWN pInterface, void *pvUser, uint32_t u32Disposition)); + DECLR3CALLBACKMEMBER(int, pfnTransmit,(PPDMICARDREADERDOWN pInterface, void *pvUser, + const PDMICARDREADER_IO_REQUEST *pioSendRequest, + const uint8_t *pu8SendBuffer, uint32_t cbSendBuffer, uint32_t cbRecvBuffer)); + /** + * Up level provides pvInBuffer of cbInBuffer bytes to call SCardControl, also it specify bytes it expects to receive + * @note Device/driver implementation should copy buffers before execution in + * async mode, and both layers shouldn't expect permanent storage for the + * buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnControl,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t u32ControlCode, const void *pvInBuffer, + uint32_t cbInBuffer, uint32_t cbOutBuffer)); + /** + * This function ask driver to provide attribute (dwAttribId) and provide limit (cbAttrib) of buffer size for attribute value, + * Callback UpGetAttrib returns buffer containing the value and altered size of the buffer. + */ + DECLR3CALLBACKMEMBER(int, pfnGetAttr,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t u32AttribId, uint32_t cbAttrib)); + DECLR3CALLBACKMEMBER(int, pfnSetAttr,(PPDMICARDREADERDOWN pInterface, void *pvUser, + uint32_t u32AttribId, const void *pvAttrib, uint32_t cbAttrib)); +}; + +#define PDMICARDREADERUP_IID "c0d7498e-0635-48ca-aab1-b11b6a55cf7d" +typedef struct PDMICARDREADERUP PDMICARDREADERUP; +typedef PDMICARDREADERUP *PPDMICARDREADERUP; +struct PDMICARDREADERUP +{ + DECLR3CALLBACKMEMBER(int, pfnEstablishContext,(PPDMICARDREADERUP pInterface, int32_t lSCardRc)); + DECLR3CALLBACKMEMBER(int, pfnStatus,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + char *pszReaderName, uint32_t cchReaderName, uint32_t u32CardState, + uint32_t u32Protocol, uint8_t *pu8Atr, uint32_t cbAtr)); + DECLR3CALLBACKMEMBER(int, pfnConnect,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + uint32_t u32ActiveProtocol)); + DECLR3CALLBACKMEMBER(int, pfnDisconnect,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc)); + DECLR3CALLBACKMEMBER(int, pfnSetStatusChange,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + PDMICARDREADER_READERSTATE *paReaderStats, uint32_t cReaderStats)); + DECLR3CALLBACKMEMBER(int, pfnBeginTransaction,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc)); + DECLR3CALLBACKMEMBER(int, pfnEndTransaction,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc)); + /* Note: pioRecvPci stack variable */ + DECLR3CALLBACKMEMBER(int, pfnTransmit,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + const PDMICARDREADER_IO_REQUEST *pioRecvPci, + uint8_t *pu8RecvBuffer, uint32_t cbRecvBuffer)); + DECLR3CALLBACKMEMBER(int, pfnControl,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + uint32_t u32ControlCode, void *pvOutBuffer, uint32_t cbOutBuffer)); + DECLR3CALLBACKMEMBER(int, pfnGetAttrib,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, + uint32_t u32AttribId, void *pvAttrib, uint32_t cbAttrib)); + DECLR3CALLBACKMEMBER(int, pfnSetAttrib,(PPDMICARDREADERUP pInterface, void *pvUser, int32_t lSCardRc, uint32_t u32AttribId)); +}; + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmcardreaderinfs_h */ + diff --git a/include/VBox/vmm/pdmcommon.h b/include/VBox/vmm/pdmcommon.h new file mode 100644 index 00000000..7257ff0b --- /dev/null +++ b/include/VBox/vmm/pdmcommon.h @@ -0,0 +1,192 @@ +/** @file + * PDM - Pluggable Device Manager, Common Definitions & Types. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmcommon_h +#define VBOX_INCLUDED_vmm_pdmcommon_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +/** @defgroup grp_pdm_common Common Definitions & Types + * @ingroup grp_pdm + * + * Not all the types here are "common", they are here to work around header + * ordering issues. + * + * @{ + */ + +/** Makes a PDM structure version out of an unique magic value and major & + * minor version numbers. + * + * @returns 32-bit structure version number. + * + * @param uMagic 16-bit magic value. This must be unique. + * @param uMajor 12-bit major version number. Structures with different + * major numbers are not compatible. + * @param uMinor 4-bit minor version number. When only the minor version + * differs, the structures will be 100% backwards + * compatible. + */ +#define PDM_VERSION_MAKE(uMagic, uMajor, uMinor) \ + ( ((uint32_t)(uMagic) << 16) | ((uint32_t)((uMajor) & 0xff) << 4) | ((uint32_t)((uMinor) & 0xf) << 0) ) + +/** + * Version of PDM_VERSION_MAKE that's compatible with the preprocessor. + * + * @returns 32-bit structure version number. + * + * @param uMagic 16-bit magic value, no suffix. This must be unique. + * @param uMajor 12-bit major version number, no suffix. Structures with + * different major numbers are not compatible. + * @param uMinor 4-bit minor version number, no suffix. When only the + * minor version differs, the structures will be 100% + * backwards compatible. + */ +#define PDM_VERSION_MAKE_PP(uMagic, uMajor, uMinor) \ + ( (UINT32_C(uMagic) << 16) | ((UINT32_C(uMajor) & UINT32_C(0xff)) << 4) | ((UINT32_C(uMinor) & UINT32_C(0xf)) << 0) ) + +/** Checks if @a uVerMagic1 is compatible with @a uVerMagic2. + * + * @returns true / false. + * @param uVerMagic1 Typically the runtime version of the struct. This must + * have the same magic and major version as @a uVerMagic2 + * and the minor version must be greater or equal to that + * of @a uVerMagic2. + * @param uVerMagic2 Typically the version the code was compiled against. + * + * @remarks The parameters will be referenced more than once. + */ +#define PDM_VERSION_ARE_COMPATIBLE(uVerMagic1, uVerMagic2) \ + ( (uVerMagic1) == (uVerMagic2) \ + || ( (uVerMagic1) >= (uVerMagic2) \ + && ((uVerMagic1) & UINT32_C(0xfffffff0)) == ((uVerMagic2) & UINT32_C(0xfffffff0)) ) \ + ) + + +/** @name PDM Attach/Detach Callback Flags. + * Used by PDMDeviceAttach, PDMDeviceDetach, PDMDriverAttach, PDMDriverDetach, + * FNPDMDEVATTACH, FNPDMDEVDETACH, FNPDMDRVATTACH, FNPDMDRVDETACH and + * FNPDMDRVCONSTRUCT. + * @{ */ +/** The attach/detach command is not a hotplug event. */ +#define PDM_TACH_FLAGS_NOT_HOT_PLUG RT_BIT_32(0) +/** Indicates that no attach or detach callbacks should be made. + * This is mostly for internal use. */ +#define PDM_TACH_FLAGS_NO_CALLBACKS RT_BIT_32(1) +/** @} */ + + +/** + * Is asynchronous handling of suspend or power off notification completed? + * + * This is called to check whether the USB device has quiesced. Don't deadlock. + * Avoid blocking. Do NOT wait for anything. + * + * @returns true if done, false if more work to be done. + * + * @param pUsbIns The USB device instance. + * + * @thread EMT(0) + */ +typedef DECLCALLBACKTYPE(bool, FNPDMUSBASYNCNOTIFY,(PPDMUSBINS pUsbIns)); +/** Pointer to a FNPDMUSBASYNCNOTIFY. */ +typedef FNPDMUSBASYNCNOTIFY *PFNPDMUSBASYNCNOTIFY; + +/** + * Is asynchronous handling of suspend or power off notification completed? + * + * This is called to check whether the device has quiesced. Don't deadlock. + * Avoid blocking. Do NOT wait for anything. + * + * @returns true if done, false if more work to be done. + * + * @param pDevIns The device instance. + * @remarks The caller will enter the device critical section. + * @thread EMT(0) + */ +typedef DECLCALLBACKTYPE(bool, FNPDMDEVASYNCNOTIFY,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVASYNCNOTIFY. */ +typedef FNPDMDEVASYNCNOTIFY *PFNPDMDEVASYNCNOTIFY; + +/** + * Is asynchronous handling of suspend or power off notification completed? + * + * This is called to check whether the driver has quiesced. Don't deadlock. + * Avoid blocking. Do NOT wait for anything. + * + * @returns true if done, false if more work to be done. + * + * @param pDrvIns The driver instance. + * + * @thread EMT(0) + */ +typedef DECLCALLBACKTYPE(bool, FNPDMDRVASYNCNOTIFY,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVASYNCNOTIFY. */ +typedef FNPDMDRVASYNCNOTIFY *PFNPDMDRVASYNCNOTIFY; + + +/** + * The ring-0 driver request handler. + * + * @returns VBox status code. PDMDevHlpCallR0 will return this. + * @param pDevIns The device instance (the ring-0 mapping). + * @param uOperation The operation. + * @param u64Arg Optional integer argument for the operation. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDEVREQHANDLERR0,(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg)); +/** Ring-0 pointer to a FNPDMDEVREQHANDLERR0. */ +typedef R0PTRTYPE(FNPDMDEVREQHANDLERR0 *) PFNPDMDEVREQHANDLERR0; + +/** + * The ring-0 driver request handler. + * + * @returns VBox status code. PDMDrvHlpCallR0 will return this. + * @param pDrvIns The driver instance (the ring-0 mapping). + * @param uOperation The operation. + * @param u64Arg Optional integer argument for the operation. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDRVREQHANDLERR0,(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)); +/** Ring-0 pointer to a FNPDMDRVREQHANDLERR0. */ +typedef R0PTRTYPE(FNPDMDRVREQHANDLERR0 *) PFNPDMDRVREQHANDLERR0; + + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmcommon_h */ + diff --git a/include/VBox/vmm/pdmcritsect.h b/include/VBox/vmm/pdmcritsect.h new file mode 100644 index 00000000..79445ecb --- /dev/null +++ b/include/VBox/vmm/pdmcritsect.h @@ -0,0 +1,143 @@ +/** @file + * PDM - Pluggable Device Manager, Critical Sections. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmcritsect_h +#define VBOX_INCLUDED_vmm_pdmcritsect_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_critsect The PDM Critical Section API + * @ingroup grp_pdm + * @{ + */ + +/** + * A PDM critical section. + * Initialize using PDMDRVHLP::pfnCritSectInit(). + */ +typedef union PDMCRITSECT +{ + /** Padding. */ + uint8_t padding[HC_ARCH_BITS == 32 ? 0xc0 : 0x100]; +#ifdef PDMCRITSECTINT_DECLARED + /** The internal structure (not normally visible). */ + struct PDMCRITSECTINT s; +#endif +} PDMCRITSECT; + +VMMR3_INT_DECL(int) PDMR3CritSectBothTerm(PVM pVM); +VMMR3_INT_DECL(void) PDMR3CritSectLeaveAll(PVM pVM); +VMM_INT_DECL(void) PDMCritSectBothFF(PVMCC pVM, PVMCPUCC pVCpu); + + +VMMR3DECL(uint32_t) PDMR3CritSectCountOwned(PVM pVM, char *pszNames, size_t cbNames); + +VMMR3DECL(int) PDMR3CritSectInit(PVM pVM, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMR3DECL(int) PDMR3CritSectEnterEx(PVM pVM, PPDMCRITSECT pCritSect, bool fCallRing3); +VMMR3DECL(bool) PDMR3CritSectYield(PVM pVM, PPDMCRITSECT pCritSect); +VMMR3DECL(const char *) PDMR3CritSectName(PCPDMCRITSECT pCritSect); +VMMR3DECL(int) PDMR3CritSectDelete(PVM pVM, PPDMCRITSECT pCritSect); +#if defined(IN_RING0) || defined(IN_RING3) +VMMDECL(int) PDMHCCritSectScheduleExitEvent(PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal); +#endif + +VMMDECL(DECL_CHECK_RETURN_NOT_R3(int)) + PDMCritSectEnter(PVMCC pVM, PPDMCRITSECT pCritSect, int rcBusy); +VMMDECL(DECL_CHECK_RETURN_NOT_R3(int)) + PDMCritSectEnterDebug(PVMCC pVM, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(DECL_CHECK_RETURN(int)) + PDMCritSectTryEnter(PVMCC pVM, PPDMCRITSECT pCritSect); +VMMDECL(DECL_CHECK_RETURN(int)) + PDMCritSectTryEnterDebug(PVMCC pVM, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectLeave(PVMCC pVM, PPDMCRITSECT pCritSect); + +VMMDECL(bool) PDMCritSectIsOwner(PVMCC pVM, PCPDMCRITSECT pCritSect); +VMMDECL(bool) PDMCritSectIsOwnerEx(PVMCPUCC pVCpu, PCPDMCRITSECT pCritSect); +VMMDECL(bool) PDMCritSectIsInitialized(PCPDMCRITSECT pCritSect); +VMMDECL(bool) PDMCritSectHasWaiters(PVMCC pVM, PCPDMCRITSECT pCritSect); +VMMDECL(uint32_t) PDMCritSectGetRecursion(PCPDMCRITSECT pCritSect); + +VMMR3DECL(PPDMCRITSECT) PDMR3CritSectGetNop(PVM pVM); + +/* Strict build: Remap the two enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMCritSectEnter(a_pVM, pCritSect, rcBusy) PDMCritSectEnterDebug((a_pVM), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMCritSectTryEnter(a_pVM, pCritSect) PDMCritSectTryEnterDebug((a_pVM), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMCritSectEnter(a_pVM, pCritSect, rcBusy) PDMCritSectEnterDebug((a_pVM), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMCritSectTryEnter(a_pVM, pCritSect) PDMCritSectTryEnterDebug((a_pVM), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +/** @def PDM_CRITSECT_RELEASE_ASSERT_RC + * Helper for PDMCritSectEnter w/ rcBusy VINF_SUCCESS when there is no way + * to forward failures to the caller. */ +#define PDM_CRITSECT_RELEASE_ASSERT_RC(a_pVM, a_pCritSect, a_rc) \ + AssertReleaseMsg(RT_SUCCESS(a_rc), ("pVM=%p pCritSect=%p: %Rrc\n", (a_pVM), (a_pCritSect), (a_rc))) + +/** @def PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + * Helper for PDMCritSectEnter w/ rcBusy VINF_SUCCESS when there is no way + * to forward failures to the caller, device edition. */ +#define PDM_CRITSECT_RELEASE_ASSERT_RC_DEV(a_pDevIns, a_pCritSect, a_rc) \ + AssertReleaseMsg(RT_SUCCESS(a_rc), ("pDevIns=%p pCritSect=%p: %Rrc\n", (a_pDevIns), (a_pCritSect), (a_rc))) + +/** @def PDM_CRITSECT_RELEASE_ASSERT_RC_DRV + * Helper for PDMCritSectEnter w/ rcBusy VINF_SUCCESS when there is no way + * to forward failures to the caller, driver edition. */ +#define PDM_CRITSECT_RELEASE_ASSERT_RC_DRV(a_pDrvIns, a_pCritSect, a_rc) \ + AssertReleaseMsg(RT_SUCCESS(a_rc), ("pDrvIns=%p pCritSect=%p: %Rrc\n", (a_pDrvIns), (a_pCritSect), (a_rc))) + +/** @def PDM_CRITSECT_RELEASE_ASSERT_RC_USB + * Helper for PDMCritSectEnter w/ rcBusy VINF_SUCCESS when there is no way + * to forward failures to the caller, USB device edition. */ +#define PDM_CRITSECT_RELEASE_ASSERT_RC_USB(a_pUsbIns, a_pCritSect, a_rc) \ + AssertReleaseMsg(RT_SUCCESS(a_rc), ("pUsbIns=%p pCritSect=%p: %Rrc\n", (a_pUsbIns), (a_pCritSect), (a_rc))) + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmcritsect_h */ + diff --git a/include/VBox/vmm/pdmcritsectrw.h b/include/VBox/vmm/pdmcritsectrw.h new file mode 100644 index 00000000..8b3eb319 --- /dev/null +++ b/include/VBox/vmm/pdmcritsectrw.h @@ -0,0 +1,111 @@ +/** @file + * PDM - Pluggable Device Manager, Read/Write Critical Section. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmcritsectrw_h +#define VBOX_INCLUDED_vmm_pdmcritsectrw_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_critsectrw The PDM Read/Write Critical Section API + * @ingroup grp_pdm + * @{ + */ + +/** + * A PDM read/write critical section. + * Initialize using PDMDRVHLP::pfnCritSectRwInit(). + */ +typedef union PDMCRITSECTRW +{ + /** Padding. */ + uint8_t padding[HC_ARCH_BITS == 32 ? 0xc0 : 0x100]; +#ifdef PDMCRITSECTRWINT_DECLARED + /** The internal structure (not normally visible). */ + struct PDMCRITSECTRWINT s; +#endif +} PDMCRITSECTRW; + +VMMR3DECL(int) PDMR3CritSectRwInit(PVM pVM, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMR3DECL(int) PDMR3CritSectRwDelete(PVM pVM, PPDMCRITSECTRW pCritSect); +VMMR3DECL(const char *) PDMR3CritSectRwName(PCPDMCRITSECTRW pCritSect); +VMMR3DECL(int) PDMR3CritSectRwEnterSharedEx(PVM pVM, PPDMCRITSECTRW pThis, bool fCallRing3); +VMMR3DECL(int) PDMR3CritSectRwEnterExclEx(PVM pVM, PPDMCRITSECTRW pThis, bool fCallRing3); + +VMMDECL(int) PDMCritSectRwEnterShared(PVMCC pVM, PPDMCRITSECTRW pCritSect, int rcBusy); +VMMDECL(int) PDMCritSectRwEnterSharedDebug(PVMCC pVM, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectRwTryEnterShared(PVMCC pVM, PPDMCRITSECTRW pCritSect); +VMMDECL(int) PDMCritSectRwTryEnterSharedDebug(PVMCC pVM, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectRwLeaveShared(PVMCC pVM, PPDMCRITSECTRW pCritSect); +VMMDECL(int) PDMCritSectRwEnterExcl(PVMCC pVM, PPDMCRITSECTRW pCritSect, int rcBusy); +VMMDECL(int) PDMCritSectRwEnterExclDebug(PVMCC pVM, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectRwTryEnterExcl(PVMCC pVM, PPDMCRITSECTRW pCritSect); +VMMDECL(int) PDMCritSectRwTryEnterExclDebug(PVMCC pVM, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL); +VMMDECL(int) PDMCritSectRwLeaveExcl(PVMCC pVM, PPDMCRITSECTRW pCritSect); + +VMMDECL(bool) PDMCritSectRwIsWriteOwner(PVMCC pVM, PPDMCRITSECTRW pCritSect); +VMMDECL(bool) PDMCritSectRwIsReadOwner(PVMCC pVM, PPDMCRITSECTRW pCritSect, bool fWannaHear); +VMMDECL(uint32_t) PDMCritSectRwGetWriteRecursion(PPDMCRITSECTRW pCritSect); +VMMDECL(uint32_t) PDMCritSectRwGetWriterReadRecursion(PPDMCRITSECTRW pCritSect); +VMMDECL(uint32_t) PDMCritSectRwGetReadCount(PPDMCRITSECTRW pCritSect); +VMMDECL(bool) PDMCritSectRwIsInitialized(PCPDMCRITSECTRW pCritSect); + +/* Lock strict build: Remap the three enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMCritSectRwEnterExcl(a_pVM, pCritSect, rcBusy) PDMCritSectRwEnterExclDebug((a_pVM), pCritSect, rcBusy, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMCritSectRwTryEnterExcl(a_pVM, pCritSect) PDMCritSectRwTryEnterExclDebug((a_pVM), pCritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMCritSectRwEnterShared(a_pVM, pCritSect, rcBusy) PDMCritSectRwEnterSharedDebug((a_pVM), pCritSect, rcBusy, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMCritSectRwTryEnterShared(a_pVM, pCritSect) PDMCritSectRwTryEnterSharedDebug((a_pVM), pCritSect, (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMCritSectRwEnterExcl(a_pVM, pCritSect, rcBusy) PDMCritSectRwEnterExclDebug((a_pVM), pCritSect, rcBusy, 0, RT_SRC_POS) +# define PDMCritSectRwTryEnterExcl(a_pVM, pCritSect) PDMCritSectRwTryEnterExclDebug((a_pVM), pCritSect, 0, RT_SRC_POS) +# define PDMCritSectRwEnterShared(a_pVM, pCritSect, rcBusy) PDMCritSectRwEnterSharedDebug((a_pVM), pCritSect, rcBusy, 0, RT_SRC_POS) +# define PDMCritSectRwTryEnterShared(a_pVM, pCritSect) PDMCritSectRwTryEnterSharedDebug((a_pVM), pCritSect, 0, RT_SRC_POS) +# endif +#endif + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmcritsectrw_h */ + diff --git a/include/VBox/vmm/pdmdev.h b/include/VBox/vmm/pdmdev.h new file mode 100644 index 00000000..fd92fef8 --- /dev/null +++ b/include/VBox/vmm/pdmdev.h @@ -0,0 +1,9690 @@ +/** @file + * PDM - Pluggable Device Manager, Devices. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmdev_h +#define VBOX_INCLUDED_vmm_pdmdev_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#ifdef IN_RING3 +# include +#endif +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* PGMR3HandlerPhysicalTypeRegister() argument types. */ +#include +#include /* VINF_EM_DBG_STOP, also 120+ source files expecting this. */ +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_device The PDM Devices API + * @ingroup grp_pdm + * @{ + */ + +/** + * Construct a device instance for a VM. + * + * @returns VBox status. + * @param pDevIns The device instance data. If the registration structure + * is needed, it can be accessed thru pDevIns->pReg. + * @param iInstance Instance number. Use this to figure out which registers + * and such to use. The instance number is also found in + * pDevIns->iInstance, but since it's likely to be + * frequently used PDM passes it as parameter. + * @param pCfg Configuration node handle for the driver. This is + * expected to be in high demand in the constructor and is + * therefore passed as an argument. When using it at other + * times, it can be found in pDevIns->pCfg. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDEVCONSTRUCT,(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg)); +/** Pointer to a FNPDMDEVCONSTRUCT() function. */ +typedef FNPDMDEVCONSTRUCT *PFNPDMDEVCONSTRUCT; + +/** + * Destruct a device instance. + * + * Most VM resources are freed by the VM. This callback is provided so that any non-VM + * resources can be freed correctly. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remarks The device critical section is not entered. The routine may delete + * the critical section, so the caller cannot exit it. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDEVDESTRUCT,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVDESTRUCT() function. */ +typedef FNPDMDEVDESTRUCT *PFNPDMDEVDESTRUCT; + +/** + * Device relocation callback. + * + * This is called when the instance data has been relocated in raw-mode context + * (RC). It is also called when the RC hypervisor selects changes. The device + * must fixup all necessary pointers and re-query all interfaces to other RC + * devices and drivers. + * + * Before the RC code is executed the first time, this function will be called + * with a 0 delta so RC pointer calculations can be one in one place. + * + * @param pDevIns Pointer to the device instance. + * @param offDelta The relocation delta relative to the old location. + * + * @remarks A relocation CANNOT fail. + * + * @remarks The device critical section is not entered. The relocations should + * not normally require any locking. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVRELOCATE,(PPDMDEVINS pDevIns, RTGCINTPTR offDelta)); +/** Pointer to a FNPDMDEVRELOCATE() function. */ +typedef FNPDMDEVRELOCATE *PFNPDMDEVRELOCATE; + +/** + * Power On notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVPOWERON,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVPOWERON() function. */ +typedef FNPDMDEVPOWERON *PFNPDMDEVPOWERON; + +/** + * Reset notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVRESET,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVRESET() function. */ +typedef FNPDMDEVRESET *PFNPDMDEVRESET; + +/** + * Soft reset notification. + * + * This is mainly for emulating the 286 style protected mode exits, in which + * most devices should remain in their current state. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * @param fFlags PDMVMRESET_F_XXX (only bits relevant to soft resets). + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVSOFTRESET,(PPDMDEVINS pDevIns, uint32_t fFlags)); +/** Pointer to a FNPDMDEVSOFTRESET() function. */ +typedef FNPDMDEVSOFTRESET *PFNPDMDEVSOFTRESET; + +/** @name PDMVMRESET_F_XXX - VM reset flags. + * These flags are used both for FNPDMDEVSOFTRESET and for hardware signalling + * reset via PDMDevHlpVMReset. + * @{ */ +/** Unknown reason. */ +#define PDMVMRESET_F_UNKNOWN UINT32_C(0x00000000) +/** GIM triggered reset. */ +#define PDMVMRESET_F_GIM UINT32_C(0x00000001) +/** The last source always causing hard resets. */ +#define PDMVMRESET_F_LAST_ALWAYS_HARD PDMVMRESET_F_GIM +/** ACPI triggered reset. */ +#define PDMVMRESET_F_ACPI UINT32_C(0x0000000c) +/** PS/2 system port A (92h) reset. */ +#define PDMVMRESET_F_PORT_A UINT32_C(0x0000000d) +/** Keyboard reset. */ +#define PDMVMRESET_F_KBD UINT32_C(0x0000000e) +/** Tripple fault. */ +#define PDMVMRESET_F_TRIPLE_FAULT UINT32_C(0x0000000f) +/** Reset source mask. */ +#define PDMVMRESET_F_SRC_MASK UINT32_C(0x0000000f) +/** @} */ + +/** + * Suspend notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * @thread EMT(0) + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVSUSPEND,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVSUSPEND() function. */ +typedef FNPDMDEVSUSPEND *PFNPDMDEVSUSPEND; + +/** + * Resume notification. + * + * @returns VBox status. + * @param pDevIns The device instance data. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVRESUME,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVRESUME() function. */ +typedef FNPDMDEVRESUME *PFNPDMDEVRESUME; + +/** + * Power Off notification. + * + * This is always called when VMR3PowerOff is called. + * There will be no callback when hot plugging devices. + * + * @param pDevIns The device instance data. + * @thread EMT(0) + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVPOWEROFF,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVPOWEROFF() function. */ +typedef FNPDMDEVPOWEROFF *PFNPDMDEVPOWEROFF; + +/** + * Attach command. + * + * This is called to let the device attach to a driver for a specified LUN + * at runtime. This is not called during VM construction, the device + * constructor has to attach to all the available drivers. + * + * This is like plugging in the keyboard or mouse after turning on the PC. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iLUN The logical unit which is being attached. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDEVATTACH,(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)); +/** Pointer to a FNPDMDEVATTACH() function. */ +typedef FNPDMDEVATTACH *PFNPDMDEVATTACH; + +/** + * Detach notification. + * + * This is called when a driver is detaching itself from a LUN of the device. + * The device should adjust its state to reflect this. + * + * This is like unplugging the network cable to use it for the laptop or + * something while the PC is still running. + * + * @param pDevIns The device instance. + * @param iLUN The logical unit which is being detached. + * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDEVDETACH,(PPDMDEVINS pDevIns, unsigned iLUN, uint32_t fFlags)); +/** Pointer to a FNPDMDEVDETACH() function. */ +typedef FNPDMDEVDETACH *PFNPDMDEVDETACH; + +/** + * Query the base interface of a logical unit. + * + * @returns VBOX status code. + * @param pDevIns The device instance. + * @param iLUN The logicial unit to query. + * @param ppBase Where to store the pointer to the base interface of the LUN. + * + * @remarks The device critical section is not entered. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDEVQUERYINTERFACE,(PPDMDEVINS pDevIns, unsigned iLUN, PPDMIBASE *ppBase)); +/** Pointer to a FNPDMDEVQUERYINTERFACE() function. */ +typedef FNPDMDEVQUERYINTERFACE *PFNPDMDEVQUERYINTERFACE; + +/** + * Init complete notification (after ring-0 & RC init since 5.1). + * + * This can be done to do communication with other devices and other + * initialization which requires everything to be in place. + * + * @returns VBOX status code. + * @param pDevIns The device instance. + * + * @remarks Caller enters the device critical section. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDEVINITCOMPLETE,(PPDMDEVINS pDevIns)); +/** Pointer to a FNPDMDEVINITCOMPLETE() function. */ +typedef FNPDMDEVINITCOMPLETE *PFNPDMDEVINITCOMPLETE; + + +/** + * The context of a pfnMemSetup call. + */ +typedef enum PDMDEVMEMSETUPCTX +{ + /** Invalid zero value. */ + PDMDEVMEMSETUPCTX_INVALID = 0, + /** After construction. */ + PDMDEVMEMSETUPCTX_AFTER_CONSTRUCTION, + /** After reset. */ + PDMDEVMEMSETUPCTX_AFTER_RESET, + /** Type size hack. */ + PDMDEVMEMSETUPCTX_32BIT_HACK = 0x7fffffff +} PDMDEVMEMSETUPCTX; + + +/** + * PDM Device Registration Structure. + * + * This structure is used when registering a device from VBoxInitDevices() in HC + * Ring-3. PDM will continue use till the VM is terminated. + * + * @note The first part is the same in every context. + */ +typedef struct PDMDEVREGR3 +{ + /** Structure version. PDM_DEVREGR3_VERSION defines the current version. */ + uint32_t u32Version; + /** Reserved, must be zero. */ + uint32_t uReserved0; + /** Device name, must match the ring-3 one. */ + char szName[32]; + /** Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */ + uint32_t fFlags; + /** Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */ + uint32_t fClass; + /** Maximum number of instances (per VM). */ + uint32_t cMaxInstances; + /** The shared data structure version number. */ + uint32_t uSharedVersion; + /** Size of the instance data. */ + uint32_t cbInstanceShared; + /** Size of the ring-0 instance data. */ + uint32_t cbInstanceCC; + /** Size of the raw-mode instance data. */ + uint32_t cbInstanceRC; + /** Max number of PCI devices. */ + uint16_t cMaxPciDevices; + /** Max number of MSI-X vectors in any of the PCI devices. */ + uint16_t cMaxMsixVectors; + /** The description of the device. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** Name of the raw-mode context module (no path). + * Only evalutated if PDM_DEVREG_FLAGS_RC is set. */ + const char *pszRCMod; + /** Name of the ring-0 module (no path). + * Only evalutated if PDM_DEVREG_FLAGS_R0 is set. */ + const char *pszR0Mod; + + /** Construct instance - required. */ + PFNPDMDEVCONSTRUCT pfnConstruct; + /** Destruct instance - optional. + * Critical section NOT entered (will be destroyed). */ + PFNPDMDEVDESTRUCT pfnDestruct; + /** Relocation command - optional. + * Critical section NOT entered. */ + PFNPDMDEVRELOCATE pfnRelocate; + /** + * Memory setup callback. + * + * @param pDevIns The device instance data. + * @param enmCtx Indicates the context of the call. + * @remarks The critical section is entered prior to calling this method. + */ + DECLR3CALLBACKMEMBER(void, pfnMemSetup, (PPDMDEVINS pDevIns, PDMDEVMEMSETUPCTX enmCtx)); + /** Power on notification - optional. + * Critical section is entered. */ + PFNPDMDEVPOWERON pfnPowerOn; + /** Reset notification - optional. + * Critical section is entered. */ + PFNPDMDEVRESET pfnReset; + /** Suspend notification - optional. + * Critical section is entered. */ + PFNPDMDEVSUSPEND pfnSuspend; + /** Resume notification - optional. + * Critical section is entered. */ + PFNPDMDEVRESUME pfnResume; + /** Attach command - optional. + * Critical section is entered. */ + PFNPDMDEVATTACH pfnAttach; + /** Detach notification - optional. + * Critical section is entered. */ + PFNPDMDEVDETACH pfnDetach; + /** Query a LUN base interface - optional. + * Critical section is NOT entered. */ + PFNPDMDEVQUERYINTERFACE pfnQueryInterface; + /** Init complete notification - optional. + * Critical section is entered. */ + PFNPDMDEVINITCOMPLETE pfnInitComplete; + /** Power off notification - optional. + * Critical section is entered. */ + PFNPDMDEVPOWEROFF pfnPowerOff; + /** Software system reset notification - optional. + * Critical section is entered. */ + PFNPDMDEVSOFTRESET pfnSoftReset; + + /** @name Reserved for future extensions, must be zero. + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnReserved0, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved1, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved2, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved3, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved4, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved5, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved6, (PPDMDEVINS pDevIns)); + DECLR3CALLBACKMEMBER(int, pfnReserved7, (PPDMDEVINS pDevIns)); + /** @} */ + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} PDMDEVREGR3; +/** Pointer to a PDM Device Structure. */ +typedef PDMDEVREGR3 *PPDMDEVREGR3; +/** Const pointer to a PDM Device Structure. */ +typedef PDMDEVREGR3 const *PCPDMDEVREGR3; +/** Current DEVREGR3 version number. */ +#define PDM_DEVREGR3_VERSION PDM_VERSION_MAKE(0xffff, 4, 0) + + +/** PDM Device Flags. + * @{ */ +/** This flag is used to indicate that the device has a R0 component. */ +#define PDM_DEVREG_FLAGS_R0 UINT32_C(0x00000001) +/** Requires the ring-0 component, ignore configuration values. */ +#define PDM_DEVREG_FLAGS_REQUIRE_R0 UINT32_C(0x00000002) +/** Requires the ring-0 component, ignore configuration values. */ +#define PDM_DEVREG_FLAGS_OPT_IN_R0 UINT32_C(0x00000004) + +/** This flag is used to indicate that the device has a RC component. */ +#define PDM_DEVREG_FLAGS_RC UINT32_C(0x00000010) +/** Requires the raw-mode component, ignore configuration values. */ +#define PDM_DEVREG_FLAGS_REQUIRE_RC UINT32_C(0x00000020) +/** Requires the raw-mode component, ignore configuration values. */ +#define PDM_DEVREG_FLAGS_OPT_IN_RC UINT32_C(0x00000040) + +/** Convenience: PDM_DEVREG_FLAGS_R0 + PDM_DEVREG_FLAGS_RC */ +#define PDM_DEVREG_FLAGS_RZ (PDM_DEVREG_FLAGS_R0 | PDM_DEVREG_FLAGS_RC) + +/** @def PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT + * The bit count for the current host. + * @note Superfluous, but still around for hysterical raisins. */ +#if HC_ARCH_BITS == 32 +# define PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT UINT32_C(0x00000100) +#elif HC_ARCH_BITS == 64 +# define PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT UINT32_C(0x00000200) +#else +# error Unsupported HC_ARCH_BITS value. +#endif +/** The host bit count mask. */ +#define PDM_DEVREG_FLAGS_HOST_BITS_MASK UINT32_C(0x00000300) + +/** The device support only 32-bit guests. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_32 UINT32_C(0x00001000) +/** The device support only 64-bit guests. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_64 UINT32_C(0x00002000) +/** The device support both 32-bit & 64-bit guests. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_32_64 UINT32_C(0x00003000) +/** @def PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT + * The guest bit count for the current compilation. */ +#if GC_ARCH_BITS == 32 +# define PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT PDM_DEVREG_FLAGS_GUEST_BITS_32 +#elif GC_ARCH_BITS == 64 +# define PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT PDM_DEVREG_FLAGS_GUEST_BITS_32_64 +#else +# error Unsupported GC_ARCH_BITS value. +#endif +/** The guest bit count mask. */ +#define PDM_DEVREG_FLAGS_GUEST_BITS_MASK UINT32_C(0x00003000) + +/** A convenience. */ +#define PDM_DEVREG_FLAGS_DEFAULT_BITS (PDM_DEVREG_FLAGS_GUEST_BITS_DEFAULT | PDM_DEVREG_FLAGS_HOST_BITS_DEFAULT) + +/** Indicates that the device needs to be notified before the drivers when suspending. */ +#define PDM_DEVREG_FLAGS_FIRST_SUSPEND_NOTIFICATION UINT32_C(0x00010000) +/** Indicates that the device needs to be notified before the drivers when powering off. */ +#define PDM_DEVREG_FLAGS_FIRST_POWEROFF_NOTIFICATION UINT32_C(0x00020000) +/** Indicates that the device needs to be notified before the drivers when resetting. */ +#define PDM_DEVREG_FLAGS_FIRST_RESET_NOTIFICATION UINT32_C(0x00040000) + +/** This flag is used to indicate that the device has been converted to the + * new device style. */ +#define PDM_DEVREG_FLAGS_NEW_STYLE UINT32_C(0x80000000) + +/** @} */ + + +/** PDM Device Classes. + * The order is important, lower bit earlier instantiation. + * @{ */ +/** Architecture device. */ +#define PDM_DEVREG_CLASS_ARCH RT_BIT(0) +/** Architecture BIOS device. */ +#define PDM_DEVREG_CLASS_ARCH_BIOS RT_BIT(1) +/** PCI bus brigde. */ +#define PDM_DEVREG_CLASS_BUS_PCI RT_BIT(2) +/** PCI built-in device (e.g. PCI root complex devices). */ +#define PDM_DEVREG_CLASS_PCI_BUILTIN RT_BIT(3) +/** Input device (mouse, keyboard, joystick, HID, ...). */ +#define PDM_DEVREG_CLASS_INPUT RT_BIT(4) +/** Interrupt controller (PIC). */ +#define PDM_DEVREG_CLASS_PIC RT_BIT(5) +/** Interval controoler (PIT). */ +#define PDM_DEVREG_CLASS_PIT RT_BIT(6) +/** RTC/CMOS. */ +#define PDM_DEVREG_CLASS_RTC RT_BIT(7) +/** DMA controller. */ +#define PDM_DEVREG_CLASS_DMA RT_BIT(8) +/** VMM Device. */ +#define PDM_DEVREG_CLASS_VMM_DEV RT_BIT(9) +/** Graphics device, like VGA. */ +#define PDM_DEVREG_CLASS_GRAPHICS RT_BIT(10) +/** Storage controller device. */ +#define PDM_DEVREG_CLASS_STORAGE RT_BIT(11) +/** Network interface controller. */ +#define PDM_DEVREG_CLASS_NETWORK RT_BIT(12) +/** Audio. */ +#define PDM_DEVREG_CLASS_AUDIO RT_BIT(13) +/** USB HIC. */ +#define PDM_DEVREG_CLASS_BUS_USB RT_BIT(14) +/** ACPI. */ +#define PDM_DEVREG_CLASS_ACPI RT_BIT(15) +/** Serial controller device. */ +#define PDM_DEVREG_CLASS_SERIAL RT_BIT(16) +/** Parallel controller device */ +#define PDM_DEVREG_CLASS_PARALLEL RT_BIT(17) +/** Host PCI pass-through device */ +#define PDM_DEVREG_CLASS_HOST_DEV RT_BIT(18) +/** Misc devices (always last). */ +#define PDM_DEVREG_CLASS_MISC RT_BIT(31) +/** @} */ + + +/** + * PDM Device Registration Structure, ring-0. + * + * This structure is used when registering a device from VBoxInitDevices() in HC + * Ring-0. PDM will continue use till the VM is terminated. + */ +typedef struct PDMDEVREGR0 +{ + /** Structure version. PDM_DEVREGR0_VERSION defines the current version. */ + uint32_t u32Version; + /** Reserved, must be zero. */ + uint32_t uReserved0; + /** Device name, must match the ring-3 one. */ + char szName[32]; + /** Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */ + uint32_t fFlags; + /** Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */ + uint32_t fClass; + /** Maximum number of instances (per VM). */ + uint32_t cMaxInstances; + /** The shared data structure version number. */ + uint32_t uSharedVersion; + /** Size of the instance data. */ + uint32_t cbInstanceShared; + /** Size of the ring-0 instance data. */ + uint32_t cbInstanceCC; + /** Size of the raw-mode instance data. */ + uint32_t cbInstanceRC; + /** Max number of PCI devices. */ + uint16_t cMaxPciDevices; + /** Max number of MSI-X vectors in any of the PCI devices. */ + uint16_t cMaxMsixVectors; + /** The description of the device. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** + * Early construction callback (optional). + * + * This is called right after the device instance structure has been allocated + * and before the ring-3 constructor gets called. + * + * @returns VBox status code. + * @param pDevIns The device instance data. + * @note The destructure is always called, regardless of the return status. + */ + DECLR0CALLBACKMEMBER(int, pfnEarlyConstruct, (PPDMDEVINS pDevIns)); + + /** + * Regular construction callback (optional). + * + * This is called after (or during) the ring-3 constructor. + * + * @returns VBox status code. + * @param pDevIns The device instance data. + * @note The destructure is always called, regardless of the return status. + */ + DECLR0CALLBACKMEMBER(int, pfnConstruct, (PPDMDEVINS pDevIns)); + + /** + * Destructor (optional). + * + * This is called after the ring-3 destruction. This is not called if ring-3 + * fails to trigger it (e.g. process is killed or crashes). + * + * @param pDevIns The device instance data. + */ + DECLR0CALLBACKMEMBER(void, pfnDestruct, (PPDMDEVINS pDevIns)); + + /** + * Final destructor (optional). + * + * This is called right before the memory is freed, which happens when the + * VM/GVM object is destroyed. This is always called. + * + * @param pDevIns The device instance data. + */ + DECLR0CALLBACKMEMBER(void, pfnFinalDestruct, (PPDMDEVINS pDevIns)); + + /** + * Generic request handler (optional). + * + * @param pDevIns The device instance data. + * @param uReq Device specific request. + * @param uArg Request argument. + */ + DECLR0CALLBACKMEMBER(int, pfnRequest, (PPDMDEVINS pDevIns, uint32_t uReq, uint64_t uArg)); + + /** @name Reserved for future extensions, must be zero. + * @{ */ + DECLR0CALLBACKMEMBER(int, pfnReserved0, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved1, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved2, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved3, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved4, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved5, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved6, (PPDMDEVINS pDevIns)); + DECLR0CALLBACKMEMBER(int, pfnReserved7, (PPDMDEVINS pDevIns)); + /** @} */ + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} PDMDEVREGR0; +/** Pointer to a ring-0 PDM device registration structure. */ +typedef PDMDEVREGR0 *PPDMDEVREGR0; +/** Pointer to a const ring-0 PDM device registration structure. */ +typedef PDMDEVREGR0 const *PCPDMDEVREGR0; +/** Current DEVREGR0 version number. */ +#define PDM_DEVREGR0_VERSION PDM_VERSION_MAKE(0xff80, 1, 0) + + +/** + * PDM Device Registration Structure, raw-mode + * + * At the moment, this structure is mostly here to match the other two contexts. + */ +typedef struct PDMDEVREGRC +{ + /** Structure version. PDM_DEVREGRC_VERSION defines the current version. */ + uint32_t u32Version; + /** Reserved, must be zero. */ + uint32_t uReserved0; + /** Device name, must match the ring-3 one. */ + char szName[32]; + /** Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */ + uint32_t fFlags; + /** Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */ + uint32_t fClass; + /** Maximum number of instances (per VM). */ + uint32_t cMaxInstances; + /** The shared data structure version number. */ + uint32_t uSharedVersion; + /** Size of the instance data. */ + uint32_t cbInstanceShared; + /** Size of the ring-0 instance data. */ + uint32_t cbInstanceCC; + /** Size of the raw-mode instance data. */ + uint32_t cbInstanceRC; + /** Max number of PCI devices. */ + uint16_t cMaxPciDevices; + /** Max number of MSI-X vectors in any of the PCI devices. */ + uint16_t cMaxMsixVectors; + /** The description of the device. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** + * Constructor callback. + * + * This is called much later than both the ring-0 and ring-3 constructors, since + * raw-mode v2 require a working VMM to run actual code. + * + * @returns VBox status code. + * @param pDevIns The device instance data. + * @note The destructure is always called, regardless of the return status. + */ + DECLRGCALLBACKMEMBER(int, pfnConstruct, (PPDMDEVINS pDevIns)); + + /** @name Reserved for future extensions, must be zero. + * @{ */ + DECLRCCALLBACKMEMBER(int, pfnReserved0, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved1, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved2, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved3, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved4, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved5, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved6, (PPDMDEVINS pDevIns)); + DECLRCCALLBACKMEMBER(int, pfnReserved7, (PPDMDEVINS pDevIns)); + /** @} */ + + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} PDMDEVREGRC; +/** Pointer to a raw-mode PDM device registration structure. */ +typedef PDMDEVREGRC *PPDMDEVREGRC; +/** Pointer to a const raw-mode PDM device registration structure. */ +typedef PDMDEVREGRC const *PCPDMDEVREGRC; +/** Current DEVREGRC version number. */ +#define PDM_DEVREGRC_VERSION PDM_VERSION_MAKE(0xff81, 1, 0) + + + +/** @def PDM_DEVREG_VERSION + * Current DEVREG version number. */ +/** @typedef PDMDEVREGR3 + * A current context PDM device registration structure. */ +/** @typedef PPDMDEVREGR3 + * Pointer to a current context PDM device registration structure. */ +/** @typedef PCPDMDEVREGR3 + * Pointer to a const current context PDM device registration structure. */ +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +# define PDM_DEVREG_VERSION PDM_DEVREGR3_VERSION +typedef PDMDEVREGR3 PDMDEVREG; +typedef PPDMDEVREGR3 PPDMDEVREG; +typedef PCPDMDEVREGR3 PCPDMDEVREG; +#elif defined(IN_RING0) +# define PDM_DEVREG_VERSION PDM_DEVREGR0_VERSION +typedef PDMDEVREGR0 PDMDEVREG; +typedef PPDMDEVREGR0 PPDMDEVREG; +typedef PCPDMDEVREGR0 PCPDMDEVREG; +#elif defined(IN_RC) +# define PDM_DEVREG_VERSION PDM_DEVREGRC_VERSION +typedef PDMDEVREGRC PDMDEVREG; +typedef PPDMDEVREGRC PPDMDEVREG; +typedef PCPDMDEVREGRC PCPDMDEVREG; +#else +# error "Not IN_RING3, IN_RING0 or IN_RC" +#endif + + +/** + * Device registrations for ring-0 modules. + * + * This structure is used directly and must therefore reside in persistent + * memory (i.e. the data section). + */ +typedef struct PDMDEVMODREGR0 +{ + /** The structure version (PDM_DEVMODREGR0_VERSION). */ + uint32_t u32Version; + /** Number of devices in the array papDevRegs points to. */ + uint32_t cDevRegs; + /** Pointer to device registration structures. */ + PCPDMDEVREGR0 *papDevRegs; + /** The ring-0 module handle - PDM internal, fingers off. */ + void *hMod; + /** List entry - PDM internal, fingers off. */ + RTLISTNODE ListEntry; +} PDMDEVMODREGR0; +/** Pointer to device registriations for a ring-0 module. */ +typedef PDMDEVMODREGR0 *PPDMDEVMODREGR0; +/** Current PDMDEVMODREGR0 version number. */ +#define PDM_DEVMODREGR0_VERSION PDM_VERSION_MAKE(0xff85, 1, 0) + + +/** @name IRQ Level for use with the *SetIrq APIs. + * @{ + */ +/** Assert the IRQ (can assume value 1). */ +#define PDM_IRQ_LEVEL_HIGH RT_BIT(0) +/** Deassert the IRQ (can assume value 0). */ +#define PDM_IRQ_LEVEL_LOW 0 +/** flip-flop - deassert and then assert the IRQ again immediately (PIC) / + * automatically deasserts it after delivery to the APIC (IOAPIC). + * @note Only suitable for edge trigger interrupts. */ +#define PDM_IRQ_LEVEL_FLIP_FLOP (RT_BIT(1) | PDM_IRQ_LEVEL_HIGH) +/** @} */ + +/** + * Registration record for MSI/MSI-X emulation. + */ +typedef struct PDMMSIREG +{ + /** Number of MSI interrupt vectors, 0 if MSI not supported */ + uint16_t cMsiVectors; + /** Offset of MSI capability */ + uint8_t iMsiCapOffset; + /** Offset of next capability to MSI */ + uint8_t iMsiNextOffset; + /** If we support 64-bit MSI addressing */ + bool fMsi64bit; + /** If we do not support per-vector masking */ + bool fMsiNoMasking; + + /** Number of MSI-X interrupt vectors, 0 if MSI-X not supported */ + uint16_t cMsixVectors; + /** Offset of MSI-X capability */ + uint8_t iMsixCapOffset; + /** Offset of next capability to MSI-X */ + uint8_t iMsixNextOffset; + /** Value of PCI BAR (base addresss register) assigned by device for MSI-X page access */ + uint8_t iMsixBar; +} PDMMSIREG; +typedef PDMMSIREG *PPDMMSIREG; + +/** + * PCI Bus registration structure. + * All the callbacks, except the PCIBIOS hack, are working on PCI devices. + */ +typedef struct PDMPCIBUSREGR3 +{ + /** Structure version number. PDM_PCIBUSREGR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Registers the device with the default PCI bus. + * + * @returns VBox status code. + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param fFlags Reserved for future use, PDMPCIDEVREG_F_MBZ. + * @param uPciDevNo PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, or a specific + * device number (0-31). + * @param uPciFunNo PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, or a specific + * function number (0-7). + * @param pszName Device name (static but not unique). + * + * @remarks Caller enters the PDM critical section. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags, + uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)); + + /** + * Initialize MSI or MSI-X emulation support in a PCI device. + * + * This cannot handle all corner cases of the MSI/MSI-X spec, but for the + * vast majority of device emulation it covers everything necessary. It's + * fully automatic, taking care of all BAR and config space requirements, + * and interrupt delivery is done using PDMDevHlpPCISetIrq and friends. + * When MSI/MSI-X is enabled then the iIrq parameter is redefined to take + * the vector number (otherwise it has the usual INTA-D meaning for PCI). + * + * A device not using this can still offer MSI/MSI-X. In this case it's + * completely up to the device (in the MSI-X case) to create/register the + * necessary MMIO BAR, handle all config space/BAR updating and take care + * of delivering the interrupts appropriately. + * + * @returns VBox status code. + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param pMsiReg MSI emulation registration structure + * @remarks Caller enters the PDM critical section. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterMsiR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg)); + + /** + * Registers a I/O region (memory mapped or I/O ports) for a PCI device. + * + * @returns VBox status code. + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param enmType PCI_ADDRESS_SPACE_MEM, PCI_ADDRESS_SPACE_IO or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally with + * PCI_ADDRESS_SPACE_BAR64 or'ed in. + * @param fFlags PDMPCIDEV_IORGN_F_XXX. + * @param hHandle An I/O port, MMIO or MMIO2 handle according to + * @a fFlags, UINT64_MAX if no handle is passed + * (old style). + * @param pfnMapUnmap Callback for doing the mapping. Optional if a handle + * is given. + * @remarks Caller enters the PDM critical section. + */ + DECLR3CALLBACKMEMBER(int, pfnIORegionRegisterR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, uint32_t fFlags, + uint64_t hHandle, PFNPCIIOREGIONMAP pfnMapUnmap)); + + /** + * Register PCI configuration space read/write intercept callbacks. + * + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param pfnRead Pointer to the user defined PCI config read function. + * @param pfnWrite Pointer to the user defined PCI config write function. + * to call default PCI config write function. Can be NULL. + * @remarks Caller enters the PDM critical section. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(void, pfnInterceptConfigAccesses,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + PFNPCICONFIGREAD pfnRead, PFNPCICONFIGWRITE pfnWrite)); + + /** + * Perform a PCI configuration space write, bypassing interception. + * + * This is for devices that make use of PDMDevHlpPCIInterceptConfigAccesses(). + * + * @returns Strict VBox status code (mainly DBGFSTOP). + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device which config space is being read. + * @param uAddress The config space address. + * @param cb The size of the read: 1, 2 or 4 bytes. + * @param u32Value The value to write. + * @note The caller (PDM) does not enter the PDM critsect, but it is possible + * that the (root) bus will have done that already. + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnConfigWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t u32Value)); + + /** + * Perform a PCI configuration space read, bypassing interception. + * + * This is for devices that make use of PDMDevHlpPCIInterceptConfigAccesses(). + * + * @returns Strict VBox status code (mainly DBGFSTOP). + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device which config space is being read. + * @param uAddress The config space address. + * @param cb The size of the read: 1, 2 or 4 bytes. + * @param pu32Value Where to return the value. + * @note The caller (PDM) does not enter the PDM critsect, but it is possible + * that the (root) bus will have done that already. + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnConfigRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t *pu32Value)); + + /** + * Set the IRQ for a PCI device. + * + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @remarks Caller enters the PDM critical section. + */ + DECLR3CALLBACKMEMBER(void, pfnSetIrqR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** Marks the end of the structure with PDM_PCIBUSREGR3_VERSION. */ + uint32_t u32EndVersion; +} PDMPCIBUSREGR3; +/** Pointer to a PCI bus registration structure. */ +typedef PDMPCIBUSREGR3 *PPDMPCIBUSREGR3; +/** Current PDMPCIBUSREGR3 version number. */ +#define PDM_PCIBUSREGR3_VERSION PDM_VERSION_MAKE(0xff86, 2, 0) + +/** + * PCI Bus registration structure for ring-0. + */ +typedef struct PDMPCIBUSREGR0 +{ + /** Structure version number. PDM_PCIBUSREGR0_VERSION defines the current version. */ + uint32_t u32Version; + /** The PCI bus number (from ring-3 registration). */ + uint32_t iBus; + /** + * Set the IRQ for a PCI device. + * + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @remarks Caller enters the PDM critical section. + */ + DECLR0CALLBACKMEMBER(void, pfnSetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)); + /** Marks the end of the structure with PDM_PCIBUSREGR0_VERSION. */ + uint32_t u32EndVersion; +} PDMPCIBUSREGR0; +/** Pointer to a PCI bus ring-0 registration structure. */ +typedef PDMPCIBUSREGR0 *PPDMPCIBUSREGR0; +/** Current PDMPCIBUSREGR0 version number. */ +#define PDM_PCIBUSREGR0_VERSION PDM_VERSION_MAKE(0xff87, 1, 0) + +/** + * PCI Bus registration structure for raw-mode. + */ +typedef struct PDMPCIBUSREGRC +{ + /** Structure version number. PDM_PCIBUSREGRC_VERSION defines the current version. */ + uint32_t u32Version; + /** The PCI bus number (from ring-3 registration). */ + uint32_t iBus; + /** + * Set the IRQ for a PCI device. + * + * @param pDevIns Device instance of the PCI Bus. + * @param pPciDev The PCI device structure. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @remarks Caller enters the PDM critical section. + */ + DECLRCCALLBACKMEMBER(void, pfnSetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel, uint32_t uTagSrc)); + /** Marks the end of the structure with PDM_PCIBUSREGRC_VERSION. */ + uint32_t u32EndVersion; +} PDMPCIBUSREGRC; +/** Pointer to a PCI bus raw-mode registration structure. */ +typedef PDMPCIBUSREGRC *PPDMPCIBUSREGRC; +/** Current PDMPCIBUSREGRC version number. */ +#define PDM_PCIBUSREGRC_VERSION PDM_VERSION_MAKE(0xff88, 1, 0) + +/** PCI bus registration structure for the current context. */ +typedef CTX_SUFF(PDMPCIBUSREG) PDMPCIBUSREGCC; +/** Pointer to a PCI bus registration structure for the current context. */ +typedef CTX_SUFF(PPDMPCIBUSREG) PPDMPCIBUSREGCC; +/** PCI bus registration structure version for the current context. */ +#define PDM_PCIBUSREGCC_VERSION CTX_MID(PDM_PCIBUSREG,_VERSION) + + +/** + * PCI Bus RC helpers. + */ +typedef struct PDMPCIHLPRC +{ + /** Structure version. PDM_PCIHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set an ISA IRQ. + * + * @param pDevIns PCI device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLRCCALLBACKMEMBER(void, pfnIsaSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Set an I/O-APIC IRQ. + * + * @param pDevIns PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * IRQ. Pass NIL_PCIBDF when it's not a PCI device or + * interrupt. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLRCCALLBACKMEMBER(void, pfnIoApicSetIrq,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send an MSI. + * + * @param pDevIns PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * MSI. Cannot be NIL_PCIBDF. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLRCCALLBACKMEMBER(void, pfnIoApicSendMsi,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, PCMSIMSG pMsi, uint32_t uTagSrc)); + + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PCI device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLRCCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLRCCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Gets a bus by it's PDM ordinal (typically the parent bus). + * + * @returns Pointer to the device instance of the bus. + * @param pDevIns The PCI bus device instance. + * @param idxPdmBus The PDM ordinal value of the bus to get. + */ + DECLRCCALLBACKMEMBER(PPDMDEVINS, pfnGetBusByNo,(PPDMDEVINS pDevIns, uint32_t idxPdmBus)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIHLPRC; +/** Pointer to PCI helpers. */ +typedef RCPTRTYPE(PDMPCIHLPRC *) PPDMPCIHLPRC; +/** Pointer to const PCI helpers. */ +typedef RCPTRTYPE(const PDMPCIHLPRC *) PCPDMPCIHLPRC; + +/** Current PDMPCIHLPRC version number. */ +#define PDM_PCIHLPRC_VERSION PDM_VERSION_MAKE(0xfffd, 4, 0) + + +/** + * PCI Bus R0 helpers. + */ +typedef struct PDMPCIHLPR0 +{ + /** Structure version. PDM_PCIHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set an ISA IRQ. + * + * @param pDevIns PCI device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLR0CALLBACKMEMBER(void, pfnIsaSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Set an I/O-APIC IRQ. + * + * @param pDevIns PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * IRQ. Pass NIL_PCIBDF when it's not a PCI device or + * interrupt. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLR0CALLBACKMEMBER(void, pfnIoApicSetIrq,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send an MSI. + * + * @param pDevIns PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * MSI. Cannot be NIL_PCIBDF. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + * @thread EMT only. + */ + DECLR0CALLBACKMEMBER(void, pfnIoApicSendMsi,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PCI device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLR0CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR0CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Gets a bus by it's PDM ordinal (typically the parent bus). + * + * @returns Pointer to the device instance of the bus. + * @param pDevIns The PCI bus device instance. + * @param idxPdmBus The PDM ordinal value of the bus to get. + */ + DECLR0CALLBACKMEMBER(PPDMDEVINS, pfnGetBusByNo,(PPDMDEVINS pDevIns, uint32_t idxPdmBus)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIHLPR0; +/** Pointer to PCI helpers. */ +typedef R0PTRTYPE(PDMPCIHLPR0 *) PPDMPCIHLPR0; +/** Pointer to const PCI helpers. */ +typedef R0PTRTYPE(const PDMPCIHLPR0 *) PCPDMPCIHLPR0; + +/** Current PDMPCIHLPR0 version number. */ +#define PDM_PCIHLPR0_VERSION PDM_VERSION_MAKE(0xfffc, 6, 0) + +/** + * PCI device helpers. + */ +typedef struct PDMPCIHLPR3 +{ + /** Structure version. PDM_PCIHLPR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set an ISA IRQ. + * + * @param pDevIns The PCI device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnIsaSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Set an I/O-APIC IRQ. + * + * @param pDevIns The PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * IRQ. Pass NIL_PCIBDF when it's not a PCI device or + * interrupt. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnIoApicSetIrq,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send an MSI. + * + * @param pDevIns PCI device instance. + * @param uBusDevFn The bus:device:function of the device initiating the + * MSI. Cannot be NIL_PCIBDF. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnIoApicSendMsi,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns Fatal error on failure. + * @param pDevIns The PCI device instance. + * @param rc Dummy for making the interface identical to the RC and R0 versions. + * + * @sa PDMCritSectEnter + */ + DECLR3CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR3CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Gets a bus by it's PDM ordinal (typically the parent bus). + * + * @returns Pointer to the device instance of the bus. + * @param pDevIns The PCI bus device instance. + * @param idxPdmBus The PDM ordinal value of the bus to get. + */ + DECLR3CALLBACKMEMBER(PPDMDEVINS, pfnGetBusByNo,(PPDMDEVINS pDevIns, uint32_t idxPdmBus)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIHLPR3; +/** Pointer to PCI helpers. */ +typedef R3PTRTYPE(PDMPCIHLPR3 *) PPDMPCIHLPR3; +/** Pointer to const PCI helpers. */ +typedef R3PTRTYPE(const PDMPCIHLPR3 *) PCPDMPCIHLPR3; + +/** Current PDMPCIHLPR3 version number. */ +#define PDM_PCIHLPR3_VERSION PDM_VERSION_MAKE(0xfffb, 5, 0) + + +/** @name PDMIOMMU_MEM_F_XXX - IOMMU memory access transaction flags. + * These flags are used for memory access transactions via the IOMMU interface. + * @{ */ +/** Memory read. */ +#define PDMIOMMU_MEM_F_READ RT_BIT_32(0) +/** Memory write. */ +#define PDMIOMMU_MEM_F_WRITE RT_BIT_32(1) +/** Valid flag mask. */ +#define PDMIOMMU_MEM_F_VALID_MASK (PDMIOMMU_MEM_F_READ | PDMIOMMU_MEM_F_WRITE) +/** @} */ + +/** + * IOMMU registration structure for ring-0. + */ +typedef struct PDMIOMMUREGR0 +{ + /** Structure version number. PDM_IOMMUREG_VERSION defines the current + * version. */ + uint32_t u32Version; + /** Index into the PDM IOMMU array (PDM::aIommus) from ring-3. */ + uint32_t idxIommu; + + /** + * Translates the physical address for a memory transaction through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param uIova The I/O virtual address being accessed. + * @param cbIova The size of the access. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param pGCPhysSpa Where to store the translated system physical address. + * @param pcbContiguous Where to store the number of contiguous bytes translated + * and permission-checked. + * + * @thread Any. + */ + DECLR0CALLBACKMEMBER(int, pfnMemAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, uint64_t uIova, size_t cbIova, + uint32_t fFlags, PRTGCPHYS pGCPhysSpa, size_t *pcbContiguous)); + + /** + * Translates in bulk physical page addresses for memory transactions through the + * IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param cIovas The number of I/O virtual addresses being accessed. + * @param pauIovas The I/O virtual addresses being accessed. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param paGCPhysSpa Where to store the translated system physical page + * addresses. + * + * @thread Any. + */ + DECLR0CALLBACKMEMBER(int, pfnMemBulkAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, size_t cIovas, uint64_t const *pauIovas, + uint32_t fFlags, PRTGCPHYS paGCPhysSpa)); + + /** + * Performs an interrupt remap request through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param pMsiIn The source MSI. + * @param pMsiOut Where to store the remapped MSI. + * + * @thread Any. + */ + DECLR0CALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUREGR0; +/** Pointer to a IOMMU registration structure. */ +typedef PDMIOMMUREGR0 *PPDMIOMMUREGR0; + +/** Current PDMIOMMUREG version number. */ +#define PDM_IOMMUREGR0_VERSION PDM_VERSION_MAKE(0xff10, 3, 0) + + +/** + * IOMMU registration structure for raw-mode. + */ +typedef struct PDMIOMMUREGRC +{ + /** Structure version number. PDM_IOMMUREG_VERSION defines the current + * version. */ + uint32_t u32Version; + /** Index into the PDM IOMMU array (PDM::aIommus) from ring-3. */ + uint32_t idxIommu; + + /** + * Translates the physical address for a memory transaction through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param uIova The I/O virtual address being accessed. + * @param cbIova The size of the access. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param pGCPhysSpa Where to store the translated system physical address. + * @param pcbContiguous Where to store the number of contiguous bytes translated + * and permission-checked. + * + * @thread Any. + */ + DECLRCCALLBACKMEMBER(int, pfnMemAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, uint64_t uIova, size_t cbIova, + uint32_t fFlags, PRTGCPHYS pGCPhysSpa, size_t *pcbContiguous)); + + /** + * Translates in bulk physical page addresses for memory transactions through the + * IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param cIovas The number of I/O virtual addresses being accessed. + * @param pauIovas The I/O virtual addresses being accessed. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param paGCPhysSpa Where to store the translated system physical page + * addresses. + * + * @thread Any. + */ + DECLRCCALLBACKMEMBER(int, pfnMemBulkAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, size_t cIovas, uint64_t const *pauIovas, + uint32_t fFlags, PRTGCPHYS paGCPhysSpa)); + + /** + * Performs an interrupt remap request through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param pMsiIn The source MSI. + * @param pMsiOut Where to store the remapped MSI. + * + * @thread Any. + */ + DECLRCCALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUREGRC; +/** Pointer to a IOMMU registration structure. */ +typedef PDMIOMMUREGRC *PPDMIOMMUREGRC; + +/** Current PDMIOMMUREG version number. */ +#define PDM_IOMMUREGRC_VERSION PDM_VERSION_MAKE(0xff11, 3, 0) + + +/** + * IOMMU registration structure for ring-3. + */ +typedef struct PDMIOMMUREGR3 +{ + /** Structure version number. PDM_IOMMUREG_VERSION defines the current + * version. */ + uint32_t u32Version; + /** Padding. */ + uint32_t uPadding0; + + /** + * Translates the physical address for a memory transaction through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param uIova The I/O virtual address being accessed. + * @param cbIova The size of the access. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param pGCPhysSpa Where to store the translated system physical address. + * @param pcbContiguous Where to store the number of contiguous bytes translated + * and permission-checked. + * + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnMemAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, uint64_t uIova, size_t cbIova, + uint32_t fFlags, PRTGCPHYS pGCPhysSpa, size_t *pcbContiguous)); + + /** + * Translates in bulk physical page addresses for memory transactions through the + * IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param cIovas The number of I/O virtual addresses being accessed. + * @param pauIovas The I/O virtual addresses being accessed. + * @param fFlags Access flags, see PDMIOMMU_MEM_F_XXX. + * @param paGCPhysSpa Where to store the translated system physical page + * addresses. + * + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnMemBulkAccess,(PPDMDEVINS pDevIns, uint16_t idDevice, size_t cIovas, uint64_t const *pauIovas, + uint32_t fFlags, PRTGCPHYS paGCPhysSpa)); + + /** + * Performs an interrupt remap request through the IOMMU. + * + * @returns VBox status code. + * @param pDevIns The IOMMU device instance. + * @param idDevice The device identifier (bus, device, function). + * @param pMsiIn The source MSI. + * @param pMsiOut Where to store the remapped MSI. + * + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnMsiRemap,(PPDMDEVINS pDevIns, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUREGR3; +/** Pointer to a IOMMU registration structure. */ +typedef PDMIOMMUREGR3 *PPDMIOMMUREGR3; + +/** Current PDMIOMMUREG version number. */ +#define PDM_IOMMUREGR3_VERSION PDM_VERSION_MAKE(0xff12, 3, 0) + +/** IOMMU registration structure for the current context. */ +typedef CTX_SUFF(PDMIOMMUREG) PDMIOMMUREGCC; +/** Pointer to an IOMMU registration structure for the current context. */ +typedef CTX_SUFF(PPDMIOMMUREG) PPDMIOMMUREGCC; +/** IOMMU registration structure version for the current context. */ +#define PDM_IOMMUREGCC_VERSION CTX_MID(PDM_IOMMUREG,_VERSION) + + +/** + * IOMMU helpers for ring-0. + */ +typedef struct PDMIOMMUHLPR0 +{ + /** Structure version. PDM_IOMMUHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PCI device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLR0CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR0CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Check whether the calling thread owns the PDM lock. + * + * @returns @c true if the PDM lock is owned, @c false otherwise. + * @param pDevIns The PCI device instance. + */ + DECLR0CALLBACKMEMBER(bool, pfnLockIsOwner,(PPDMDEVINS pDevIns)); + + /** + * Send an MSI (when generated by the IOMMU device itself). + * + * @param pDevIns PCI device instance. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR0CALLBACKMEMBER(void, pfnSendMsi,(PPDMDEVINS pDevIns, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUHLPR0; +/** Pointer to IOMMU helpers for ring-0. */ +typedef PDMIOMMUHLPR0 *PPDMIOMMUHLPR0; +/** Pointer to const IOMMU helpers for ring-0. */ +typedef const PDMIOMMUHLPR0 *PCPDMIOMMUHLPR0; + +/** Current PDMIOMMUHLPR0 version number. */ +#define PDM_IOMMUHLPR0_VERSION PDM_VERSION_MAKE(0xff13, 5, 0) + + +/** + * IOMMU helpers for raw-mode. + */ +typedef struct PDMIOMMUHLPRC +{ + /** Structure version. PDM_IOMMUHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PCI device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLRCCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLRCCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Check whether the threads owns the PDM lock. + * + * @returns @c true if the PDM lock is owned, @c false otherwise. + * @param pDevIns The PCI device instance. + */ + DECLRCCALLBACKMEMBER(bool, pfnLockIsOwner,(PPDMDEVINS pDevIns)); + + /** + * Send an MSI (when generated by the IOMMU device itself). + * + * @param pDevIns PCI device instance. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLRCCALLBACKMEMBER(void, pfnSendMsi,(PPDMDEVINS pDevIns, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUHLPRC; +/** Pointer to IOMMU helpers for raw-mode. */ +typedef PDMIOMMUHLPRC *PPDMIOMMUHLPRC; +/** Pointer to const IOMMU helpers for raw-mode. */ +typedef const PDMIOMMUHLPRC *PCPDMIOMMUHLPRC; + +/** Current PDMIOMMUHLPRC version number. */ +#define PDM_IOMMUHLPRC_VERSION PDM_VERSION_MAKE(0xff14, 5, 0) + + +/** + * IOMMU helpers for ring-3. + */ +typedef struct PDMIOMMUHLPR3 +{ + /** Structure version. PDM_IOMMUHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PCI device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLR3CALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PCI device instance. + */ + DECLR3CALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Check whether the threads owns the PDM lock. + * + * @returns @c true if the PDM lock is owned, @c false otherwise. + * @param pDevIns The PCI device instance. + */ + DECLR3CALLBACKMEMBER(bool, pfnLockIsOwner,(PPDMDEVINS pDevIns)); + + /** + * Send an MSI (when generated by the IOMMU device itself). + * + * @param pDevIns PCI device instance. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + */ + DECLR3CALLBACKMEMBER(void, pfnSendMsi,(PPDMDEVINS pDevIns, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOMMUHLPR3; +/** Pointer to IOMMU helpers for raw-mode. */ +typedef PDMIOMMUHLPR3 *PPDMIOMMUHLPR3; +/** Pointer to const IOMMU helpers for raw-mode. */ +typedef const PDMIOMMUHLPR3 *PCPDMIOMMUHLPR3; + +/** Current PDMIOMMUHLPR3 version number. */ +#define PDM_IOMMUHLPR3_VERSION PDM_VERSION_MAKE(0xff15, 5, 0) + + +/** + * Programmable Interrupt Controller registration structure (all contexts). + */ +typedef struct PDMPICREG +{ + /** Structure version number. PDM_PICREG_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set the an IRQ. + * + * @param pDevIns Device instance of the PIC. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * @remarks Caller enters the PDM critical section. + */ + DECLCALLBACKMEMBER(void, pfnSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Get a pending interrupt. + * + * @returns Pending interrupt number. + * @param pDevIns Device instance of the PIC. + * @param puTagSrc Where to return the IRQ tag and source. + * @remarks Caller enters the PDM critical section. + */ + DECLCALLBACKMEMBER(int, pfnGetInterrupt,(PPDMDEVINS pDevIns, uint32_t *puTagSrc)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPICREG; +/** Pointer to a PIC registration structure. */ +typedef PDMPICREG *PPDMPICREG; + +/** Current PDMPICREG version number. */ +#define PDM_PICREG_VERSION PDM_VERSION_MAKE(0xfffa, 3, 0) + +/** + * PIC helpers, same in all contexts. + */ +typedef struct PDMPICHLP +{ + /** Structure version. PDM_PICHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set the interrupt force action flag. + * + * @param pDevIns Device instance of the PIC. + */ + DECLCALLBACKMEMBER(void, pfnSetInterruptFF,(PPDMDEVINS pDevIns)); + + /** + * Clear the interrupt force action flag. + * + * @param pDevIns Device instance of the PIC. + */ + DECLCALLBACKMEMBER(void, pfnClearInterruptFF,(PPDMDEVINS pDevIns)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The PIC device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The PIC device instance. + */ + DECLCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPICHLP; +/** Pointer to PIC helpers. */ +typedef PDMPICHLP *PPDMPICHLP; +/** Pointer to const PIC helpers. */ +typedef const PDMPICHLP *PCPDMPICHLP; + +/** Current PDMPICHLP version number. */ +#define PDM_PICHLP_VERSION PDM_VERSION_MAKE(0xfff9, 3, 0) + + +/** + * Firmware registration structure. + */ +typedef struct PDMFWREG +{ + /** Struct version+magic number (PDM_FWREG_VERSION). */ + uint32_t u32Version; + + /** + * Checks whether this is a hard or soft reset. + * + * The current definition of soft reset is what the PC BIOS does when CMOS[0xF] + * is 5, 9 or 0xA. + * + * @returns true if hard reset, false if soft. + * @param pDevIns Device instance of the firmware. + * @param fFlags PDMRESET_F_XXX passed to the PDMDevHlpVMReset API. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsHardReset,(PPDMDEVINS pDevIns, uint32_t fFlags)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMFWREG; +/** Pointer to a FW registration structure. */ +typedef PDMFWREG *PPDMFWREG; +/** Pointer to a const FW registration structure. */ +typedef PDMFWREG const *PCPDMFWREG; + +/** Current PDMFWREG version number. */ +#define PDM_FWREG_VERSION PDM_VERSION_MAKE(0xffdd, 1, 0) + +/** + * Firmware R3 helpers. + */ +typedef struct PDMFWHLPR3 +{ + /** Structure version. PDM_FWHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMFWHLPR3; + +/** Pointer to FW R3 helpers. */ +typedef R3PTRTYPE(PDMFWHLPR3 *) PPDMFWHLPR3; +/** Pointer to const FW R3 helpers. */ +typedef R3PTRTYPE(const PDMFWHLPR3 *) PCPDMFWHLPR3; + +/** Current PDMFWHLPR3 version number. */ +#define PDM_FWHLPR3_VERSION PDM_VERSION_MAKE(0xffdb, 1, 0) + + +/** + * APIC mode argument for apicR3SetCpuIdFeatureLevel. + * + * Also used in saved-states, CFGM don't change existing values. + */ +typedef enum PDMAPICMODE +{ + /** Invalid 0 entry. */ + PDMAPICMODE_INVALID = 0, + /** No APIC. */ + PDMAPICMODE_NONE, + /** Standard APIC (X86_CPUID_FEATURE_EDX_APIC). */ + PDMAPICMODE_APIC, + /** Intel X2APIC (X86_CPUID_FEATURE_ECX_X2APIC). */ + PDMAPICMODE_X2APIC, + /** The usual 32-bit paranoia. */ + PDMAPICMODE_32BIT_HACK = 0x7fffffff +} PDMAPICMODE; + +/** + * APIC irq argument for pfnSetInterruptFF and pfnClearInterruptFF. + */ +typedef enum PDMAPICIRQ +{ + /** Invalid 0 entry. */ + PDMAPICIRQ_INVALID = 0, + /** Normal hardware interrupt. */ + PDMAPICIRQ_HARDWARE, + /** NMI. */ + PDMAPICIRQ_NMI, + /** SMI. */ + PDMAPICIRQ_SMI, + /** ExtINT (HW interrupt via PIC). */ + PDMAPICIRQ_EXTINT, + /** Interrupt arrived, needs to be updated to the IRR. */ + PDMAPICIRQ_UPDATE_PENDING, + /** The usual 32-bit paranoia. */ + PDMAPICIRQ_32BIT_HACK = 0x7fffffff +} PDMAPICIRQ; + + +/** + * I/O APIC registration structure (all contexts). + */ +typedef struct PDMIOAPICREG +{ + /** Struct version+magic number (PDM_IOAPICREG_VERSION). */ + uint32_t u32Version; + + /** + * Set an IRQ. + * + * @param pDevIns Device instance of the I/O APIC. + * @param uBusDevFn The bus:device:function of the device initiating the + * IRQ. Can be NIL_PCIBDF. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @param uTagSrc The IRQ tag and source (for tracing). + * + * @remarks Caller enters the PDM critical section + * Actually, as per 2018-07-21 this isn't true (bird). + */ + DECLCALLBACKMEMBER(void, pfnSetIrq,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, int iIrq, int iLevel, uint32_t uTagSrc)); + + /** + * Send a MSI. + * + * @param pDevIns Device instance of the I/O APIC. + * @param uBusDevFn The bus:device:function of the device initiating the + * MSI. Cannot be NIL_PCIBDF. + * @param pMsi The MSI to send. + * @param uTagSrc The IRQ tag and source (for tracing). + * + * @remarks Caller enters the PDM critical section + * Actually, as per 2018-07-21 this isn't true (bird). + */ + DECLCALLBACKMEMBER(void, pfnSendMsi,(PPDMDEVINS pDevIns, PCIBDF uBusDevFn, PCMSIMSG pMsi, uint32_t uTagSrc)); + + /** + * Set the EOI for an interrupt vector. + * + * @param pDevIns Device instance of the I/O APIC. + * @param u8Vector The vector. + * + * @remarks Caller enters the PDM critical section + * Actually, as per 2018-07-21 this isn't true (bird). + */ + DECLCALLBACKMEMBER(void, pfnSetEoi,(PPDMDEVINS pDevIns, uint8_t u8Vector)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOAPICREG; +/** Pointer to an APIC registration structure. */ +typedef PDMIOAPICREG *PPDMIOAPICREG; + +/** Current PDMAPICREG version number. */ +#define PDM_IOAPICREG_VERSION PDM_VERSION_MAKE(0xfff2, 8, 0) + + +/** + * IOAPIC helpers, same in all contexts. + */ +typedef struct PDMIOAPICHLP +{ + /** Structure version. PDM_IOAPICHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Private interface between the IOAPIC and APIC. + * + * @returns status code. + * @param pDevIns Device instance of the IOAPIC. + * @param u8Dest See APIC implementation. + * @param u8DestMode See APIC implementation. + * @param u8DeliveryMode See APIC implementation. + * @param uVector See APIC implementation. + * @param u8Polarity See APIC implementation. + * @param u8TriggerMode See APIC implementation. + * @param uTagSrc The IRQ tag and source (for tracing). + * + * @sa APICBusDeliver() + */ + DECLCALLBACKMEMBER(int, pfnApicBusDeliver,(PPDMDEVINS pDevIns, uint8_t u8Dest, uint8_t u8DestMode, uint8_t u8DeliveryMode, + uint8_t uVector, uint8_t u8Polarity, uint8_t u8TriggerMode, uint32_t uTagSrc)); + + /** + * Acquires the PDM lock. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to acquire the lock. + * @param pDevIns The IOAPIC device instance. + * @param rc What to return if we fail to acquire the lock. + * + * @sa PDMCritSectEnter + */ + DECLCALLBACKMEMBER(int, pfnLock,(PPDMDEVINS pDevIns, int rc)); + + /** + * Releases the PDM lock. + * + * @param pDevIns The IOAPIC device instance. + */ + DECLCALLBACKMEMBER(void, pfnUnlock,(PPDMDEVINS pDevIns)); + + /** + * Checks if the calling thread owns the PDM lock. + * + * @param pDevIns The IOAPIC device instance. + */ + DECLCALLBACKMEMBER(bool, pfnLockIsOwner,(PPDMDEVINS pDevIns)); + + /** + * Private interface between the IOAPIC and IOMMU. + * + * @returns status code. + * @param pDevIns Device instance of the IOAPIC. + * @param idDevice The device identifier (bus, device, function). + * @param pMsiIn The source MSI. + * @param pMsiOut Where to store the remapped MSI (only updated when + * VINF_SUCCESS is returned). + */ + DECLCALLBACKMEMBER(int, pfnIommuMsiRemap,(PPDMDEVINS pDevIns, uint16_t idDevice, PCMSIMSG pMsiIn, PMSIMSG pMsiOut)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMIOAPICHLP; +/** Pointer to IOAPIC helpers. */ +typedef PDMIOAPICHLP * PPDMIOAPICHLP; +/** Pointer to const IOAPIC helpers. */ +typedef const PDMIOAPICHLP * PCPDMIOAPICHLP; + +/** Current PDMIOAPICHLP version number. */ +#define PDM_IOAPICHLP_VERSION PDM_VERSION_MAKE(0xfff0, 3, 1) + + +/** + * HPET registration structure. + */ +typedef struct PDMHPETREG +{ + /** Struct version+magic number (PDM_HPETREG_VERSION). */ + uint32_t u32Version; +} PDMHPETREG; +/** Pointer to an HPET registration structure. */ +typedef PDMHPETREG *PPDMHPETREG; + +/** Current PDMHPETREG version number. */ +#define PDM_HPETREG_VERSION PDM_VERSION_MAKE(0xffe2, 1, 0) + +/** + * HPET RC helpers. + * + * @remarks Keep this around in case HPET will need PDM interaction in again RC + * at some later point. + */ +typedef struct PDMHPETHLPRC +{ + /** Structure version. PDM_HPETHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMHPETHLPRC; + +/** Pointer to HPET RC helpers. */ +typedef RCPTRTYPE(PDMHPETHLPRC *) PPDMHPETHLPRC; +/** Pointer to const HPET RC helpers. */ +typedef RCPTRTYPE(const PDMHPETHLPRC *) PCPDMHPETHLPRC; + +/** Current PDMHPETHLPRC version number. */ +#define PDM_HPETHLPRC_VERSION PDM_VERSION_MAKE(0xffee, 2, 0) + + +/** + * HPET R0 helpers. + * + * @remarks Keep this around in case HPET will need PDM interaction in again R0 + * at some later point. + */ +typedef struct PDMHPETHLPR0 +{ + /** Structure version. PDM_HPETHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMHPETHLPR0; + +/** Pointer to HPET R0 helpers. */ +typedef R0PTRTYPE(PDMHPETHLPR0 *) PPDMHPETHLPR0; +/** Pointer to const HPET R0 helpers. */ +typedef R0PTRTYPE(const PDMHPETHLPR0 *) PCPDMHPETHLPR0; + +/** Current PDMHPETHLPR0 version number. */ +#define PDM_HPETHLPR0_VERSION PDM_VERSION_MAKE(0xffed, 2, 0) + +/** + * HPET R3 helpers. + */ +typedef struct PDMHPETHLPR3 +{ + /** Structure version. PDM_HPETHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Set legacy mode on PIT and RTC. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to set legacy mode. + * @param pDevIns Device instance of the HPET. + * @param fActivated Whether legacy mode is activated or deactivated. + */ + DECLR3CALLBACKMEMBER(int, pfnSetLegacyMode,(PPDMDEVINS pDevIns, bool fActivated)); + + + /** + * Set IRQ, bypassing ISA bus override rules. + * + * @returns VINF_SUCCESS on success. + * @returns rc if we failed to set legacy mode. + * @param pDevIns Device instance of the HPET. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + */ + DECLR3CALLBACKMEMBER(int, pfnSetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMHPETHLPR3; + +/** Pointer to HPET R3 helpers. */ +typedef R3PTRTYPE(PDMHPETHLPR3 *) PPDMHPETHLPR3; +/** Pointer to const HPET R3 helpers. */ +typedef R3PTRTYPE(const PDMHPETHLPR3 *) PCPDMHPETHLPR3; + +/** Current PDMHPETHLPR3 version number. */ +#define PDM_HPETHLPR3_VERSION PDM_VERSION_MAKE(0xffec, 3, 0) + + +/** + * Raw PCI device registration structure. + */ +typedef struct PDMPCIRAWREG +{ + /** Struct version+magic number (PDM_PCIRAWREG_VERSION). */ + uint32_t u32Version; + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIRAWREG; +/** Pointer to a raw PCI registration structure. */ +typedef PDMPCIRAWREG *PPDMPCIRAWREG; + +/** Current PDMPCIRAWREG version number. */ +#define PDM_PCIRAWREG_VERSION PDM_VERSION_MAKE(0xffe1, 1, 0) + +/** + * Raw PCI device raw-mode context helpers. + */ +typedef struct PDMPCIRAWHLPRC +{ + /** Structure version and magic number (PDM_PCIRAWHLPRC_VERSION). */ + uint32_t u32Version; + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIRAWHLPRC; +/** Pointer to a raw PCI deviec raw-mode context helper structure. */ +typedef RCPTRTYPE(PDMPCIRAWHLPRC *) PPDMPCIRAWHLPRC; +/** Pointer to a const raw PCI deviec raw-mode context helper structure. */ +typedef RCPTRTYPE(const PDMPCIRAWHLPRC *) PCPDMPCIRAWHLPRC; + +/** Current PDMPCIRAWHLPRC version number. */ +#define PDM_PCIRAWHLPRC_VERSION PDM_VERSION_MAKE(0xffe0, 1, 0) + +/** + * Raw PCI device ring-0 context helpers. + */ +typedef struct PDMPCIRAWHLPR0 +{ + /** Structure version and magic number (PDM_PCIRAWHLPR0_VERSION). */ + uint32_t u32Version; + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIRAWHLPR0; +/** Pointer to a raw PCI deviec ring-0 context helper structure. */ +typedef R0PTRTYPE(PDMPCIRAWHLPR0 *) PPDMPCIRAWHLPR0; +/** Pointer to a const raw PCI deviec ring-0 context helper structure. */ +typedef R0PTRTYPE(const PDMPCIRAWHLPR0 *) PCPDMPCIRAWHLPR0; + +/** Current PDMPCIRAWHLPR0 version number. */ +#define PDM_PCIRAWHLPR0_VERSION PDM_VERSION_MAKE(0xffdf, 1, 0) + + +/** + * Raw PCI device ring-3 context helpers. + */ +typedef struct PDMPCIRAWHLPR3 +{ + /** Undefined structure version and magic number. */ + uint32_t u32Version; + + /** + * Gets the address of the RC raw PCI device helpers. + * + * This should be called at both construction and relocation time to obtain + * the correct address of the RC helpers. + * + * @returns RC pointer to the raw PCI device helpers. + * @param pDevIns Device instance of the raw PCI device. + */ + DECLR3CALLBACKMEMBER(PCPDMPCIRAWHLPRC, pfnGetRCHelpers,(PPDMDEVINS pDevIns)); + + /** + * Gets the address of the R0 raw PCI device helpers. + * + * This should be called at both construction and relocation time to obtain + * the correct address of the R0 helpers. + * + * @returns R0 pointer to the raw PCI device helpers. + * @param pDevIns Device instance of the raw PCI device. + */ + DECLR3CALLBACKMEMBER(PCPDMPCIRAWHLPR0, pfnGetR0Helpers,(PPDMDEVINS pDevIns)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMPCIRAWHLPR3; +/** Pointer to raw PCI R3 helpers. */ +typedef R3PTRTYPE(PDMPCIRAWHLPR3 *) PPDMPCIRAWHLPR3; +/** Pointer to const raw PCI R3 helpers. */ +typedef R3PTRTYPE(const PDMPCIRAWHLPR3 *) PCPDMPCIRAWHLPR3; + +/** Current PDMPCIRAWHLPR3 version number. */ +#define PDM_PCIRAWHLPR3_VERSION PDM_VERSION_MAKE(0xffde, 1, 0) + + +#ifdef IN_RING3 + +/** + * DMA Transfer Handler. + * + * @returns Number of bytes transferred. + * @param pDevIns The device instance that registered the handler. + * @param pvUser User pointer. + * @param uChannel Channel number. + * @param off DMA position. + * @param cb Block size. + * @remarks The device lock is take before the callback (in fact, the locks of + * DMA devices and the DMA controller itself are taken). + */ +typedef DECLCALLBACKTYPE(uint32_t, FNDMATRANSFERHANDLER,(PPDMDEVINS pDevIns, void *pvUser, unsigned uChannel, + uint32_t off, uint32_t cb)); +/** Pointer to a FNDMATRANSFERHANDLER(). */ +typedef FNDMATRANSFERHANDLER *PFNDMATRANSFERHANDLER; + +/** + * DMA Controller registration structure. + */ +typedef struct PDMDMAREG +{ + /** Structure version number. PDM_DMACREG_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Execute pending transfers. + * + * @returns A more work indiciator. I.e. 'true' if there is more to be done, and 'false' if all is done. + * @param pDevIns Device instance of the DMAC. + * @remarks No locks held, called on EMT(0) as a form of serialization. + */ + DECLR3CALLBACKMEMBER(bool, pfnRun,(PPDMDEVINS pDevIns)); + + /** + * Register transfer function for DMA channel. + * + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @param pDevInsHandler The device instance of the device making the + * regstration (will be passed to the callback). + * @param pfnTransferHandler Device specific transfer function. + * @param pvUser User pointer to be passed to the callback. + * @remarks No locks held, called on an EMT. + */ + DECLR3CALLBACKMEMBER(void, pfnRegister,(PPDMDEVINS pDevIns, unsigned uChannel, PPDMDEVINS pDevInsHandler, + PFNDMATRANSFERHANDLER pfnTransferHandler, void *pvUser)); + + /** + * Read memory + * + * @returns Number of bytes read. + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @param pvBuffer Pointer to target buffer. + * @param off DMA position. + * @param cbBlock Block size. + * @remarks No locks held, called on an EMT. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnReadMemory,(PPDMDEVINS pDevIns, unsigned uChannel, void *pvBuffer, uint32_t off, uint32_t cbBlock)); + + /** + * Write memory + * + * @returns Number of bytes written. + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @param pvBuffer Memory to write. + * @param off DMA position. + * @param cbBlock Block size. + * @remarks No locks held, called on an EMT. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnWriteMemory,(PPDMDEVINS pDevIns, unsigned uChannel, const void *pvBuffer, uint32_t off, uint32_t cbBlock)); + + /** + * Set the DREQ line. + * + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @param uLevel Level of the line. + * @remarks No locks held, called on an EMT. + */ + DECLR3CALLBACKMEMBER(void, pfnSetDREQ,(PPDMDEVINS pDevIns, unsigned uChannel, unsigned uLevel)); + + /** + * Get channel mode + * + * @returns Channel mode. + * @param pDevIns Device instance of the DMAC. + * @param uChannel Channel number. + * @remarks No locks held, called on an EMT. + */ + DECLR3CALLBACKMEMBER(uint8_t, pfnGetChannelMode,(PPDMDEVINS pDevIns, unsigned uChannel)); + +} PDMDMACREG; +/** Pointer to a DMAC registration structure. */ +typedef PDMDMACREG *PPDMDMACREG; + +/** Current PDMDMACREG version number. */ +#define PDM_DMACREG_VERSION PDM_VERSION_MAKE(0xffeb, 2, 0) + + +/** + * DMA Controller device helpers. + */ +typedef struct PDMDMACHLP +{ + /** Structure version. PDM_DMACHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /* to-be-defined */ + +} PDMDMACHLP; +/** Pointer to DMAC helpers. */ +typedef PDMDMACHLP *PPDMDMACHLP; +/** Pointer to const DMAC helpers. */ +typedef const PDMDMACHLP *PCPDMDMACHLP; + +/** Current PDMDMACHLP version number. */ +#define PDM_DMACHLP_VERSION PDM_VERSION_MAKE(0xffea, 1, 0) + +#endif /* IN_RING3 */ + + + +/** + * RTC registration structure. + */ +typedef struct PDMRTCREG +{ + /** Structure version number. PDM_RTCREG_VERSION defines the current version. */ + uint32_t u32Version; + uint32_t u32Alignment; /**< structure size alignment. */ + + /** + * Write to a CMOS register and update the checksum if necessary. + * + * @returns VBox status code. + * @param pDevIns Device instance of the RTC. + * @param iReg The CMOS register index. + * @param u8Value The CMOS register value. + * @remarks Caller enters the device critical section. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMDEVINS pDevIns, unsigned iReg, uint8_t u8Value)); + + /** + * Read a CMOS register. + * + * @returns VBox status code. + * @param pDevIns Device instance of the RTC. + * @param iReg The CMOS register index. + * @param pu8Value Where to store the CMOS register value. + * @remarks Caller enters the device critical section. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMDEVINS pDevIns, unsigned iReg, uint8_t *pu8Value)); + +} PDMRTCREG; +/** Pointer to a RTC registration structure. */ +typedef PDMRTCREG *PPDMRTCREG; +/** Pointer to a const RTC registration structure. */ +typedef const PDMRTCREG *PCPDMRTCREG; + +/** Current PDMRTCREG version number. */ +#define PDM_RTCREG_VERSION PDM_VERSION_MAKE(0xffe9, 2, 0) + + +/** + * RTC device helpers. + */ +typedef struct PDMRTCHLP +{ + /** Structure version. PDM_RTCHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /* to-be-defined */ + +} PDMRTCHLP; +/** Pointer to RTC helpers. */ +typedef PDMRTCHLP *PPDMRTCHLP; +/** Pointer to const RTC helpers. */ +typedef const PDMRTCHLP *PCPDMRTCHLP; + +/** Current PDMRTCHLP version number. */ +#define PDM_RTCHLP_VERSION PDM_VERSION_MAKE(0xffe8, 1, 0) + + + +/** @name Flags for PCI I/O region registration + * @{ */ +/** No handle is passed. */ +#define PDMPCIDEV_IORGN_F_NO_HANDLE UINT32_C(0x00000000) +/** An I/O port handle is passed. */ +#define PDMPCIDEV_IORGN_F_IOPORT_HANDLE UINT32_C(0x00000001) +/** An MMIO range handle is passed. */ +#define PDMPCIDEV_IORGN_F_MMIO_HANDLE UINT32_C(0x00000002) +/** An MMIO2 handle is passed. */ +#define PDMPCIDEV_IORGN_F_MMIO2_HANDLE UINT32_C(0x00000003) +/** Handle type mask. */ +#define PDMPCIDEV_IORGN_F_HANDLE_MASK UINT32_C(0x00000003) +/** New-style (mostly wrt callbacks). */ +#define PDMPCIDEV_IORGN_F_NEW_STYLE UINT32_C(0x00000004) +/** Mask of valid flags. */ +#define PDMPCIDEV_IORGN_F_VALID_MASK UINT32_C(0x00000007) +/** @} */ + + +/** @name Flags for the guest physical read/write helpers + * @{ */ +/** Default flag with no indication whether the data is processed by the device or just passed through. */ +#define PDM_DEVHLP_PHYS_RW_F_DEFAULT UINT32_C(0x00000000) +/** The data is user data which is just passed through between the guest and the source or destination and not processed + * by the device in any way. */ +#define PDM_DEVHLP_PHYS_RW_F_DATA_USER RT_BIT_32(0) +/** The data is metadata and being processed by the device in some way. */ +#define PDM_DEVHLP_PHYS_RW_F_DATA_META RT_BIT_32(1) +/** @} */ + + +#ifdef IN_RING3 + +/** @name Special values for PDMDEVHLPR3::pfnPCIRegister parameters. + * @{ */ +/** Same device number (and bus) as the previous PCI device registered with the PDM device. + * This is handy when registering multiple PCI device functions and the device + * number is left up to the PCI bus. In order to facilitate one PDM device + * instance for each PCI function, this searches earlier PDM device + * instances as well. */ +# define PDMPCIDEVREG_DEV_NO_SAME_AS_PREV UINT8_C(0xfd) +/** Use the first unused device number (all functions must be unused). */ +# define PDMPCIDEVREG_DEV_NO_FIRST_UNUSED UINT8_C(0xfe) +/** Use the first unused device function. */ +# define PDMPCIDEVREG_FUN_NO_FIRST_UNUSED UINT8_C(0xff) + +/** The device and function numbers are not mandatory, just suggestions. */ +# define PDMPCIDEVREG_F_NOT_MANDATORY_NO RT_BIT_32(0) +/** Registering a PCI bridge device. */ +# define PDMPCIDEVREG_F_PCI_BRIDGE RT_BIT_32(1) +/** Valid flag mask. */ +# define PDMPCIDEVREG_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +/** Current PDMDEVHLPR3 version number. */ +#define PDM_DEVHLPR3_VERSION PDM_VERSION_MAKE_PP(0xffe7, 65, 0) + +/** + * PDM Device API. + */ +typedef struct PDMDEVHLPR3 +{ + /** Structure version. PDM_DEVHLPR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** @name I/O ports + * @{ */ + /** + * Creates a range of I/O ports for a device. + * + * The I/O port range must be mapped in a separately call. Any ring-0 and + * raw-mode context callback handlers needs to be set up in the respective + * contexts. + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param cPorts Number of ports to register. + * @param fFlags IOM_IOPORT_F_XXX. + * @param pPciDev The PCI device the range is associated with, if + * applicable. + * @param iPciRegion The PCI device region in the high 16-bit word and + * sub-region in the low 16-bit word. UINT32_MAX if NA. + * @param pfnOut Pointer to function which is gonna handle OUT + * operations. Optional. + * @param pfnIn Pointer to function which is gonna handle IN operations. + * Optional. + * @param pfnOutStr Pointer to function which is gonna handle string OUT + * operations. Optional. + * @param pfnInStr Pointer to function which is gonna handle string IN + * operations. Optional. + * @param pvUser User argument to pass to the callbacks. + * @param pszDesc Pointer to description string. This must not be freed. + * @param paExtDescs Extended per-port descriptions, optional. Partial range + * coverage is allowed. This must not be freed. + * @param phIoPorts Where to return the I/O port range handle. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpIoPortSetUpContext, PDMDevHlpIoPortMap, + * PDMDevHlpIoPortUnmap. + */ + DECLR3CALLBACKMEMBER(int, pfnIoPortCreateEx,(PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev, + uint32_t iPciRegion, PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, RTR3PTR pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts)); + + /** + * Maps an I/O port range. + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + * @param Port Where to map the range. + * @sa PDMDevHlpIoPortUnmap, PDMDevHlpIoPortSetUpContext, + * PDMDevHlpIoPortCreate, PDMDevHlpIoPortCreateEx. + */ + DECLR3CALLBACKMEMBER(int, pfnIoPortMap,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, RTIOPORT Port)); + + /** + * Unmaps an I/O port range. + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + * @sa PDMDevHlpIoPortMap, PDMDevHlpIoPortSetUpContext, + * PDMDevHlpIoPortCreate, PDMDevHlpIoPortCreateEx. + */ + DECLR3CALLBACKMEMBER(int, pfnIoPortUnmap,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts)); + + /** + * Gets the mapping address of the I/O port range @a hIoPorts. + * + * @returns Mapping address (0..65535) or UINT32_MAX if not mapped (or invalid + * parameters). + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnIoPortGetMappingAddress,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts)); + + /** + * Writes to an I/O port register. + * + * @returns Strict VBox status code. Informational status codes other than the one documented + * here are to be treated as internal failure. Use IOM_SUCCESS() to check for success. + * @retval VINF_SUCCESS Success. + * @retval VINF_EM_FIRST-VINF_EM_LAST Success with some exceptions (see IOM_SUCCESS()), the + * status code must be passed on to EM. + * + * @param pDevIns The device instance to register the ports with. + * @param Port The port to write to. + * @param u32Value The value to write. + * @param cbValue The size of the register to read in bytes. 1, 2 or 4 bytes. + * + * @thread EMT + * @todo r=aeichner This is only used by DevPCI.cpp to write the ELCR of the PIC. This shouldn't be done that way + * and removed again as soon as possible (no time right now)... + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnIoPortWrite,(PPDMDEVINS pDevIns, RTIOPORT Port, uint32_t u32Value, size_t cbValue)); + /** @} */ + + /** @name MMIO + * @{ */ + /** + * Creates a memory mapped I/O (MMIO) region for a device. + * + * The MMIO region must be mapped in a separately call. Any ring-0 and + * raw-mode context callback handlers needs to be set up in the respective + * contexts. + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param cbRegion The size of the region in bytes. + * @param fFlags Flags, IOMMMIO_FLAGS_XXX. + * @param pPciDev The PCI device the range is associated with, if + * applicable. + * @param iPciRegion The PCI device region in the high 16-bit word and + * sub-region in the low 16-bit word. UINT32_MAX if NA. + * @param pfnWrite Pointer to function which is gonna handle Write + * operations. + * @param pfnRead Pointer to function which is gonna handle Read + * operations. + * @param pfnFill Pointer to function which is gonna handle Fill/memset + * operations. (optional) + * @param pvUser User argument to pass to the callbacks. + * @param pszDesc Pointer to description string. This must not be freed. + * @param phRegion Where to return the MMIO region handle. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpMmioSetUpContext, PDMDevHlpMmioMap, PDMDevHlpMmioUnmap. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioCreateEx,(PPDMDEVINS pDevIns, RTGCPHYS cbRegion, + uint32_t fFlags, PPDMPCIDEV pPciDev, uint32_t iPciRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, + void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion)); + + /** + * Maps a memory mapped I/O (MMIO) region (into the guest physical address space). + * + * @returns VBox status. + * @param pDevIns The device instance the region is associated with. + * @param hRegion The MMIO region handle. + * @param GCPhys Where to map the region. + * @note An MMIO range may overlap with base memory if a lot of RAM is + * configured for the VM, in which case we'll drop the base memory + * pages. Presently we will make no attempt to preserve anything that + * happens to be present in the base memory that is replaced, this is + * technically incorrect but it's just not worth the effort to do + * right, at least not at this point. + * @sa PDMDevHlpMmioUnmap, PDMDevHlpMmioCreate, PDMDevHlpMmioCreateEx, + * PDMDevHlpMmioSetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnMmioMap,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys)); + + /** + * Unmaps a memory mapped I/O (MMIO) region. + * + * @returns VBox status. + * @param pDevIns The device instance the region is associated with. + * @param hRegion The MMIO region handle. + * @sa PDMDevHlpMmioMap, PDMDevHlpMmioCreate, PDMDevHlpMmioCreateEx, + * PDMDevHlpMmioSetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnMmioUnmap,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)); + + /** + * Reduces the length of a MMIO range. + * + * This is for implementations of PDMPCIDEV::pfnRegionLoadChangeHookR3 and will + * only work during saved state restore. It will not call the PCI bus code, as + * that is expected to restore the saved resource configuration. + * + * It just adjusts the mapping length of the region so that when pfnMmioMap is + * called it will only map @a cbRegion bytes and not the value set during + * registration. + * + * @return VBox status code. + * @param pDevIns The device owning the range. + * @param hRegion The MMIO region handle. + * @param cbRegion The new size, must be smaller. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioReduce,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion)); + + /** + * Gets the mapping address of the MMIO region @a hRegion. + * + * @returns Mapping address, NIL_RTGCPHYS if not mapped (or invalid parameters). + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO region handle. + */ + DECLR3CALLBACKMEMBER(RTGCPHYS, pfnMmioGetMappingAddress,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)); + /** @} */ + + /** @name MMIO2 + * @{ */ + /** + * Creates a MMIO2 region. + * + * As mentioned elsewhere, MMIO2 is just RAM spelled differently. It's RAM + * associated with a device. It is also non-shared memory with a permanent + * ring-3 mapping and page backing (presently). + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param pPciDev The PCI device the region is associated with, or + * NULL if no PCI device association. + * @param iPciRegion The region number. Use the PCI region number as + * this must be known to the PCI bus device too. If + * it's not associated with the PCI device, then + * any number up to UINT8_MAX is fine. + * @param cbRegion The size (in bytes) of the region. + * @param fFlags PGMPHYS_MMIO2_FLAGS_XXX (see pgm.h). + * @param pszDesc Pointer to description string. This must not be + * freed. + * @param ppvMapping Where to store the address of the ring-3 mapping + * of the memory. + * @param phRegion Where to return the MMIO2 region handle. + * + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Create,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iPciRegion, RTGCPHYS cbRegion, + uint32_t fFlags, const char *pszDesc, void **ppvMapping, PPGMMMIO2HANDLE phRegion)); + + /** + * Destroys a MMIO2 region, unmapping it and freeing the memory. + * + * Any physical access handlers registered for the region must be deregistered + * before calling this function. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Destroy,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion)); + + /** + * Maps a MMIO2 region (into the guest physical address space). + * + * @returns VBox status. + * @param pDevIns The device instance the region is associated with. + * @param hRegion The MMIO2 region handle. + * @param GCPhys Where to map the region. + * @note A MMIO2 region overlap with base memory if a lot of RAM is + * configured for the VM, in which case we'll drop the base memory + * pages. Presently we will make no attempt to preserve anything that + * happens to be present in the base memory that is replaced, this is + * technically incorrect but it's just not worth the effort to do + * right, at least not at this point. + * @sa PDMDevHlpMmio2Unmap, PDMDevHlpMmio2Create, PDMDevHlpMmio2SetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Map,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, RTGCPHYS GCPhys)); + + /** + * Unmaps a MMIO2 region. + * + * @returns VBox status. + * @param pDevIns The device instance the region is associated with. + * @param hRegion The MMIO2 region handle. + * @sa PDMDevHlpMmio2Map, PDMDevHlpMmio2Create, PDMDevHlpMmio2SetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Unmap,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion)); + + /** + * Reduces the length of a MMIO range. + * + * This is for implementations of PDMPCIDEV::pfnRegionLoadChangeHookR3 and will + * only work during saved state restore. It will not call the PCI bus code, as + * that is expected to restore the saved resource configuration. + * + * It just adjusts the mapping length of the region so that when pfnMmioMap is + * called it will only map @a cbRegion bytes and not the value set during + * registration. + * + * @return VBox status code. + * @param pDevIns The device owning the range. + * @param hRegion The MMIO2 region handle. + * @param cbRegion The new size, must be smaller. + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2Reduce,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, RTGCPHYS cbRegion)); + + /** + * Gets the mapping address of the MMIO region @a hRegion. + * + * @returns Mapping address, NIL_RTGCPHYS if not mapped (or invalid parameters). + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO2 region handle. + */ + DECLR3CALLBACKMEMBER(RTGCPHYS, pfnMmio2GetMappingAddress,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion)); + + /** + * Queries and resets the dirty bitmap for an MMIO2 region. + * + * The MMIO2 region must have been created with the + * PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES flag for this to work. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + * @param pvBitmap Where to return the bitmap. Must be 8-byte aligned. + * Can be NULL if only resetting the tracking is desired. + * @param cbBitmap The bitmap size. One bit per page in the region, + * rounded up to 8-bytes. If pvBitmap is NULL this must + * also be zero. + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2QueryAndResetDirtyBitmap, (PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, + void *pvBitmap, size_t cbBitmap)); + + /** + * Controls the dirty page tracking for an MMIO2 region. + * + * The MMIO2 region must have been created with the + * PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES flag for this to work. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + * @param fEnabled When set to @c true the dirty page tracking will be + * enabled if currently disabled (bitmap is reset). When + * set to @c false the dirty page tracking will be + * disabled. + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2ControlDirtyPageTracking, (PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, bool fEnabled)); + + /** + * Changes the number of an MMIO2 or pre-registered MMIO region. + * + * This should only be used to deal with saved state problems, so there is no + * convenience inline wrapper for this method. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + * @param iNewRegion The new region index. + * + * @sa @bugref{9359} + */ + DECLR3CALLBACKMEMBER(int, pfnMmio2ChangeRegionNo,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, uint32_t iNewRegion)); + + /** + * Mapping an MMIO2 page in place of an MMIO page for direct access. + * + * This is a special optimization used by the VGA device. Call + * PDMDevHlpMmioResetRegion() to undo the mapping. + * + * @returns VBox status code. This API may return VINF_SUCCESS even if no + * remapping is made. + * @retval VERR_SEM_BUSY in ring-0 if we cannot get the IOM lock. + * + * @param pDevIns The device instance @a hRegion and @a hMmio2 are + * associated with. + * @param hRegion The handle to the MMIO region. + * @param offRegion The offset into @a hRegion of the page to be + * remapped. + * @param hMmio2 The MMIO2 handle. + * @param offMmio2 Offset into @a hMmio2 of the page to be use for the + * mapping. + * @param fPageFlags Page flags to set. Must be (X86_PTE_RW | X86_PTE_P) + * for the time being. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioMapMmio2Page,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion, + uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags)); + + /** + * Reset a previously modified MMIO region; restore the access flags. + * + * This undoes the effects of PDMDevHlpMmioMapMmio2Page() and is currently only + * intended for some ancient VGA hack. However, it would be great to extend it + * beyond VT-x and/or nested-paging. + * + * @returns VBox status code. + * + * @param pDevIns The device instance @a hRegion is associated with. + * @param hRegion The handle to the MMIO region. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioResetRegion, (PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)); + /** @} */ + + /** + * Register a ROM (BIOS) region. + * + * It goes without saying that this is read-only memory. The memory region must be + * in unassigned memory. I.e. from the top of the address space or on the PC in + * the 0xa0000-0xfffff range. + * + * @returns VBox status. + * @param pDevIns The device instance owning the ROM region. + * @param GCPhysStart First physical address in the range. + * Must be page aligned! + * @param cbRange The size of the range (in bytes). + * Must be page aligned! + * @param pvBinary Pointer to the binary data backing the ROM image. + * @param cbBinary The size of the binary pointer. This must + * be equal or smaller than @a cbRange. + * @param fFlags PGMPHYS_ROM_FLAGS_XXX (see pgm.h). + * @param pszDesc Pointer to description string. This must not be freed. + * + * @remark There is no way to remove the rom, automatically on device cleanup or + * manually from the device yet. At present I doubt we need such features... + */ + DECLR3CALLBACKMEMBER(int, pfnROMRegister,(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, + const void *pvBinary, uint32_t cbBinary, uint32_t fFlags, const char *pszDesc)); + + /** + * Changes the protection of shadowed ROM mapping. + * + * This is intented for use by the system BIOS, chipset or device in question to + * change the protection of shadowed ROM code after init and on reset. + * + * @param pDevIns The device instance. + * @param GCPhysStart Where the mapping starts. + * @param cbRange The size of the mapping. + * @param enmProt The new protection type. + */ + DECLR3CALLBACKMEMBER(int, pfnROMProtectShadow,(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, PGMROMPROT enmProt)); + + /** + * Register a save state data unit. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * @param pszBefore Name of data unit which we should be put in + * front of. Optional (NULL). + * + * @param pfnLivePrep Prepare live save callback, optional. + * @param pfnLiveExec Execute live save callback, optional. + * @param pfnLiveVote Vote live save callback, optional. + * + * @param pfnSavePrep Prepare save callback, optional. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnSaveDone Done save callback, optional. + * + * @param pfnLoadPrep Prepare load callback, optional. + * @param pfnLoadExec Execute load callback, optional. + * @param pfnLoadDone Done load callback, optional. + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMRegister,(PPDMDEVINS pDevIns, uint32_t uVersion, size_t cbGuess, const char *pszBefore, + PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote, + PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone, + PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone)); + + /** + * Register a save state data unit for backward compatibility. + * + * This is for migrating from an old device name to a new one or for merging + * devices. It will only help loading old saved states. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param pszOldName The old unit name. + * @param pfnLoadPrep Prepare load callback, optional. + * @param pfnLoadExec Execute load callback, optional. + * @param pfnLoadDone Done load callback, optional. + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMRegisterLegacy,(PPDMDEVINS pDevIns, const char *pszOldName, PFNSSMDEVLOADPREP pfnLoadPrep, + PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone)); + + /** @name Exported SSM Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnSSMPutStruct,(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStructEx,(PSSMHANDLE pSSM, const void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutBool,(PSSMHANDLE pSSM, bool fBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU8,(PSSMHANDLE pSSM, uint8_t u8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS8,(PSSMHANDLE pSSM, int8_t i8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU16,(PSSMHANDLE pSSM, uint16_t u16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS16,(PSSMHANDLE pSSM, int16_t i16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU32,(PSSMHANDLE pSSM, uint32_t u32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS32,(PSSMHANDLE pSSM, int32_t i32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU64,(PSSMHANDLE pSSM, uint64_t u64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS64,(PSSMHANDLE pSSM, int64_t i64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU128,(PSSMHANDLE pSSM, uint128_t u128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS128,(PSSMHANDLE pSSM, int128_t i128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutUInt,(PSSMHANDLE pSSM, RTUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSInt,(PSSMHANDLE pSSM, RTINT i)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUInt,(PSSMHANDLE pSSM, RTGCUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntReg,(PSSMHANDLE pSSM, RTGCUINTREG u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys32,(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys64,(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys,(PSSMHANDLE pSSM, RTGCPHYS GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPtr,(PSSMHANDLE pSSM, RTGCPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntPtr,(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutRCPtr,(PSSMHANDLE pSSM, RTRCPTR RCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutIOPort,(PSSMHANDLE pSSM, RTIOPORT IOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSel,(PSSMHANDLE pSSM, RTSEL Sel)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutMem,(PSSMHANDLE pSSM, const void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStrZ,(PSSMHANDLE pSSM, const char *psz)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStruct,(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStructEx,(PSSMHANDLE pSSM, void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBool,(PSSMHANDLE pSSM, bool *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBoolV,(PSSMHANDLE pSSM, bool volatile *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8,(PSSMHANDLE pSSM, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8V,(PSSMHANDLE pSSM, uint8_t volatile *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8,(PSSMHANDLE pSSM, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8V,(PSSMHANDLE pSSM, int8_t volatile *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16,(PSSMHANDLE pSSM, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16V,(PSSMHANDLE pSSM, uint16_t volatile *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16,(PSSMHANDLE pSSM, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16V,(PSSMHANDLE pSSM, int16_t volatile *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32,(PSSMHANDLE pSSM, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32V,(PSSMHANDLE pSSM, uint32_t volatile *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32,(PSSMHANDLE pSSM, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32V,(PSSMHANDLE pSSM, int32_t volatile *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64,(PSSMHANDLE pSSM, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64V,(PSSMHANDLE pSSM, uint64_t volatile *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64,(PSSMHANDLE pSSM, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64V,(PSSMHANDLE pSSM, int64_t volatile *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128,(PSSMHANDLE pSSM, uint128_t *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128V,(PSSMHANDLE pSSM, uint128_t volatile *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128,(PSSMHANDLE pSSM, int128_t *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128V,(PSSMHANDLE pSSM, int128_t volatile *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32,(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32V,(PSSMHANDLE pSSM, RTGCPHYS32 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64,(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64V,(PSSMHANDLE pSSM, RTGCPHYS64 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys,(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhysV,(PSSMHANDLE pSSM, RTGCPHYS volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetUInt,(PSSMHANDLE pSSM, PRTUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSInt,(PSSMHANDLE pSSM, PRTINT pi)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUInt,(PSSMHANDLE pSSM, PRTGCUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntReg,(PSSMHANDLE pSSM, PRTGCUINTREG pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPtr,(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntPtr,(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetRCPtr,(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetIOPort,(PSSMHANDLE pSSM, PRTIOPORT pIOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSel,(PSSMHANDLE pSSM, PRTSEL pSel)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetMem,(PSSMHANDLE pSSM, void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZ,(PSSMHANDLE pSSM, char *psz, size_t cbMax)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZEx,(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkip,(PSSMHANDLE pSSM, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkipToEndOfUnit,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadError,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadErrorV,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgError,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgErrorV,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMHandleGetStatus,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(SSMAFTER, pfnSSMHandleGetAfter,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(bool, pfnSSMHandleIsLiveSave,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleMaxDowntime,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleHostBits,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleRevision,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleVersion,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(const char *, pfnSSMHandleHostOSAndArch,(PSSMHANDLE pSSM)); + /** @} */ + + /** + * Creates a timer w/ a cross context handle. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param enmClock The clock to use on this timer. + * @param pfnCallback Callback function. + * @param pvUser User argument for the callback. + * @param fFlags Flags, see TMTIMER_FLAGS_*. + * @param pszDesc Pointer to description string which must stay around + * until the timer is fully destroyed (i.e. a bit after TMTimerDestroy()). + * @param phTimer Where to store the timer handle on success. + * @remarks Caller enters the device critical section prior to invoking the + * callback. + */ + DECLR3CALLBACKMEMBER(int, pfnTimerCreate,(PPDMDEVINS pDevIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, + void *pvUser, uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)); + + /** @name Timer handle method wrappers + * @{ */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromMicro,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromMilli,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGet,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGetFreq,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGetNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(bool, pfnTimerIsActive,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(bool, pfnTimerIsLockOwner,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnTimerLockClock,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, int rcBusy)); + /** Takes the clock lock then enters the specified critical section. */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnTimerLockClock2,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnTimerSet,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t uExpire)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetFrequencyHint,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint32_t uHz)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetMicro,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetMillies,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetRelative,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now)); + DECLR3CALLBACKMEMBER(int, pfnTimerStop,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(void, pfnTimerUnlockClock,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(void, pfnTimerUnlockClock2,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetCritSect,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSave,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnTimerLoad,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnTimerDestroy,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + /** @sa TMR3TimerSkip */ + DECLR3CALLBACKMEMBER(int, pfnTimerSkipLoad,(PSSMHANDLE pSSM, bool *pfActive)); + /** @} */ + + /** + * Get the real world UTC time adjusted for VM lag, user offset and warpdrive. + * + * @returns pTime. + * @param pDevIns The device instance. + * @param pTime Where to store the time. + */ + DECLR3CALLBACKMEMBER(PRTTIMESPEC, pfnTMUtcNow,(PPDMDEVINS pDevIns, PRTTIMESPEC pTime)); + + /** @name Exported CFGM Functions. + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCFGMExists,( PCFGMNODE pNode, const char *pszName)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryType,( PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySize,( PCFGMNODE pNode, const char *pszName, size_t *pcb)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryInteger,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryIntegerDef,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryString,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPassword,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPasswordDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBytes,( PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64Def,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64,( PCFGMNODE pNode, const char *pszName, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64Def,( PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32Def,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32,( PCFGMNODE pNode, const char *pszName, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32Def,( PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16Def,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16,( PCFGMNODE pNode, const char *pszName, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16Def,( PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8Def,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8,( PCFGMNODE pNode, const char *pszName, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8Def,( PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBool,( PCFGMNODE pNode, const char *pszName, bool *pf)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBoolDef,( PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPort,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPortDef,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUInt,( PCFGMNODE pNode, const char *pszName, unsigned int *pu)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUIntDef,( PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySInt,( PCFGMNODE pNode, const char *pszName, signed int *pi)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySIntDef,( PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtr,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrDef,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrU,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrUDef,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrS,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrSDef,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAlloc,( PCFGMNODE pNode, const char *pszName, char **ppszString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAllocDef,(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetParent,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChild,(PCFGMNODE pNode, const char *pszPath)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildF,(PCFGMNODE pNode, const char *pszPathFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildFV,(PCFGMNODE pNode, const char *pszPathFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetFirstChild,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetNextChild,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetName,(PCFGMNODE pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetNameLen,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreChildrenValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetFirstValue,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetNextValue,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetValueName,(PCFGMLEAF pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetValueNameLen,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(CFGMVALUETYPE, pfnCFGMGetValueType,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreValuesValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(int, pfnCFGMValidateConfig,(PCFGMNODE pNode, const char *pszNode, + const char *pszValidValues, const char *pszValidNodes, + const char *pszWho, uint32_t uInstance)); + /** @} */ + + /** + * Read physical memory. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Write to physical memory. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Requests the mapping of a guest page into ring-3. + * + * When you're done with the page, call pfnPhysReleasePageMappingLock() ASAP to + * release it. + * + * This API will assume your intention is to write to the page, and will + * therefore replace shared and zero pages. If you do not intend to modify the + * page, use the pfnPhysGCPhys2CCPtrReadOnly() API. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical + * backing or if the page has any active access handlers. The caller + * must fall back on using PGMR3PhysWriteExternal. + * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address. + * + * @param pDevIns The device instance. + * @param GCPhys The guest physical address of the page that + * should be mapped. + * @param fFlags Flags reserved for future use, MBZ. + * @param ppv Where to store the address corresponding to + * GCPhys. + * @param pLock Where to store the lock information that + * pfnPhysReleasePageMappingLock needs. + * + * @remark Avoid calling this API from within critical sections (other than the + * PGM one) because of the deadlock risk when we have to delegating the + * task to an EMT. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysGCPhys2CCPtr,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, void **ppv, + PPGMPAGEMAPLOCK pLock)); + + /** + * Requests the mapping of a guest page into ring-3, external threads. + * + * When you're done with the page, call pfnPhysReleasePageMappingLock() ASAP to + * release it. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PGM_PHYS_PAGE_RESERVED it it's a valid page but has no physical + * backing or if the page as an active ALL access handler. The caller + * must fall back on using PGMPhysRead. + * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if it's not a valid physical address. + * + * @param pDevIns The device instance. + * @param GCPhys The guest physical address of the page that + * should be mapped. + * @param fFlags Flags reserved for future use, MBZ. + * @param ppv Where to store the address corresponding to + * GCPhys. + * @param pLock Where to store the lock information that + * pfnPhysReleasePageMappingLock needs. + * + * @remark Avoid calling this API from within critical sections. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysGCPhys2CCPtrReadOnly,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, + void const **ppv, PPGMPAGEMAPLOCK pLock)); + + /** + * Release the mapping of a guest page. + * + * This is the counter part of pfnPhysGCPhys2CCPtr and + * pfnPhysGCPhys2CCPtrReadOnly. + * + * @param pDevIns The device instance. + * @param pLock The lock structure initialized by the mapping + * function. + */ + DECLR3CALLBACKMEMBER(void, pfnPhysReleasePageMappingLock,(PPDMDEVINS pDevIns, PPGMPAGEMAPLOCK pLock)); + + /** + * Read guest physical memory by virtual address. + * + * @param pDevIns The device instance. + * @param pvDst Where to put the read bits. + * @param GCVirtSrc Guest virtual address to start reading from. + * @param cb How many bytes to read. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysReadGCVirt,(PPDMDEVINS pDevIns, void *pvDst, RTGCPTR GCVirtSrc, size_t cb)); + + /** + * Write to guest physical memory by virtual address. + * + * @param pDevIns The device instance. + * @param GCVirtDst Guest virtual address to write to. + * @param pvSrc What to write. + * @param cb How many bytes to write. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysWriteGCVirt,(PPDMDEVINS pDevIns, RTGCPTR GCVirtDst, const void *pvSrc, size_t cb)); + + /** + * Convert a guest virtual address to a guest physical address. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPtr Guest virtual address. + * @param pGCPhys Where to store the GC physical address + * corresponding to GCPtr. + * @thread The emulation thread. + * @remark Careful with page boundaries. + */ + DECLR3CALLBACKMEMBER(int, pfnPhysGCPtr2GCPhys, (PPDMDEVINS pDevIns, RTGCPTR GCPtr, PRTGCPHYS pGCPhys)); + + /** + * Checks if a GC physical address is a normal page, + * i.e. not ROM, MMIO or reserved. + * + * @returns true if normal. + * @returns false if invalid, ROM, MMIO or reserved page. + * @param pDevIns The device instance. + * @param GCPhys The physical address to check. + */ + DECLR3CALLBACKMEMBER(bool, pfnPhysIsGCPhysNormal,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)); + + /** + * Inflate or deflate a memory balloon + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param fInflate Inflate or deflate memory balloon + * @param cPages Number of pages to free + * @param paPhysPage Array of guest physical addresses + */ + DECLR3CALLBACKMEMBER(int, pfnPhysChangeMemBalloon,(PPDMDEVINS pDevIns, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage)); + + /** + * Allocate memory which is associated with current VM instance + * and automatically freed on it's destruction. + * + * @returns Pointer to allocated memory. The memory is *NOT* zero-ed. + * @param pDevIns The device instance. + * @param cb Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(void *, pfnMMHeapAlloc,(PPDMDEVINS pDevIns, size_t cb)); + + /** + * Allocate memory which is associated with current VM instance + * and automatically freed on it's destruction. The memory is ZEROed. + * + * @returns Pointer to allocated memory. The memory is *NOT* zero-ed. + * @param pDevIns The device instance. + * @param cb Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(void *, pfnMMHeapAllocZ,(PPDMDEVINS pDevIns, size_t cb)); + + /** + * Allocating string printf. + * + * @returns Pointer to the string. + * @param pDevIns The device instance. + * @param enmTag The statistics tag. + * @param pszFormat The format string. + * @param va Format arguments. + */ + DECLR3CALLBACKMEMBER(char *, pfnMMHeapAPrintfV,(PPDMDEVINS pDevIns, MMTAG enmTag, const char *pszFormat, va_list va)); + + /** + * Free memory allocated with pfnMMHeapAlloc() and pfnMMHeapAllocZ(). + * + * @param pDevIns The device instance. + * @param pv Pointer to the memory to free. + */ + DECLR3CALLBACKMEMBER(void, pfnMMHeapFree,(PPDMDEVINS pDevIns, void *pv)); + + /** + * Returns the physical RAM size of the VM. + * + * @returns RAM size in bytes. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnMMPhysGetRamSize,(PPDMDEVINS pDevIns)); + + /** + * Returns the physical RAM size of the VM below the 4GB boundary. + * + * @returns RAM size in bytes. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnMMPhysGetRamSizeBelow4GB,(PPDMDEVINS pDevIns)); + + /** + * Returns the physical RAM size of the VM above the 4GB boundary. + * + * @returns RAM size in bytes. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnMMPhysGetRamSizeAbove4GB,(PPDMDEVINS pDevIns)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pDevIns The device instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLR3CALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMDEVINS pDevIns)); + + /** + * Checks if the VM was teleported and hasn't been fully resumed yet. + * + * @returns true / false. + * @param pDevIns The device instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnVMTeleportedAndNotFullyResumedYet,(PPDMDEVINS pDevIns)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDevIns The device instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetErrorV,(PPDMDEVINS pDevIns, int rc, RT_SRC_POS_DECL, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetRuntimeErrorV,(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(4, 0)); + + /** + * Special interface for implementing a HLT-like port on a device. + * + * This can be called directly from device code, provide the device is trusted + * to access the VMM directly. Since we may not have an accurate register set + * and the caller certainly shouldn't (device code does not access CPU + * registers), this function will return when interrupts are pending regardless + * of the actual EFLAGS.IF state. + * + * @returns VBox error status (never informational statuses). + * @param pDevIns The device instance. + * @param idCpu The id of the calling EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnVMWaitForDeviceReady,(PPDMDEVINS pDevIns, VMCPUID idCpu)); + + /** + * Wakes up a CPU that has called PDMDEVHLPR3::pfnVMWaitForDeviceReady. + * + * @returns VBox error status (never informational statuses). + * @param pDevIns The device instance. + * @param idCpu The id of the calling EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnVMNotifyCpuDeviceReady,(PPDMDEVINS pDevIns, VMCPUID idCpu)); + + /** + * Convenience wrapper for VMR3ReqCallU. + * + * This assumes (1) you're calling a function that returns an VBox status code + * and that you do not wish to wait for it to complete. + * + * @returns VBox status code returned by VMR3ReqCallVU. + * + * @param pDevIns The device instance. + * @param idDstCpu The destination CPU(s). Either a specific CPU ID or + * one of the following special values: + * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param Args Argument vector. + * + * @remarks See remarks on VMR3ReqCallVU. + */ + DECLR3CALLBACKMEMBER(int, pfnVMReqCallNoWaitV,(PPDMDEVINS pDevIns, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, va_list Args)); + + /** + * Convenience wrapper for VMR3ReqCallU. + * + * This assumes (1) you're calling a function that returns void, (2) that you + * wish to wait for ever for it to return, and (3) that it's priority request + * that can be safely be handled during async suspend and power off. + * + * @returns VBox status code of VMR3ReqCallVU. + * + * @param pDevIns The device instance. + * @param idDstCpu The destination CPU(s). Either a specific CPU ID or + * one of the following special values: + * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param Args Argument vector. + * + * @remarks See remarks on VMR3ReqCallVU. + */ + DECLR3CALLBACKMEMBER(int, pfnVMReqPriorityCallWaitV,(PPDMDEVINS pDevIns, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, va_list Args)); + + /** + * Stops the VM and enters the debugger to look at the guest state. + * + * Use the PDMDeviceDBGFStop() inline function with the RT_SRC_POS macro instead of + * invoking this function directly. + * + * @returns VBox status code which must be passed up to the VMM. + * @param pDevIns The device instance. + * @param pszFile Filename of the assertion location. + * @param iLine The linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + * @param pszFormat Message. (optional) + * @param args Message parameters. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFStopV,(PPDMDEVINS pDevIns, const char *pszFile, unsigned iLine, const char *pszFunction, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(5, 0)); + + /** + * Register a info handler with DBGF. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszName The identifier of the info. + * @param pszDesc The description of the info and any arguments + * the handler may take. + * @param pfnHandler The handler function to be called to display the + * info. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoRegister,(PPDMDEVINS pDevIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDEV pfnHandler)); + + /** + * Register a info handler with DBGF, argv style. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszName The identifier of the info. + * @param pszDesc The description of the info and any arguments + * the handler may take. + * @param pfnHandler The handler function to be called to display the + * info. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoRegisterArgv,(PPDMDEVINS pDevIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDEV pfnHandler)); + + /** + * Registers a set of registers for a device. + * + * The @a pvUser argument of the getter and setter callbacks will be + * @a pDevIns. The register names will be prefixed by the device name followed + * immediately by the instance number. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param paRegisters The register descriptors. + * + * @remarks The device critical section is NOT entered prior to working the + * callbacks registered via this helper! + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFRegRegister,(PPDMDEVINS pDevIns, PCDBGFREGDESC paRegisters)); + + /** + * Gets the trace buffer handle. + * + * This is used by the macros found in VBox/vmm/dbgftrace.h and is not + * really inteded for direct usage, thus no inline wrapper function. + * + * @returns Trace buffer handle or NIL_RTTRACEBUF. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(RTTRACEBUF, pfnDBGFTraceBuf,(PPDMDEVINS pDevIns)); + + /** + * Report a bug check. + * + * @returns + * @param pDevIns The device instance. + * @param enmEvent The kind of BSOD event this is. + * @param uBugCheck The bug check number. + * @param uP1 The bug check parameter \#1. + * @param uP2 The bug check parameter \#2. + * @param uP3 The bug check parameter \#3. + * @param uP4 The bug check parameter \#4. + * + * @thread EMT + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnDBGFReportBugCheck,(PPDMDEVINS pDevIns, DBGFEVENTTYPE enmEvent, uint64_t uBugCheck, + uint64_t uP1, uint64_t uP2, uint64_t uP3, uint64_t uP4)); + + /** + * Write core dump of the guest. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszFilename The name of the file to which the guest core + * dump should be written. + * @param fReplaceFile Whether to replace the file or not. + * + * @remarks The VM may need to be suspended before calling this function in + * order to truly stop all device threads and drivers. This function + * only synchronizes EMTs. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFCoreWrite,(PPDMDEVINS pDevIns, const char *pszFilename, bool fReplaceFile)); + + /** + * Gets the logger info helper. + * The returned info helper will unconditionally write all output to the log. + * + * @returns Pointer to the logger info helper. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PCDBGFINFOHLP, pfnDBGFInfoLogHlp,(PPDMDEVINS pDevIns)); + + /** + * Queries a 64-bit register value. + * + * @retval VINF_SUCCESS + * @retval VERR_INVALID_VM_HANDLE + * @retval VERR_INVALID_CPU_ID + * @retval VERR_DBGF_REGISTER_NOT_FOUND + * @retval VERR_DBGF_UNSUPPORTED_CAST + * @retval VINF_DBGF_TRUNCATED_REGISTER + * @retval VINF_DBGF_ZERO_EXTENDED_REGISTER + * + * @param pDevIns The device instance. + * @param idDefCpu The default target CPU ID, VMCPUID_ANY if not + * applicable. Can be OR'ed with + * DBGFREG_HYPER_VMCPUID. + * @param pszReg The register that's being queried. Except for + * CPU registers, this must be on the form + * "set.reg[.sub]". + * @param pu64 Where to store the register value. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFRegNmQueryU64,(PPDMDEVINS pDevIns, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64)); + + /** + * Format a set of registers. + * + * This is restricted to registers from one CPU, that specified by @a idCpu. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param idCpu The CPU ID of any CPU registers that may be + * printed, pass VMCPUID_ANY if not applicable. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pszFormat The format string. Register names are given by + * %VR{name}, they take no arguments. + * @param va Other format arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFRegPrintfV,(PPDMDEVINS pDevIns, VMCPUID idCpu, char *pszBuf, size_t cbBuf, + const char *pszFormat, va_list va)); + + /** + * Registers a statistics sample. + * + * @param pDevIns Device instance of the DMA. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is + * pointing at. + * @param pszName Sample name, unix path style. If this does not + * start with a '/', the default prefix will be + * prepended, otherwise it will be used as-is. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegister,(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, const char *pszName, STAMUNIT enmUnit, const char *pszDesc)); + + /** + * Same as pfnSTAMRegister except that the name is specified in a + * RTStrPrintfV like fashion. + * + * @returns VBox status. + * @param pDevIns Device instance of the DMA. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is + * pointing at. + * @param enmVisibility Visibility type specifying whether unused + * statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName Sample name format string, unix path style. If + * this does not start with a '/', the default + * prefix will be prepended, otherwise it will be + * used as-is. + * @param args Arguments to the format string. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegisterV,(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, + STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszDesc, + const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(7, 0)); + + /** + * Registers a PCI device with the default PCI bus. + * + * If a PDM device has more than one PCI device, they must be registered in the + * order of PDMDEVINSR3::apPciDevs. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. + * This must be kept in the instance data. + * The PCI configuration must be initialized before registration. + * @param fFlags 0, PDMPCIDEVREG_F_PCI_BRIDGE or + * PDMPCIDEVREG_F_NOT_MANDATORY_NO. + * @param uPciDevNo PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, + * PDMPCIDEVREG_DEV_NO_SAME_AS_PREV, or a specific + * device number (0-31). This will be ignored if + * the CFGM configuration contains a PCIDeviceNo + * value. + * @param uPciFunNo PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, or a specific + * function number (0-7). This will be ignored if + * the CFGM configuration contains a PCIFunctionNo + * value. + * @param pszName Device name, if NULL PDMDEVREG::szName is used. + * The pointer is saved, so don't free or changed. + * @note The PCI device configuration is now implicit from the apPciDevs + * index, meaning that the zero'th entry is the primary one and + * subsequent uses CFGM subkeys "PciDev1", "PciDev2" and so on. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIRegister,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags, + uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName)); + + /** + * Initialize MSI or MSI-X emulation support for the given PCI device. + * + * @see PDMPCIBUSREG::pfnRegisterMsiR3 for details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device. NULL is an alias for the first + * one registered. + * @param pMsiReg MSI emulation registration structure. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIRegisterMsi,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg)); + + /** + * Registers a I/O region (memory mapped or I/O ports) for a PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param enmType PCI_ADDRESS_SPACE_MEM, PCI_ADDRESS_SPACE_IO or PCI_ADDRESS_SPACE_MEM_PREFETCH. + * @param fFlags PDMPCIDEV_IORGN_F_XXX. + * @param hHandle An I/O port, MMIO or MMIO2 handle according to + * @a fFlags, UINT64_MAX if no handle is passed + * (old style). + * @param pfnMapUnmap Callback for doing the mapping, optional when a + * handle is specified. The callback will be + * invoked holding only the PDM lock. The device + * lock will _not_ be taken (due to lock order). + */ + DECLR3CALLBACKMEMBER(int, pfnPCIIORegionRegister,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, uint32_t fFlags, + uint64_t hHandle, PFNPCIIOREGIONMAP pfnMapUnmap)); + + /** + * Register PCI configuration space read/write callbacks. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param pfnRead Pointer to the user defined PCI config read function. + * to call default PCI config read function. Can be NULL. + * @param pfnWrite Pointer to the user defined PCI config write function. + * @remarks The callbacks will be invoked holding the PDM lock. The device lock + * is NOT take because that is very likely be a lock order violation. + * @thread EMT(0) + * @note Only callable during VM creation. + * @sa PDMDevHlpPCIConfigRead, PDMDevHlpPCIConfigWrite + */ + DECLR3CALLBACKMEMBER(int, pfnPCIInterceptConfigAccesses,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + PFNPCICONFIGREAD pfnRead, PFNPCICONFIGWRITE pfnWrite)); + + /** + * Perform a PCI configuration space write. + * + * This is for devices that make use of PDMDevHlpPCIInterceptConfigAccesses(). + * + * @returns Strict VBox status code (mainly DBGFSTOP). + * @param pDevIns The device instance. + * @param pPciDev The PCI device which config space is being read. + * @param uAddress The config space address. + * @param cb The size of the read: 1, 2 or 4 bytes. + * @param u32Value The value to write. + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnPCIConfigWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t u32Value)); + + /** + * Perform a PCI configuration space read. + * + * This is for devices that make use of PDMDevHlpPCIInterceptConfigAccesses(). + * + * @returns Strict VBox status code (mainly DBGFSTOP). + * @param pDevIns The device instance. + * @param pPciDev The PCI device which config space is being read. + * @param uAddress The config space address. + * @param cb The size of the read: 1, 2 or 4 bytes. + * @param pu32Value Where to return the value. + */ + DECLR3CALLBACKMEMBER(VBOXSTRICTRC, pfnPCIConfigRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t *pu32Value)); + + /** + * Bus master physical memory read. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Bus master physical memory write. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Requests the mapping of a guest page into ring-3 in preparation for a bus master + * physical memory write operation. + * + * Refer pfnPhysGCPhys2CCPtr() for further details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys The guest physical address of the page that should be + * mapped. + * @param fFlags Flags reserved for future use, MBZ. + * @param ppv Where to store the address corresponding to GCPhys. + * @param pLock Where to store the lock information that + * pfnPhysReleasePageMappingLock needs. + * + * @remarks Avoid calling this API from within critical sections (other than the PGM + * one) because of the deadlock risk when we have to delegating the task to + * an EMT. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysGCPhys2CCPtr,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, uint32_t fFlags, + void **ppv, PPGMPAGEMAPLOCK pLock)); + + /** + * Requests the mapping of a guest page into ring-3, external threads, in prepartion + * for a bus master physical memory read operation. + * + * Refer pfnPhysGCPhys2CCPtrReadOnly() for further details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys The guest physical address of the page that + * should be mapped. + * @param fFlags Flags reserved for future use, MBZ. + * @param ppv Where to store the address corresponding to + * GCPhys. + * @param pLock Where to store the lock information that + * pfnPhysReleasePageMappingLock needs. + * + * @remarks Avoid calling this API from within critical sections. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysGCPhys2CCPtrReadOnly,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + uint32_t fFlags, void const **ppv, PPGMPAGEMAPLOCK pLock)); + + /** + * Requests the mapping of multiple guest pages into ring-3 in prepartion for a bus + * master physical memory write operation. + * + * When you're done with the pages, call pfnPhysBulkReleasePageMappingLocks() + * ASAP to release them. + * + * Refer pfnPhysBulkGCPhys2CCPtr() for further details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param cPages Number of pages to lock. + * @param paGCPhysPages The guest physical address of the pages that + * should be mapped (@a cPages entries). + * @param fFlags Flags reserved for future use, MBZ. + * @param papvPages Where to store the ring-3 mapping addresses + * corresponding to @a paGCPhysPages. + * @param paLocks Where to store the locking information that + * pfnPhysBulkReleasePageMappingLock needs (@a cPages + * in length). + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysBulkGCPhys2CCPtr,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t cPages, + PCRTGCPHYS paGCPhysPages, uint32_t fFlags, void **papvPages, + PPGMPAGEMAPLOCK paLocks)); + + /** + * Requests the mapping of multiple guest pages into ring-3 in preparation for a bus + * master physical memory read operation. + * + * When you're done with the pages, call pfnPhysBulkReleasePageMappingLocks() + * ASAP to release them. + * + * Refer pfnPhysBulkGCPhys2CCPtrReadOnly() for further details. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param cPages Number of pages to lock. + * @param paGCPhysPages The guest physical address of the pages that + * should be mapped (@a cPages entries). + * @param fFlags Flags reserved for future use, MBZ. + * @param papvPages Where to store the ring-3 mapping addresses + * corresponding to @a paGCPhysPages. + * @param paLocks Where to store the lock information that + * pfnPhysReleasePageMappingLock needs (@a cPages + * in length). + */ + DECLR3CALLBACKMEMBER(int, pfnPCIPhysBulkGCPhys2CCPtrReadOnly,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t cPages, + PCRTGCPHYS paGCPhysPages, uint32_t fFlags, + void const **papvPages, PPGMPAGEMAPLOCK paLocks)); + + /** + * Sets the IRQ for the given PCI device. + * + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)); + + /** + * Sets the IRQ for the given PCI device, but doesn't wait for EMT to process + * the request when not called from EMT. + * + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnPCISetIrqNoWait,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)); + + /** + * Set ISA IRQ for a device. + * + * @param pDevIns The device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnISASetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Set the ISA IRQ for a device, but don't wait for EMT to process + * the request when not called from EMT. + * + * @param pDevIns The device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnISASetIrqNoWait,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Attaches a driver (chain) to the device. + * + * The first call for a LUN this will serve as a registration of the LUN. The pBaseInterface and + * the pszDesc string will be registered with that LUN and kept around for PDMR3QueryDeviceLun(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iLun The logical unit to attach. + * @param pBaseInterface Pointer to the base interface for that LUN. (device side / down) + * @param ppBaseInterface Where to store the pointer to the base interface. (driver side / up) + * @param pszDesc Pointer to a string describing the LUN. This string must remain valid + * for the live of the device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverAttach,(PPDMDEVINS pDevIns, uint32_t iLun, PPDMIBASE pBaseInterface, + PPDMIBASE *ppBaseInterface, const char *pszDesc)); + + /** + * Detaches an attached driver (chain) from the device again. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pDrvIns The driver instance to detach. + * @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverDetach,(PPDMDEVINS pDevIns, PPDMDRVINS pDrvIns, uint32_t fFlags)); + + /** + * Reconfigures the driver chain for a LUN, detaching any driver currently + * present there. + * + * Caller will have attach it, of course. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iLun The logical unit to reconfigure. + * @param cDepth The depth of the driver chain. Determins the + * size of @a papszDrivers and @a papConfigs. + * @param papszDrivers The names of the drivers to configure in the + * chain, first entry is the one immediately + * below the device/LUN + * @param papConfigs The configurations for each of the drivers + * in @a papszDrivers array. NULL entries + * corresponds to empty 'Config' nodes. This + * function will take ownership of non-NULL + * CFGM sub-trees and set the array member to + * NULL, so the caller can do cleanups on + * failure. This parameter is optional. + * @param fFlags Reserved, MBZ. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverReconfigure,(PPDMDEVINS pDevIns, uint32_t iLun, uint32_t cDepth, + const char * const *papszDrivers, PCFGMNODE *papConfigs, uint32_t fFlags)); + + /** @name Exported PDM Queue Functions + * @{ */ + /** + * Create a queue. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param cbItem The size of a queue item. + * @param cItems The number of items in the queue. + * @param cMilliesInterval The number of milliseconds between polling the queue. + * If 0 then the emulation thread will be notified whenever an item arrives. + * @param pfnCallback The consumer function. + * @param fRZEnabled Set if the queue should work in RC and R0. + * @param pszName The queue base name. The instance number will be + * appended automatically. + * @param phQueue Where to store the queue handle on success. + * @thread EMT(0) + * @remarks The device critical section will NOT be entered before calling the + * callback. No locks will be held, but for now it's safe to assume + * that only one EMT will do queue callbacks at any one time. + */ + DECLR3CALLBACKMEMBER(int, pfnQueueCreate,(PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, const char *pszName, + PDMQUEUEHANDLE *phQueue)); + + DECLR3CALLBACKMEMBER(PPDMQUEUEITEMCORE, pfnQueueAlloc,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)); + DECLR3CALLBACKMEMBER(int, pfnQueueInsert,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)); + DECLR3CALLBACKMEMBER(bool, pfnQueueFlushIfNecessary,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)); + /** @} */ + + /** @name PDM Task + * @{ */ + /** + * Create an asynchronous ring-3 task. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param fFlags PDMTASK_F_XXX + * @param pszName The function name or similar. Used for statistics, + * so no slashes. + * @param pfnCallback The task function. + * @param pvUser User argument for the task function. + * @param phTask Where to return the task handle. + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnTaskCreate,(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszName, + PFNPDMTASKDEV pfnCallback, void *pvUser, PDMTASKHANDLE *phTask)); + /** + * Triggers the running the given task. + * + * @returns VBox status code. + * @retval VINF_ALREADY_POSTED is the task is already pending. + * @param pDevIns The device instance. + * @param hTask The task to trigger. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnTaskTrigger,(PPDMDEVINS pDevIns, PDMTASKHANDLE hTask)); + /** @} */ + + /** @name SUP Event Semaphore Wrappers (single release / auto reset) + * These semaphores can be signalled from ring-0. + * @{ */ + /** @sa SUPSemEventCreate */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventCreate,(PPDMDEVINS pDevIns, PSUPSEMEVENT phEvent)); + /** @sa SUPSemEventClose */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventClose,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent)); + /** @sa SUPSemEventSignal */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventSignal,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent)); + /** @sa SUPSemEventWaitNoResume */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventWaitNoResume,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint32_t cMillies)); + /** @sa SUPSemEventWaitNsAbsIntr */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventWaitNsAbsIntr,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t uNsTimeout)); + /** @sa SUPSemEventWaitNsRelIntr */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventWaitNsRelIntr,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t cNsTimeout)); + /** @sa SUPSemEventGetResolution */ + DECLR3CALLBACKMEMBER(uint32_t, pfnSUPSemEventGetResolution,(PPDMDEVINS pDevIns)); + /** @} */ + + /** @name SUP Multi Event Semaphore Wrappers (multiple release / manual reset) + * These semaphores can be signalled from ring-0. + * @{ */ + /** @sa SUPSemEventMultiCreate */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiCreate,(PPDMDEVINS pDevIns, PSUPSEMEVENTMULTI phEventMulti)); + /** @sa SUPSemEventMultiClose */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiClose,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiSignal */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiSignal,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiReset */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiReset,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiWaitNoResume */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNoResume,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies)); + /** @sa SUPSemEventMultiWaitNsAbsIntr */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNsAbsIntr,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t uNsTimeout)); + /** @sa SUPSemEventMultiWaitNsRelIntr */ + DECLR3CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNsRelIntr,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t cNsTimeout)); + /** @sa SUPSemEventMultiGetResolution */ + DECLR3CALLBACKMEMBER(uint32_t, pfnSUPSemEventMultiGetResolution,(PPDMDEVINS pDevIns)); + /** @} */ + + /** + * Initializes a PDM critical section. + * + * The PDM critical sections are derived from the IPRT critical sections, but + * works in RC and R0 as well. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect Pointer to the critical section. + * @param SRC_POS Use RT_SRC_POS. + * @param pszNameFmt Format string for naming the critical section. + * For statistics and lock validation. + * @param va Arguments for the format string. + */ + DECLR3CALLBACKMEMBER(int, pfnCritSectInit,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * Gets the NOP critical section. + * + * @returns The ring-3 address of the NOP critical section. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PPDMCRITSECT, pfnCritSectGetNop,(PPDMDEVINS pDevIns)); + + /** + * Changes the device level critical section from the automatically created + * default to one desired by the device constructor. + * + * For ring-0 and raw-mode capable devices, the call must be repeated in each of + * the additional contexts. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect The critical section to use. NULL is not + * valid, instead use the NOP critical + * section. + */ + DECLR3CALLBACKMEMBER(int, pfnSetDeviceCritSect,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCritSectYield,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectScheduleExitEvent,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)); + DECLR3CALLBACKMEMBER(int, pfnCritSectDelete,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + /** @} */ + + /** @name Exported PDM Read/Write Critical Section Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnCritSectRwInit,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwDelete,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR3CALLBACKMEMBER(int, pfnCritSectRwEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwTryEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwTryEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwLeaveShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR3CALLBACKMEMBER(int, pfnCritSectRwEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwTryEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwTryEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectRwLeaveExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR3CALLBACKMEMBER(bool, pfnCritSectRwIsWriteOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectRwIsReadOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, bool fWannaHear)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriteRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriterReadRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectRwGetReadCount,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectRwIsInitialized,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + /** @} */ + + /** + * Creates a PDM thread. + * + * This differs from the RTThreadCreate() API in that PDM takes care of suspending, + * resuming, and destroying the thread as the VM state changes. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param ppThread Where to store the thread 'handle'. + * @param pvUser The user argument to the thread function. + * @param pfnThread The thread function. + * @param pfnWakeup The wakup callback. This is called on the EMT + * thread when a state change is pending. + * @param cbStack See RTThreadCreate. + * @param enmType See RTThreadCreate. + * @param pszName See RTThreadCreate. + * @remarks The device critical section will NOT be entered prior to invoking + * the function pointers. + */ + DECLR3CALLBACKMEMBER(int, pfnThreadCreate,(PPDMDEVINS pDevIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDEV pfnThread, + PFNPDMTHREADWAKEUPDEV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)); + + /** @name Exported PDM Thread Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnThreadDestroy,(PPDMTHREAD pThread, int *pRcThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmSuspending,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmRunning,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadSleep,(PPDMTHREAD pThread, RTMSINTERVAL cMillies)); + DECLR3CALLBACKMEMBER(int, pfnThreadSuspend,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadResume,(PPDMTHREAD pThread)); + /** @} */ + + /** + * Set up asynchronous handling of a suspend, reset or power off notification. + * + * This shall only be called when getting the notification. It must be called + * for each one. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pfnAsyncNotify The callback. + * @thread EMT(0) + * @remarks The caller will enter the device critical section prior to invoking + * the callback. + */ + DECLR3CALLBACKMEMBER(int, pfnSetAsyncNotification, (PPDMDEVINS pDevIns, PFNPDMDEVASYNCNOTIFY pfnAsyncNotify)); + + /** + * Notify EMT(0) that the device has completed the asynchronous notification + * handling. + * + * This can be called at any time, spurious calls will simply be ignored. + * + * @param pDevIns The device instance. + * @thread Any + */ + DECLR3CALLBACKMEMBER(void, pfnAsyncNotificationCompleted, (PPDMDEVINS pDevIns)); + + /** + * Register the RTC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pRtcReg Pointer to a RTC registration structure. + * @param ppRtcHlp Where to store the pointer to the helper + * functions. + */ + DECLR3CALLBACKMEMBER(int, pfnRTCRegister,(PPDMDEVINS pDevIns, PCPDMRTCREG pRtcReg, PCPDMRTCHLP *ppRtcHlp)); + + /** + * Register a PCI Bus. + * + * @returns VBox status code, but the positive values 0..31 are used to indicate + * bus number rather than informational status codes. + * @param pDevIns The device instance. + * @param pPciBusReg Pointer to PCI bus registration structure. + * @param ppPciHlp Where to store the pointer to the PCI Bus + * helpers. + * @param piBus Where to return the PDM bus number. Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnPCIBusRegister,(PPDMDEVINS pDevIns, PPDMPCIBUSREGR3 pPciBusReg, + PCPDMPCIHLPR3 *ppPciHlp, uint32_t *piBus)); + + /** + * Register the IOMMU device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIommuReg Pointer to a IOMMU registration structure. + * @param ppIommuHlp Where to store the pointer to the ring-3 IOMMU + * helpers. + * @param pidxIommu Where to return the IOMMU index. Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnIommuRegister,(PPDMDEVINS pDevIns, PPDMIOMMUREGR3 pIommuReg, PCPDMIOMMUHLPR3 *ppIommuHlp, + uint32_t *pidxIommu)); + + /** + * Register the PIC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPicReg Pointer to a PIC registration structure. + * @param ppPicHlp Where to store the pointer to the ring-3 PIC + * helpers. + * @sa PDMDevHlpPICSetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnPICRegister,(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp)); + + /** + * Register the APIC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnApicRegister,(PPDMDEVINS pDevIns)); + + /** + * Register the I/O APIC device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIoApicReg Pointer to a I/O APIC registration structure. + * @param ppIoApicHlp Where to store the pointer to the IOAPIC + * helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnIoApicRegister,(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp)); + + /** + * Register the HPET device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pHpetReg Pointer to a HPET registration structure. + * @param ppHpetHlpR3 Where to store the pointer to the HPET + * helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnHpetRegister,(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, PCPDMHPETHLPR3 *ppHpetHlpR3)); + + /** + * Register a raw PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciRawReg Pointer to a raw PCI registration structure. + * @param ppPciRawHlpR3 Where to store the pointer to the raw PCI + * device helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnPciRawRegister,(PPDMDEVINS pDevIns, PPDMPCIRAWREG pPciRawReg, PCPDMPCIRAWHLPR3 *ppPciRawHlpR3)); + + /** + * Register the DMA device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pDmacReg Pointer to a DMAC registration structure. + * @param ppDmacHlp Where to store the pointer to the DMA helpers. + */ + DECLR3CALLBACKMEMBER(int, pfnDMACRegister,(PPDMDEVINS pDevIns, PPDMDMACREG pDmacReg, PCPDMDMACHLP *ppDmacHlp)); + + /** + * Register transfer function for DMA channel. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param uChannel Channel number. + * @param pfnTransferHandler Device specific transfer callback function. + * @param pvUser User pointer to pass to the callback. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnDMARegister,(PPDMDEVINS pDevIns, unsigned uChannel, PFNDMATRANSFERHANDLER pfnTransferHandler, void *pvUser)); + + /** + * Read memory. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param uChannel Channel number. + * @param pvBuffer Pointer to target buffer. + * @param off DMA position. + * @param cbBlock Block size. + * @param pcbRead Where to store the number of bytes which was + * read. optional. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnDMAReadMemory,(PPDMDEVINS pDevIns, unsigned uChannel, void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbRead)); + + /** + * Write memory. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param uChannel Channel number. + * @param pvBuffer Memory to write. + * @param off DMA position. + * @param cbBlock Block size. + * @param pcbWritten Where to store the number of bytes which was + * written. optional. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnDMAWriteMemory,(PPDMDEVINS pDevIns, unsigned uChannel, const void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbWritten)); + + /** + * Set the DREQ line. + * + * @returns VBox status code. + * @param pDevIns Device instance. + * @param uChannel Channel number. + * @param uLevel Level of the line. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnDMASetDREQ,(PPDMDEVINS pDevIns, unsigned uChannel, unsigned uLevel)); + + /** + * Get channel mode. + * + * @returns Channel mode. See specs. + * @param pDevIns The device instance. + * @param uChannel Channel number. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(uint8_t, pfnDMAGetChannelMode,(PPDMDEVINS pDevIns, unsigned uChannel)); + + /** + * Schedule DMA execution. + * + * @param pDevIns The device instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(void, pfnDMASchedule,(PPDMDEVINS pDevIns)); + + /** + * Write CMOS value and update the checksum(s). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iReg The CMOS register index. + * @param u8Value The CMOS register value. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnCMOSWrite,(PPDMDEVINS pDevIns, unsigned iReg, uint8_t u8Value)); + + /** + * Read CMOS value. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iReg The CMOS register index. + * @param pu8Value Where to store the CMOS register value. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnCMOSRead,(PPDMDEVINS pDevIns, unsigned iReg, uint8_t *pu8Value)); + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDevIns The device instance. + * @param pszFile Filename of the assertion location. + * @param iLine The linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMDEVINS pDevIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDevIns The device instance. + * @param pszFile Filename of the assertion location. + * @param iLine The linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertOther,(PPDMDEVINS pDevIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Resolves the symbol for a raw-mode context interface. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pvInterface The interface structure. + * @param cbInterface The size of the interface structure. + * @param pszSymPrefix What to prefix the symbols in the list with + * before resolving them. This must start with + * 'dev' and contain the driver name. + * @param pszSymList List of symbols corresponding to the interface. + * There is generally a there is generally a define + * holding this list associated with the interface + * definition (INTERFACE_SYM_LIST). For more + * details see PDMR3LdrGetInterfaceSymbols. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnLdrGetRCInterfaceSymbols,(PPDMDEVINS pDevIns, void *pvInterface, size_t cbInterface, + const char *pszSymPrefix, const char *pszSymList)); + + /** + * Resolves the symbol for a ring-0 context interface. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pvInterface The interface structure. + * @param cbInterface The size of the interface structure. + * @param pszSymPrefix What to prefix the symbols in the list with + * before resolving them. This must start with + * 'dev' and contain the driver name. + * @param pszSymList List of symbols corresponding to the interface. + * There is generally a there is generally a define + * holding this list associated with the interface + * definition (INTERFACE_SYM_LIST). For more + * details see PDMR3LdrGetInterfaceSymbols. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnLdrGetR0InterfaceSymbols,(PPDMDEVINS pDevIns, void *pvInterface, size_t cbInterface, + const char *pszSymPrefix, const char *pszSymList)); + + /** + * Calls the PDMDEVREGR0::pfnRequest callback (in ring-0 context). + * + * @returns VBox status code. + * @retval VERR_INVALID_FUNCTION if the callback member is NULL. + * @retval VERR_ACCESS_DENIED if the device isn't ring-0 capable. + * + * @param pDevIns The device instance. + * @param uOperation The operation to perform. + * @param u64Arg 64-bit integer argument. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnCallR0,(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg)); + + /** + * Gets the reason for the most recent VM suspend. + * + * @returns The suspend reason. VMSUSPENDREASON_INVALID is returned if no + * suspend has been made or if the pDevIns is invalid. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(VMSUSPENDREASON, pfnVMGetSuspendReason,(PPDMDEVINS pDevIns)); + + /** + * Gets the reason for the most recent VM resume. + * + * @returns The resume reason. VMRESUMEREASON_INVALID is returned if no + * resume has been made or if the pDevIns is invalid. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(VMRESUMEREASON, pfnVMGetResumeReason,(PPDMDEVINS pDevIns)); + + /** + * Requests the mapping of multiple guest page into ring-3. + * + * When you're done with the pages, call pfnPhysBulkReleasePageMappingLocks() + * ASAP to release them. + * + * This API will assume your intention is to write to the pages, and will + * therefore replace shared and zero pages. If you do not intend to modify the + * pages, use the pfnPhysBulkGCPhys2CCPtrReadOnly() API. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PGM_PHYS_PAGE_RESERVED if any of the pages has no physical + * backing or if any of the pages the page has any active access + * handlers. The caller must fall back on using PGMR3PhysWriteExternal. + * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if @a paGCPhysPages contains + * an invalid physical address. + * + * @param pDevIns The device instance. + * @param cPages Number of pages to lock. + * @param paGCPhysPages The guest physical address of the pages that + * should be mapped (@a cPages entries). + * @param fFlags Flags reserved for future use, MBZ. + * @param papvPages Where to store the ring-3 mapping addresses + * corresponding to @a paGCPhysPages. + * @param paLocks Where to store the locking information that + * pfnPhysBulkReleasePageMappingLock needs (@a cPages + * in length). + * + * @remark Avoid calling this API from within critical sections (other than the + * PGM one) because of the deadlock risk when we have to delegating the + * task to an EMT. + * @thread Any. + * @since 6.0.6 + */ + DECLR3CALLBACKMEMBER(int, pfnPhysBulkGCPhys2CCPtr,(PPDMDEVINS pDevIns, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + uint32_t fFlags, void **papvPages, PPGMPAGEMAPLOCK paLocks)); + + /** + * Requests the mapping of multiple guest page into ring-3, for reading only. + * + * When you're done with the pages, call pfnPhysBulkReleasePageMappingLocks() + * ASAP to release them. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_PGM_PHYS_PAGE_RESERVED if any of the pages has no physical + * backing or if any of the pages the page has an active ALL access + * handler. The caller must fall back on using PGMR3PhysWriteExternal. + * @retval VERR_PGM_INVALID_GC_PHYSICAL_ADDRESS if @a paGCPhysPages contains + * an invalid physical address. + * + * @param pDevIns The device instance. + * @param cPages Number of pages to lock. + * @param paGCPhysPages The guest physical address of the pages that + * should be mapped (@a cPages entries). + * @param fFlags Flags reserved for future use, MBZ. + * @param papvPages Where to store the ring-3 mapping addresses + * corresponding to @a paGCPhysPages. + * @param paLocks Where to store the lock information that + * pfnPhysReleasePageMappingLock needs (@a cPages + * in length). + * + * @remark Avoid calling this API from within critical sections. + * @thread Any. + * @since 6.0.6 + */ + DECLR3CALLBACKMEMBER(int, pfnPhysBulkGCPhys2CCPtrReadOnly,(PPDMDEVINS pDevIns, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + uint32_t fFlags, void const **papvPages, PPGMPAGEMAPLOCK paLocks)); + + /** + * Release the mappings of multiple guest pages. + * + * This is the counter part of pfnPhysBulkGCPhys2CCPtr and + * pfnPhysBulkGCPhys2CCPtrReadOnly. + * + * @param pDevIns The device instance. + * @param cPages Number of pages to unlock. + * @param paLocks The lock structures initialized by the mapping + * function (@a cPages in length). + * @thread Any. + * @since 6.0.6 + */ + DECLR3CALLBACKMEMBER(void, pfnPhysBulkReleasePageMappingLocks,(PPDMDEVINS pDevIns, uint32_t cPages, PPGMPAGEMAPLOCK paLocks)); + + /** + * Returns the micro architecture used for the guest. + * + * @returns CPU micro architecture enum. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(CPUMMICROARCH, pfnCpuGetGuestMicroarch,(PPDMDEVINS pDevIns)); + + /** + * Get the number of physical and linear address bits supported by the guest. + * + * @param pDevIns The device instance. + * @param pcPhysAddrWidth Where to store the number of physical address bits + * supported by the guest. + * @param pcLinearAddrWidth Where to store the number of linear address bits + * supported by the guest. + */ + DECLR3CALLBACKMEMBER(void, pfnCpuGetGuestAddrWidths,(PPDMDEVINS pDevIns, uint8_t *pcPhysAddrWidth, + uint8_t *pcLinearAddrWidth)); + + /** + * Gets the scalable bus frequency. + * + * The bus frequency is used as a base in several MSRs that gives the CPU and + * other frequency ratios. + * + * @returns Scalable bus frequency in Hz. Will not return CPUM_SBUSFREQ_UNKNOWN. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnCpuGetGuestScalableBusFrequency,(PPDMDEVINS pDevIns)); + + /** Space reserved for future members. + * @{ */ + /** + * Deregister zero or more samples given their name prefix. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszPrefix The name prefix of the samples to remove. If this does + * not start with a '/', the default prefix will be + * prepended, otherwise it will be used as-is. + */ + DECLR3CALLBACKMEMBER(int, pfnSTAMDeregisterByPrefix,(PPDMDEVINS pDevIns, const char *pszPrefix)); + DECLR3CALLBACKMEMBER(void, pfnReserved2,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved3,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved4,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved5,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved6,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved7,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved8,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved9,(void)); + DECLR3CALLBACKMEMBER(void, pfnReserved10,(void)); + /** @} */ + + + /** API available to trusted devices only. + * + * These APIs are providing unrestricted access to the guest and the VM, + * or they are interacting intimately with PDM. + * + * @{ + */ + + /** + * Gets the user mode VM handle. Restricted API. + * + * @returns User mode VM Handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PUVM, pfnGetUVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the global VM handle. Restricted API. + * + * @returns VM Handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PVMCC, pfnGetVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the VMCPU handle. Restricted API. + * + * @returns VMCPU Handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PVMCPU, pfnGetVMCPU,(PPDMDEVINS pDevIns)); + + /** + * The the VM CPU ID of the current thread (restricted API). + * + * @returns The VMCPUID of the calling thread, NIL_VMCPUID if not EMT. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(VMCPUID, pfnGetCurrentCpuId,(PPDMDEVINS pDevIns)); + + /** + * Registers the VMM device heap or notifies about mapping/unmapping. + * + * This interface serves three purposes: + * + * -# Register the VMM device heap during device construction + * for the HM to use. + * -# Notify PDM/HM that it's mapped into guest address + * space (i.e. usable). + * -# Notify PDM/HM that it is being unmapped from the guest + * address space (i.e. not usable). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The physical address if mapped, NIL_RTGCPHYS if + * not mapped. + * @param pvHeap Ring 3 heap pointer. + * @param cbHeap Size of the heap. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnRegisterVMMDevHeap,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbHeap)); + + /** + * Registers the firmware (BIOS, EFI) device with PDM. + * + * The firmware provides a callback table and gets a special PDM helper table. + * There can only be one firmware device for a VM. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pFwReg Firmware registration structure. + * @param ppFwHlp Where to return the firmware helper structure. + * @remarks Only valid during device construction. + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnFirmwareRegister,(PPDMDEVINS pDevIns, PCPDMFWREG pFwReg, PCPDMFWHLPR3 *ppFwHlp)); + + /** + * Resets the VM. + * + * @returns The appropriate VBox status code to pass around on reset. + * @param pDevIns The device instance. + * @param fFlags PDMVMRESET_F_XXX flags. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVMReset,(PPDMDEVINS pDevIns, uint32_t fFlags)); + + /** + * Suspends the VM. + * + * @returns The appropriate VBox status code to pass around on suspend. + * @param pDevIns The device instance. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSuspend,(PPDMDEVINS pDevIns)); + + /** + * Suspends, saves and powers off the VM. + * + * @returns The appropriate VBox status code to pass around. + * @param pDevIns The device instance. + * @thread An emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSuspendSaveAndPowerOff,(PPDMDEVINS pDevIns)); + + /** + * Power off the VM. + * + * @returns The appropriate VBox status code to pass around on power off. + * @param pDevIns The device instance. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVMPowerOff,(PPDMDEVINS pDevIns)); + + /** + * Checks if the Gate A20 is enabled or not. + * + * @returns true if A20 is enabled. + * @returns false if A20 is disabled. + * @param pDevIns The device instance. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnA20IsEnabled,(PPDMDEVINS pDevIns)); + + /** + * Enables or disables the Gate A20. + * + * @param pDevIns The device instance. + * @param fEnable Set this flag to enable the Gate A20; clear it + * to disable. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnA20Set,(PPDMDEVINS pDevIns, bool fEnable)); + + /** + * Get the specified CPUID leaf for the virtual CPU associated with the calling + * thread. + * + * @param pDevIns The device instance. + * @param iLeaf The CPUID leaf to get. + * @param pEax Where to store the EAX value. + * @param pEbx Where to store the EBX value. + * @param pEcx Where to store the ECX value. + * @param pEdx Where to store the EDX value. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(void, pfnGetCpuId,(PPDMDEVINS pDevIns, uint32_t iLeaf, uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx)); + + /** + * Gets the main execution engine for the VM. + * + * @returns VM_EXEC_ENGINE_XXX + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint8_t, pfnGetMainExecutionEngine,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM. The clock frequency must be + * queried separately. + * + * @returns Current clock time. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGet,(PPDMDEVINS pDevIns)); + + /** + * Get the frequency of the virtual clock. + * + * @returns The clock frequency (not variable at run-time). + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetFreq,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM, in nanoseconds. + * + * @returns Current clock time (in ns). + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetNano,(PPDMDEVINS pDevIns)); + + /** + * Get the timestamp frequency. + * + * @returns Number of ticks per second. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMCpuTicksPerSecond,(PPDMDEVINS pDevIns)); + + /** + * Gets the support driver session. + * + * This is intended for working with the semaphore API. + * + * @returns Support driver session handle. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(PSUPDRVSESSION, pfnGetSupDrvSession,(PPDMDEVINS pDevIns)); + + /** + * Queries a generic object from the VMM user. + * + * @returns Pointer to the object if found, NULL if not. + * @param pDevIns The device instance. + * @param pUuid The UUID of what's being queried. The UUIDs and + * the usage conventions are defined by the user. + * + * @note It is strictly forbidden to call this internally in VBox! This + * interface is exclusively for hacks in externally developed devices. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryGenericUserObject,(PPDMDEVINS pDevIns, PCRTUUID pUuid)); + + /** + * Register a physical page access handler type. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param enmKind The kind of access handler. + * @param pfnHandler Pointer to the ring-3 handler callback. + * @param pszDesc The type description. + * @param phType Where to return the type handle (cross context safe). + * @sa PDMDevHlpPGMHandlerPhysicalTypeSetUpContext + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalTypeRegister, (PPDMDEVINS pDevIns, PGMPHYSHANDLERKIND enmKind, + PFNPGMPHYSHANDLER pfnHandler, + const char *pszDesc, PPGMPHYSHANDLERTYPE phType)); + + /** + * Register a access handler for a physical range. + * + * @returns VBox status code. + * @retval VINF_SUCCESS when successfully installed. + * @retval VINF_PGM_GCPHYS_ALIASED when the shadow PTs could be updated because + * the guest page aliased or/and mapped by multiple PTs. A CR3 sync has been + * flagged together with a pool clearing. + * @retval VERR_PGM_HANDLER_PHYSICAL_CONFLICT if the range conflicts with an existing + * one. A debug assertion is raised. + * + * @param pDevIns The device instance. + * @param GCPhys Start physical address. + * @param GCPhysLast Last physical address. (inclusive) + * @param hType The handler type registration handle. + * @param pszDesc Description of this handler. If NULL, the type + * description will be used instead. + * @note There is no @a uUser argument, because it will be set to the pDevIns + * in the context the handler is called. + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalRegister, (PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, + PGMPHYSHANDLERTYPE hType, R3PTRTYPE(const char *) pszDesc)); + + /** + * Deregister a physical page access handler. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys Start physical address. + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalDeregister,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)); + + /** + * Temporarily turns off the access monitoring of a page within a monitored + * physical write/all page access handler region. + * + * Use this when no further \#PFs are required for that page. Be aware that + * a page directory sync might reset the flags, and turn on access monitoring + * for the page. + * + * The caller must do required page table modifications. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The start address of the access handler. This + * must be a fully page aligned range or we risk + * messing up other handlers installed for the + * start and end pages. + * @param GCPhysPage The physical address of the page to turn off + * access monitoring for. + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalPageTempOff,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage)); + + /** + * Resets any modifications to individual pages in a physical page access + * handler region. + * + * This is used in pair with PGMHandlerPhysicalPageTempOff(), + * PGMHandlerPhysicalPageAliasMmio2() or PGMHandlerPhysicalPageAliasHC(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The start address of the handler regions, i.e. what you + * passed to PGMR3HandlerPhysicalRegister(), + * PGMHandlerPhysicalRegisterEx() or + * PGMHandlerPhysicalModify(). + */ + DECLR3CALLBACKMEMBER(int, pfnPGMHandlerPhysicalReset,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys)); + + /** + * Registers the guest memory range that can be used for patching. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPtrPatchMem Patch memory range. + * @param cbPatchMem Size of the memory range. + */ + DECLR3CALLBACKMEMBER(int, pfnVMMRegisterPatchMemory, (PPDMDEVINS pDevIns, RTGCPTR GCPtrPatchMem, uint32_t cbPatchMem)); + + /** + * Deregisters the guest memory range that can be used for patching. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPtrPatchMem Patch memory range. + * @param cbPatchMem Size of the memory range. + */ + DECLR3CALLBACKMEMBER(int, pfnVMMDeregisterPatchMemory, (PPDMDEVINS pDevIns, RTGCPTR GCPtrPatchMem, uint32_t cbPatchMem)); + + /** + * Registers a new shared module for the VM + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param enmGuestOS Guest OS type. + * @param pszModuleName Module name. + * @param pszVersion Module version. + * @param GCBaseAddr Module base address. + * @param cbModule Module size. + * @param cRegions Number of shared region descriptors. + * @param paRegions Shared region(s). + */ + DECLR3CALLBACKMEMBER(int, pfnSharedModuleRegister,(PPDMDEVINS pDevIns, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule, + uint32_t cRegions, VMMDEVSHAREDREGIONDESC const *paRegions)); + + /** + * Unregisters a shared module for the VM + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszModuleName Module name. + * @param pszVersion Module version. + * @param GCBaseAddr Module base address. + * @param cbModule Module size. + */ + DECLR3CALLBACKMEMBER(int, pfnSharedModuleUnregister,(PPDMDEVINS pDevIns, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule)); + + /** + * Query the state of a page in a shared module + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPtrPage Page address. + * @param pfShared Shared status (out). + * @param pfPageFlags Page flags (out). + */ + DECLR3CALLBACKMEMBER(int, pfnSharedModuleGetPageState, (PPDMDEVINS pDevIns, RTGCPTR GCPtrPage, bool *pfShared, uint64_t *pfPageFlags)); + + /** + * Check all registered modules for changes. + * + * @returns VBox status code. + * @param pDevIns The device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnSharedModuleCheckAll,(PPDMDEVINS pDevIns)); + + /** + * Query the interface of the top level driver on a LUN. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pszDevice Device name. + * @param iInstance Device instance. + * @param iLun The Logical Unit to obtain the interface of. + * @param ppBase Where to store the base interface pointer. + * + * @remark We're not doing any locking ATM, so don't try call this at times when the + * device chain is known to be updated. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryLun,(PPDMDEVINS pDevIns, const char *pszDevice, unsigned iInstance, unsigned iLun, PPPDMIBASE ppBase)); + + /** + * Registers the GIM device with VMM. + * + * @param pDevIns Pointer to the GIM device instance. + * @param pDbg Pointer to the GIM device debug structure, can be + * NULL. + */ + DECLR3CALLBACKMEMBER(void, pfnGIMDeviceRegister,(PPDMDEVINS pDevIns, PGIMDEBUG pDbg)); + + /** + * Gets debug setup specified by the provider. + * + * @returns VBox status code. + * @param pDevIns Pointer to the GIM device instance. + * @param pDbgSetup Where to store the debug setup details. + */ + DECLR3CALLBACKMEMBER(int, pfnGIMGetDebugSetup,(PPDMDEVINS pDevIns, PGIMDEBUGSETUP pDbgSetup)); + + /** + * Returns the array of MMIO2 regions that are expected to be registered and + * later mapped into the guest-physical address space for the GIM provider + * configured for the VM. + * + * @returns Pointer to an array of GIM MMIO2 regions, may return NULL. + * @param pDevIns Pointer to the GIM device instance. + * @param pcRegions Where to store the number of items in the array. + * + * @remarks The caller does not own and therefore must -NOT- try to free the + * returned pointer. + */ + DECLR3CALLBACKMEMBER(PGIMMMIO2REGION, pfnGIMGetMmio2Regions,(PPDMDEVINS pDevIns, uint32_t *pcRegions)); + + /** @} */ + + /** Just a safety precaution. (PDM_DEVHLPR3_VERSION) */ + uint32_t u32TheEnd; +} PDMDEVHLPR3; +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ +/** Pointer to the R3 PDM Device API. */ +typedef R3PTRTYPE(struct PDMDEVHLPR3 *) PPDMDEVHLPR3; +/** Pointer to the R3 PDM Device API, const variant. */ +typedef R3PTRTYPE(const struct PDMDEVHLPR3 *) PCPDMDEVHLPR3; + + +/** + * PDM Device API - RC Variant. + */ +typedef struct PDMDEVHLPRC +{ + /** Structure version. PDM_DEVHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Sets up raw-mode context callback handlers for an I/O port range. + * + * The range must have been registered in ring-3 first using + * PDMDevHlpIoPortCreate() or PDMDevHlpIoPortCreateEx(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + * @param pfnOut Pointer to function which is gonna handle OUT + * operations. Optional. + * @param pfnIn Pointer to function which is gonna handle IN operations. + * Optional. + * @param pfnOutStr Pointer to function which is gonna handle string OUT + * operations. Optional. + * @param pfnInStr Pointer to function which is gonna handle string IN + * operations. Optional. + * @param pvUser User argument to pass to the callbacks. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpIoPortCreate, PDMDevHlpIoPortCreateEx, PDMDevHlpIoPortMap, + * PDMDevHlpIoPortUnmap. + */ + DECLRCCALLBACKMEMBER(int, pfnIoPortSetUpContextEx,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, + void *pvUser)); + + /** + * Sets up raw-mode context callback handlers for an MMIO region. + * + * The region must have been registered in ring-3 first using + * PDMDevHlpMmioCreate() or PDMDevHlpMmioCreateEx(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO region handle. + * @param pfnWrite Pointer to function which is gonna handle Write + * operations. + * @param pfnRead Pointer to function which is gonna handle Read + * operations. + * @param pfnFill Pointer to function which is gonna handle Fill/memset + * operations. (optional) + * @param pvUser User argument to pass to the callbacks. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpMmioCreate, PDMDevHlpMmioCreateEx, PDMDevHlpMmioMap, + * PDMDevHlpMmioUnmap. + */ + DECLRCCALLBACKMEMBER(int, pfnMmioSetUpContextEx,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser)); + + /** + * Sets up a raw-mode mapping for an MMIO2 region. + * + * The region must have been created in ring-3 first using + * PDMDevHlpMmio2Create(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO2 region handle. + * @param offSub Start of what to map into raw-mode. Must be page aligned. + * @param cbSub Number of bytes to map into raw-mode. Must be page + * aligned. Zero is an alias for everything. + * @param ppvMapping Where to return the mapping corresponding to @a offSub. + * @thread EMT(0) + * @note Only available at VM creation time. + * + * @sa PDMDevHlpMmio2Create(). + */ + DECLRCCALLBACKMEMBER(int, pfnMmio2SetUpContext,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, + size_t offSub, size_t cbSub, void **ppvMapping)); + + /** + * Bus master physical memory read from the given PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLRCCALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Bus master physical memory write from the given PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLRCCALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Set the IRQ for the given PCI device. + * + * @param pDevIns Device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLRCCALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)); + + /** + * Set ISA IRQ for a device. + * + * @param pDevIns Device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLRCCALLBACKMEMBER(void, pfnISASetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Read physical memory. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns Device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + */ + DECLRCCALLBACKMEMBER(int, pfnPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Write to physical memory. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns Device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + */ + DECLRCCALLBACKMEMBER(int, pfnPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Checks if the Gate A20 is enabled or not. + * + * @returns true if A20 is enabled. + * @returns false if A20 is disabled. + * @param pDevIns Device instance. + * @thread The emulation thread. + */ + DECLRCCALLBACKMEMBER(bool, pfnA20IsEnabled,(PPDMDEVINS pDevIns)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pDevIns The device instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLRCCALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMDEVINS pDevIns)); + + /** + * Gets the VM handle. Restricted API. + * + * @returns VM Handle. + * @param pDevIns Device instance. + */ + DECLRCCALLBACKMEMBER(PVMCC, pfnGetVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the VMCPU handle. Restricted API. + * + * @returns VMCPU Handle. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(PVMCPUCC, pfnGetVMCPU,(PPDMDEVINS pDevIns)); + + /** + * The the VM CPU ID of the current thread (restricted API). + * + * @returns The VMCPUID of the calling thread, NIL_VMCPUID if not EMT. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(VMCPUID, pfnGetCurrentCpuId,(PPDMDEVINS pDevIns)); + + /** + * Gets the main execution engine for the VM. + * + * @returns VM_EXEC_ENGINE_XXX + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(uint8_t, pfnGetMainExecutionEngine,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM. The clock frequency must be + * queried separately. + * + * @returns Current clock time. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(uint64_t, pfnTMTimeVirtGet,(PPDMDEVINS pDevIns)); + + /** + * Get the frequency of the virtual clock. + * + * @returns The clock frequency (not variable at run-time). + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetFreq,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM, in nanoseconds. + * + * @returns Current clock time (in ns). + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetNano,(PPDMDEVINS pDevIns)); + + /** + * Gets the NOP critical section. + * + * @returns The ring-3 address of the NOP critical section. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(PPDMCRITSECT, pfnCritSectGetNop,(PPDMDEVINS pDevIns)); + + /** + * Changes the device level critical section from the automatically created + * default to one desired by the device constructor. + * + * Must first be done in ring-3. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect The critical section to use. NULL is not + * valid, instead use the NOP critical + * section. + */ + DECLRCCALLBACKMEMBER(int, pfnSetDeviceCritSect,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLRCCALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLRCCALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + /** @} */ + + /** @name Exported PDM Read/Write Critical Section Functions + * @{ */ + DECLRCCALLBACKMEMBER(int, pfnCritSectRwEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwTryEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwTryEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwLeaveShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLRCCALLBACKMEMBER(int, pfnCritSectRwEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwTryEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwTryEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectRwLeaveExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLRCCALLBACKMEMBER(bool, pfnCritSectRwIsWriteOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectRwIsReadOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, bool fWannaHear)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriteRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriterReadRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectRwGetReadCount,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectRwIsInitialized,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + /** @} */ + + /** + * Gets the trace buffer handle. + * + * This is used by the macros found in VBox/vmm/dbgftrace.h and is not + * really inteded for direct usage, thus no inline wrapper function. + * + * @returns Trace buffer handle or NIL_RTTRACEBUF. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(RTTRACEBUF, pfnDBGFTraceBuf,(PPDMDEVINS pDevIns)); + + /** + * Sets up the PCI bus for the raw-mode context. + * + * This must be called after ring-3 has registered the PCI bus using + * PDMDevHlpPCIBusRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciBusReg The PCI bus registration information for raw-mode, + * considered volatile. + * @param ppPciHlp Where to return the raw-mode PCI bus helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnPCIBusSetUpContext,(PPDMDEVINS pDevIns, PPDMPCIBUSREGRC pPciBusReg, PCPDMPCIHLPRC *ppPciHlp)); + + /** + * Sets up the IOMMU for the raw-mode context. + * + * This must be called after ring-3 has registered the IOMMU using + * PDMDevHlpIommuRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIommuReg The IOMMU registration information for raw-mode, + * considered volatile. + * @param ppIommuHlp Where to return the raw-mode IOMMU helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnIommuSetUpContext,(PPDMDEVINS pDevIns, PPDMIOMMUREGRC pIommuReg, PCPDMIOMMUHLPRC *ppIommuHlp)); + + /** + * Sets up the PIC for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpPICRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPicReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppPicHlp Where to return the ring-0 PIC helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnPICSetUpContext,(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp)); + + /** + * Sets up the APIC for the raw-mode context. + * + * This must be called after ring-3 has registered the APIC using + * PDMDevHlpApicRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + */ + DECLRCCALLBACKMEMBER(int, pfnApicSetUpContext,(PPDMDEVINS pDevIns)); + + /** + * Sets up the IOAPIC for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpIoApicRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIoApicReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppIoApicHlp Where to return the ring-0 IOAPIC helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnIoApicSetUpContext,(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp)); + + /** + * Sets up the HPET for the raw-mode context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpHpetRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pHpetReg The PIC registration information for raw-mode, + * considered volatile and copied. + * @param ppHpetHlp Where to return the raw-mode HPET helpers. + */ + DECLRCCALLBACKMEMBER(int, pfnHpetSetUpContext,(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, PCPDMHPETHLPRC *ppHpetHlp)); + + /** Space reserved for future members. + * @{ */ + DECLRCCALLBACKMEMBER(void, pfnReserved1,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved2,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved3,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved4,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved5,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved6,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved7,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved8,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved9,(void)); + DECLRCCALLBACKMEMBER(void, pfnReserved10,(void)); + /** @} */ + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDEVHLPRC; +/** Pointer PDM Device RC API. */ +typedef RGPTRTYPE(struct PDMDEVHLPRC *) PPDMDEVHLPRC; +/** Pointer PDM Device RC API. */ +typedef RGPTRTYPE(const struct PDMDEVHLPRC *) PCPDMDEVHLPRC; + +/** Current PDMDEVHLP version number. */ +#define PDM_DEVHLPRC_VERSION PDM_VERSION_MAKE(0xffe6, 19, 0) + + +/** + * PDM Device API - R0 Variant. + */ +typedef struct PDMDEVHLPR0 +{ + /** Structure version. PDM_DEVHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Sets up ring-0 callback handlers for an I/O port range. + * + * The range must have been created in ring-3 first using + * PDMDevHlpIoPortCreate() or PDMDevHlpIoPortCreateEx(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hIoPorts The I/O port range handle. + * @param pfnOut Pointer to function which is gonna handle OUT + * operations. Optional. + * @param pfnIn Pointer to function which is gonna handle IN operations. + * Optional. + * @param pfnOutStr Pointer to function which is gonna handle string OUT + * operations. Optional. + * @param pfnInStr Pointer to function which is gonna handle string IN + * operations. Optional. + * @param pvUser User argument to pass to the callbacks. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpIoPortCreate(), PDMDevHlpIoPortCreateEx(), + * PDMDevHlpIoPortMap(), PDMDevHlpIoPortUnmap(). + */ + DECLR0CALLBACKMEMBER(int, pfnIoPortSetUpContextEx,(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, + void *pvUser)); + + /** + * Sets up ring-0 callback handlers for an MMIO region. + * + * The region must have been created in ring-3 first using + * PDMDevHlpMmioCreate(), PDMDevHlpMmioCreateEx(), PDMDevHlpMmioCreateAndMap(), + * PDMDevHlpMmioCreateExAndMap() or PDMDevHlpPCIIORegionCreateMmio(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO region handle. + * @param pfnWrite Pointer to function which is gonna handle Write + * operations. + * @param pfnRead Pointer to function which is gonna handle Read + * operations. + * @param pfnFill Pointer to function which is gonna handle Fill/memset + * operations. (optional) + * @param pvUser User argument to pass to the callbacks. + * + * @remarks Caller enters the device critical section prior to invoking the + * registered callback methods. + * + * @sa PDMDevHlpMmioCreate(), PDMDevHlpMmioCreateEx(), PDMDevHlpMmioMap(), + * PDMDevHlpMmioUnmap(). + */ + DECLR0CALLBACKMEMBER(int, pfnMmioSetUpContextEx,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser)); + + /** + * Sets up a ring-0 mapping for an MMIO2 region. + * + * The region must have been created in ring-3 first using + * PDMDevHlpMmio2Create(). + * + * @returns VBox status. + * @param pDevIns The device instance to register the ports with. + * @param hRegion The MMIO2 region handle. + * @param offSub Start of what to map into ring-0. Must be page aligned. + * @param cbSub Number of bytes to map into ring-0. Must be page + * aligned. Zero is an alias for everything. + * @param ppvMapping Where to return the mapping corresponding to @a offSub. + * + * @thread EMT(0) + * @note Only available at VM creation time. + * + * @sa PDMDevHlpMmio2Create(). + */ + DECLR0CALLBACKMEMBER(int, pfnMmio2SetUpContext,(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, size_t offSub, size_t cbSub, + void **ppvMapping)); + + /** + * Bus master physical memory read from the given PCI device. + * + * @returns VINF_SUCCESS or VERR_PDM_NOT_PCI_BUS_MASTER, later maybe + * VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR0CALLBACKMEMBER(int, pfnPCIPhysRead,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Bus master physical memory write from the given PCI device. + * + * @returns VINF_SUCCESS or VERR_PDM_NOT_PCI_BUS_MASTER, later maybe + * VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + * @thread Any thread, but the call may involve the emulation thread. + */ + DECLR0CALLBACKMEMBER(int, pfnPCIPhysWrite,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, + const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Set the IRQ for the given PCI device. + * + * @param pDevIns Device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR0CALLBACKMEMBER(void, pfnPCISetIrq,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel)); + + /** + * Set ISA IRQ for a device. + * + * @param pDevIns Device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ + DECLR0CALLBACKMEMBER(void, pfnISASetIrq,(PPDMDEVINS pDevIns, int iIrq, int iLevel)); + + /** + * Read physical memory. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns Device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + */ + DECLR0CALLBACKMEMBER(int, pfnPhysRead,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, uint32_t fFlags)); + + /** + * Write to physical memory. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns Device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @param fFlags Combination of PDM_DEVHLP_PHYS_RW_F_XXX. + */ + DECLR0CALLBACKMEMBER(int, pfnPhysWrite,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, uint32_t fFlags)); + + /** + * Checks if the Gate A20 is enabled or not. + * + * @returns true if A20 is enabled. + * @returns false if A20 is disabled. + * @param pDevIns Device instance. + * @thread The emulation thread. + */ + DECLR0CALLBACKMEMBER(bool, pfnA20IsEnabled,(PPDMDEVINS pDevIns)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pDevIns The device instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLR0CALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMDEVINS pDevIns)); + + /** + * Gets the VM handle. Restricted API. + * + * @returns VM Handle. + * @param pDevIns Device instance. + */ + DECLR0CALLBACKMEMBER(PVMCC, pfnGetVM,(PPDMDEVINS pDevIns)); + + /** + * Gets the VMCPU handle. Restricted API. + * + * @returns VMCPU Handle. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(PVMCPUCC, pfnGetVMCPU,(PPDMDEVINS pDevIns)); + + /** + * The the VM CPU ID of the current thread (restricted API). + * + * @returns The VMCPUID of the calling thread, NIL_VMCPUID if not EMT. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(VMCPUID, pfnGetCurrentCpuId,(PPDMDEVINS pDevIns)); + + /** + * Gets the main execution engine for the VM. + * + * @returns VM_EXEC_ENGINE_XXX + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(uint8_t, pfnGetMainExecutionEngine,(PPDMDEVINS pDevIns)); + + /** @name Timer handle method wrappers + * @{ */ + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerFromMicro,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerFromMilli,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerFromNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerGet,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerGetFreq,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(uint64_t, pfnTimerGetNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(bool, pfnTimerIsActive,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(bool, pfnTimerIsLockOwner,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(VBOXSTRICTRC, pfnTimerLockClock,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, int rcBusy)); + /** Takes the clock lock then enters the specified critical section. */ + DECLR0CALLBACKMEMBER(VBOXSTRICTRC, pfnTimerLockClock2,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnTimerSet,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t uExpire)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetFrequencyHint,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint32_t uHz)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetMicro,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetMillies,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetNano,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext)); + DECLR0CALLBACKMEMBER(int, pfnTimerSetRelative,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now)); + DECLR0CALLBACKMEMBER(int, pfnTimerStop,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(void, pfnTimerUnlockClock,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer)); + DECLR0CALLBACKMEMBER(void, pfnTimerUnlockClock2,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + /** @} */ + + /** + * Get the current virtual clock time in a VM. The clock frequency must be + * queried separately. + * + * @returns Current clock time. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGet,(PPDMDEVINS pDevIns)); + + /** + * Get the frequency of the virtual clock. + * + * @returns The clock frequency (not variable at run-time). + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetFreq,(PPDMDEVINS pDevIns)); + + /** + * Get the current virtual clock time in a VM, in nanoseconds. + * + * @returns Current clock time (in ns). + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(uint64_t, pfnTMTimeVirtGetNano,(PPDMDEVINS pDevIns)); + + /** @name Exported PDM Queue Functions + * @{ */ + DECLR0CALLBACKMEMBER(PPDMQUEUEITEMCORE, pfnQueueAlloc,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)); + DECLR0CALLBACKMEMBER(int, pfnQueueInsert,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)); + DECLR0CALLBACKMEMBER(bool, pfnQueueFlushIfNecessary,(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue)); + /** @} */ + + /** @name PDM Task + * @{ */ + /** + * Triggers the running the given task. + * + * @returns VBox status code. + * @retval VINF_ALREADY_POSTED is the task is already pending. + * @param pDevIns The device instance. + * @param hTask The task to trigger. + * @thread Any thread. + */ + DECLR0CALLBACKMEMBER(int, pfnTaskTrigger,(PPDMDEVINS pDevIns, PDMTASKHANDLE hTask)); + /** @} */ + + /** @name SUP Event Semaphore Wrappers (single release / auto reset) + * These semaphores can be signalled from ring-0. + * @{ */ + /** @sa SUPSemEventSignal */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventSignal,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent)); + /** @sa SUPSemEventWaitNoResume */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventWaitNoResume,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint32_t cMillies)); + /** @sa SUPSemEventWaitNsAbsIntr */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventWaitNsAbsIntr,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t uNsTimeout)); + /** @sa SUPSemEventWaitNsRelIntr */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventWaitNsRelIntr,(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t cNsTimeout)); + /** @sa SUPSemEventGetResolution */ + DECLR0CALLBACKMEMBER(uint32_t, pfnSUPSemEventGetResolution,(PPDMDEVINS pDevIns)); + /** @} */ + + /** @name SUP Multi Event Semaphore Wrappers (multiple release / manual reset) + * These semaphores can be signalled from ring-0. + * @{ */ + /** @sa SUPSemEventMultiSignal */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiSignal,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiReset */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiReset,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti)); + /** @sa SUPSemEventMultiWaitNoResume */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNoResume,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies)); + /** @sa SUPSemEventMultiWaitNsAbsIntr */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNsAbsIntr,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t uNsTimeout)); + /** @sa SUPSemEventMultiWaitNsRelIntr */ + DECLR0CALLBACKMEMBER(int, pfnSUPSemEventMultiWaitNsRelIntr,(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t cNsTimeout)); + /** @sa SUPSemEventMultiGetResolution */ + DECLR0CALLBACKMEMBER(uint32_t, pfnSUPSemEventMultiGetResolution,(PPDMDEVINS pDevIns)); + /** @} */ + + /** + * Gets the NOP critical section. + * + * @returns The ring-3 address of the NOP critical section. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(PPDMCRITSECT, pfnCritSectGetNop,(PPDMDEVINS pDevIns)); + + /** + * Changes the device level critical section from the automatically created + * default to one desired by the device constructor. + * + * Must first be done in ring-3. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect The critical section to use. NULL is not + * valid, instead use the NOP critical + * section. + */ + DECLR0CALLBACKMEMBER(int, pfnSetDeviceCritSect,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLR0CALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectScheduleExitEvent,(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)); + /** @} */ + + /** @name Exported PDM Read/Write Critical Section Functions + * @{ */ + DECLR0CALLBACKMEMBER(int, pfnCritSectRwEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwTryEnterShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwTryEnterSharedDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwLeaveShared,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR0CALLBACKMEMBER(int, pfnCritSectRwEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwTryEnterExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwTryEnterExclDebug,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectRwLeaveExcl,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + + DECLR0CALLBACKMEMBER(bool, pfnCritSectRwIsWriteOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectRwIsReadOwner,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, bool fWannaHear)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriteRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectRwGetWriterReadRecursion,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectRwGetReadCount,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectRwIsInitialized,(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect)); + /** @} */ + + /** + * Gets the trace buffer handle. + * + * This is used by the macros found in VBox/vmm/dbgftrace.h and is not + * really inteded for direct usage, thus no inline wrapper function. + * + * @returns Trace buffer handle or NIL_RTTRACEBUF. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(RTTRACEBUF, pfnDBGFTraceBuf,(PPDMDEVINS pDevIns)); + + /** + * Sets up the PCI bus for the ring-0 context. + * + * This must be called after ring-3 has registered the PCI bus using + * PDMDevHlpPCIBusRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciBusReg The PCI bus registration information for ring-0, + * considered volatile and copied. + * @param ppPciHlp Where to return the ring-0 PCI bus helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnPCIBusSetUpContext,(PPDMDEVINS pDevIns, PPDMPCIBUSREGR0 pPciBusReg, PCPDMPCIHLPR0 *ppPciHlp)); + + /** + * Sets up the IOMMU for the ring-0 context. + * + * This must be called after ring-3 has registered the IOMMU using + * PDMDevHlpIommuRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIommuReg The IOMMU registration information for ring-0, + * considered volatile and copied. + * @param ppIommuHlp Where to return the ring-0 IOMMU helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnIommuSetUpContext,(PPDMDEVINS pDevIns, PPDMIOMMUREGR0 pIommuReg, PCPDMIOMMUHLPR0 *ppIommuHlp)); + + /** + * Sets up the PIC for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpPICRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPicReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppPicHlp Where to return the ring-0 PIC helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnPICSetUpContext,(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp)); + + /** + * Sets up the APIC for the ring-0 context. + * + * This must be called after ring-3 has registered the APIC using + * PDMDevHlpApicRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + */ + DECLR0CALLBACKMEMBER(int, pfnApicSetUpContext,(PPDMDEVINS pDevIns)); + + /** + * Sets up the IOAPIC for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpIoApicRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pIoApicReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppIoApicHlp Where to return the ring-0 IOAPIC helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnIoApicSetUpContext,(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp)); + + /** + * Sets up the HPET for the ring-0 context. + * + * This must be called after ring-3 has registered the PIC using + * PDMDevHlpHpetRegister(). + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pHpetReg The PIC registration information for ring-0, + * considered volatile and copied. + * @param ppHpetHlp Where to return the ring-0 HPET helpers. + */ + DECLR0CALLBACKMEMBER(int, pfnHpetSetUpContext,(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, PCPDMHPETHLPR0 *ppHpetHlp)); + + /** + * Sets up a physical page access handler type for ring-0 callbacks. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param enmKind The kind of access handler. + * @param pfnHandler Pointer to the ring-0 handler callback. NULL if + * the ring-3 handler should be called. + * @param pfnPfHandler The name of the ring-0 \#PF handler, NULL if the + * ring-3 handler should be called. + * @param pszDesc The type description. + * @param hType The type handle registered in ring-3 already. + * @sa PDMDevHlpPGMHandlerPhysicalTypeRegister + */ + DECLR0CALLBACKMEMBER(int, pfnPGMHandlerPhysicalTypeSetUpContext, (PPDMDEVINS pDevIns, PGMPHYSHANDLERKIND enmKind, + PFNPGMPHYSHANDLER pfnHandler, + PFNPGMRZPHYSPFHANDLER pfnPfHandler, + const char *pszDesc, PGMPHYSHANDLERTYPE hType)); + + /** + * Temporarily turns off the access monitoring of a page within a monitored + * physical write/all page access handler region. + * + * Use this when no further \#PFs are required for that page. Be aware that + * a page directory sync might reset the flags, and turn on access monitoring + * for the page. + * + * The caller must do required page table modifications. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param GCPhys The start address of the access handler. This + * must be a fully page aligned range or we risk + * messing up other handlers installed for the + * start and end pages. + * @param GCPhysPage The physical address of the page to turn off + * access monitoring for. + */ + DECLR0CALLBACKMEMBER(int, pfnPGMHandlerPhysicalPageTempOff,(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage)); + + /** + * Mapping an MMIO2 page in place of an MMIO page for direct access. + * + * This is a special optimization used by the VGA device. Call + * PDMDevHlpMmioResetRegion() to undo the mapping. + * + * @returns VBox status code. This API may return VINF_SUCCESS even if no + * remapping is made. + * @retval VERR_SEM_BUSY in ring-0 if we cannot get the IOM lock. + * + * @param pDevIns The device instance @a hRegion and @a hMmio2 are + * associated with. + * @param hRegion The handle to the MMIO region. + * @param offRegion The offset into @a hRegion of the page to be + * remapped. + * @param hMmio2 The MMIO2 handle. + * @param offMmio2 Offset into @a hMmio2 of the page to be use for the + * mapping. + * @param fPageFlags Page flags to set. Must be (X86_PTE_RW | X86_PTE_P) + * for the time being. + */ + DECLR0CALLBACKMEMBER(int, pfnMmioMapMmio2Page,(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion, + uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags)); + + /** + * Reset a previously modified MMIO region; restore the access flags. + * + * This undoes the effects of PDMDevHlpMmioMapMmio2Page() and is currently only + * intended for some ancient VGA hack. However, it would be great to extend it + * beyond VT-x and/or nested-paging. + * + * @returns VBox status code. + * + * @param pDevIns The device instance @a hRegion is associated with. + * @param hRegion The handle to the MMIO region. + */ + DECLR0CALLBACKMEMBER(int, pfnMmioResetRegion, (PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion)); + + /** + * Returns the array of MMIO2 regions that are expected to be registered and + * later mapped into the guest-physical address space for the GIM provider + * configured for the VM. + * + * @returns Pointer to an array of GIM MMIO2 regions, may return NULL. + * @param pDevIns Pointer to the GIM device instance. + * @param pcRegions Where to store the number of items in the array. + * + * @remarks The caller does not own and therefore must -NOT- try to free the + * returned pointer. + */ + DECLR0CALLBACKMEMBER(PGIMMMIO2REGION, pfnGIMGetMmio2Regions,(PPDMDEVINS pDevIns, uint32_t *pcRegions)); + + /** Space reserved for future members. + * @{ */ + DECLR0CALLBACKMEMBER(void, pfnReserved1,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved2,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved3,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved4,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved5,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved6,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved7,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved8,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved9,(void)); + DECLR0CALLBACKMEMBER(void, pfnReserved10,(void)); + /** @} */ + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDEVHLPR0; +/** Pointer PDM Device R0 API. */ +typedef R0PTRTYPE(struct PDMDEVHLPR0 *) PPDMDEVHLPR0; +/** Pointer PDM Device GC API. */ +typedef R0PTRTYPE(const struct PDMDEVHLPR0 *) PCPDMDEVHLPR0; + +/** Current PDMDEVHLP version number. */ +#define PDM_DEVHLPR0_VERSION PDM_VERSION_MAKE(0xffe5, 27, 0) + + +/** + * PDM Device Instance. + */ +typedef struct PDMDEVINSR3 +{ + /** Structure version. PDM_DEVINSR3_VERSION defines the current version. */ + uint32_t u32Version; + /** Device instance number. */ + uint32_t iInstance; + /** Size of the ring-3, raw-mode and shared bits. */ + uint32_t cbRing3; + /** Set if ring-0 context is enabled. */ + bool fR0Enabled; + /** Set if raw-mode context is enabled. */ + bool fRCEnabled; + /** Alignment padding. */ + bool afReserved[2]; + /** Pointer the HC PDM Device API. */ + PCPDMDEVHLPR3 pHlpR3; + /** Pointer to the shared device instance data. */ + RTR3PTR pvInstanceDataR3; + /** Pointer to the device instance data for ring-3. */ + RTR3PTR pvInstanceDataForR3; + /** The critical section for the device. + * + * TM and IOM will enter this critical section before calling into the device + * code. PDM will when doing power on, power off, reset, suspend and resume + * notifications. SSM will currently not, but this will be changed later on. + * + * The device gets a critical section automatically assigned to it before + * the constructor is called. If the constructor wishes to use a different + * critical section, it calls PDMDevHlpSetDeviceCritSect() to change it + * very early on. + */ + R3PTRTYPE(PPDMCRITSECT) pCritSectRoR3; + /** Pointer to device registration structure. */ + R3PTRTYPE(PCPDMDEVREG) pReg; + /** Configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfg; + /** The base interface of the device. + * + * The device constructor initializes this if it has any + * device level interfaces to export. To obtain this interface + * call PDMR3QueryDevice(). */ + PDMIBASE IBase; + + /** Tracing indicator. */ + uint32_t fTracing; + /** The tracing ID of this device. */ + uint32_t idTracing; + + /** Ring-3 pointer to the raw-mode device instance. */ + R3PTRTYPE(struct PDMDEVINSRC *) pDevInsForRCR3; + /** Raw-mode address of the raw-mode device instance. */ + RTRGPTR pDevInsForRC; + /** Ring-3 pointer to the raw-mode instance data. */ + RTR3PTR pvInstanceDataForRCR3; + + /** PCI device structure size. */ + uint32_t cbPciDev; + /** Number of PCI devices in apPciDevs. */ + uint32_t cPciDevs; + /** Pointer to the PCI devices for this device. + * (Allocated after the shared instance data.) + * @note If we want to extend this beyond 8 sub-functions/devices, those 1 or + * two devices ever needing it can use cbPciDev and do the address + * calculations that for entries 8+. */ + R3PTRTYPE(struct PDMPCIDEV *) apPciDevs[8]; + + /** Temporarily. */ + R0PTRTYPE(struct PDMDEVINSR0 *) pDevInsR0RemoveMe; + /** Temporarily. */ + RTR0PTR pvInstanceDataR0; + /** Temporarily. */ + RTRCPTR pvInstanceDataRC; + /** Align the internal data more naturally. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 13 : 11]; + + /** Internal data. */ + union + { +#ifdef PDMDEVINSINT_DECLARED + PDMDEVINSINTR3 s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 0x40 : 0x90]; + } Internal; + + /** Device instance data for ring-3. The size of this area is defined + * in the PDMDEVREG::cbInstanceR3 field. */ + char achInstanceData[8]; +} PDMDEVINSR3; + +/** Current PDMDEVINSR3 version number. */ +#define PDM_DEVINSR3_VERSION PDM_VERSION_MAKE(0xff82, 4, 0) + +/** Converts a pointer to the PDMDEVINSR3::IBase to a pointer to PDMDEVINS. */ +#define PDMIBASE_2_PDMDEV(pInterface) ( (PPDMDEVINS)((char *)(pInterface) - RT_UOFFSETOF(PDMDEVINS, IBase)) ) + + +/** + * PDM ring-0 device instance. + */ +typedef struct PDMDEVINSR0 +{ + /** Structure version. PDM_DEVINSR0_VERSION defines the current version. */ + uint32_t u32Version; + /** Device instance number. */ + uint32_t iInstance; + + /** Pointer the HC PDM Device API. */ + PCPDMDEVHLPR0 pHlpR0; + /** Pointer to the shared device instance data. */ + RTR0PTR pvInstanceDataR0; + /** Pointer to the device instance data for ring-0. */ + RTR0PTR pvInstanceDataForR0; + /** The critical section for the device. + * + * TM and IOM will enter this critical section before calling into the device + * code. PDM will when doing power on, power off, reset, suspend and resume + * notifications. SSM will currently not, but this will be changed later on. + * + * The device gets a critical section automatically assigned to it before + * the constructor is called. If the constructor wishes to use a different + * critical section, it calls PDMDevHlpSetDeviceCritSect() to change it + * very early on. + */ + R0PTRTYPE(PPDMCRITSECT) pCritSectRoR0; + /** Pointer to the ring-0 device registration structure. */ + R0PTRTYPE(PCPDMDEVREGR0) pReg; + /** Ring-3 address of the ring-3 device instance. */ + R3PTRTYPE(struct PDMDEVINSR3 *) pDevInsForR3; + /** Ring-0 pointer to the ring-3 device instance. */ + R0PTRTYPE(struct PDMDEVINSR3 *) pDevInsForR3R0; + /** Ring-0 pointer to the ring-3 instance data. */ + RTR0PTR pvInstanceDataForR3R0; + /** Raw-mode address of the raw-mode device instance. */ + RGPTRTYPE(struct PDMDEVINSRC *) pDevInsForRC; + /** Ring-0 pointer to the raw-mode device instance. */ + R0PTRTYPE(struct PDMDEVINSRC *) pDevInsForRCR0; + /** Ring-0 pointer to the raw-mode instance data. */ + RTR0PTR pvInstanceDataForRCR0; + + /** PCI device structure size. */ + uint32_t cbPciDev; + /** Number of PCI devices in apPciDevs. */ + uint32_t cPciDevs; + /** Pointer to the PCI devices for this device. + * (Allocated after the shared instance data.) + * @note If we want to extend this beyond 8 sub-functions/devices, those 1 or + * two devices ever needing it can use cbPciDev and do the address + * calculations that for entries 8+. */ + R0PTRTYPE(struct PDMPCIDEV *) apPciDevs[8]; + + /** Align the internal data more naturally. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 3 : 2 + 4]; + + /** Internal data. */ + union + { +#ifdef PDMDEVINSINT_DECLARED + PDMDEVINSINTR0 s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 0x40 : 0x80]; + } Internal; + + /** Device instance data for ring-0. The size of this area is defined + * in the PDMDEVREG::cbInstanceR0 field. */ + char achInstanceData[8]; +} PDMDEVINSR0; + +/** Current PDMDEVINSR0 version number. */ +#define PDM_DEVINSR0_VERSION PDM_VERSION_MAKE(0xff83, 4, 0) + + +/** + * PDM raw-mode device instance. + */ +typedef struct PDMDEVINSRC +{ + /** Structure version. PDM_DEVINSRC_VERSION defines the current version. */ + uint32_t u32Version; + /** Device instance number. */ + uint32_t iInstance; + + /** Pointer the HC PDM Device API. */ + PCPDMDEVHLPRC pHlpRC; + /** Pointer to the shared device instance data. */ + RTRGPTR pvInstanceDataRC; + /** Pointer to the device instance data for raw-mode. */ + RTRGPTR pvInstanceDataForRC; + /** The critical section for the device. + * + * TM and IOM will enter this critical section before calling into the device + * code. PDM will when doing power on, power off, reset, suspend and resume + * notifications. SSM will currently not, but this will be changed later on. + * + * The device gets a critical section automatically assigned to it before + * the constructor is called. If the constructor wishes to use a different + * critical section, it calls PDMDevHlpSetDeviceCritSect() to change it + * very early on. + */ + RGPTRTYPE(PPDMCRITSECT) pCritSectRoRC; + /** Pointer to the raw-mode device registration structure. */ + RGPTRTYPE(PCPDMDEVREGRC) pReg; + + /** PCI device structure size. */ + uint32_t cbPciDev; + /** Number of PCI devices in apPciDevs. */ + uint32_t cPciDevs; + /** Pointer to the PCI devices for this device. + * (Allocated after the shared instance data.) */ + RGPTRTYPE(struct PDMPCIDEV *) apPciDevs[8]; + + /** Align the internal data more naturally. */ + uint32_t au32Padding[14]; + + /** Internal data. */ + union + { +#ifdef PDMDEVINSINT_DECLARED + PDMDEVINSINTRC s; +#endif + uint8_t padding[0x10]; + } Internal; + + /** Device instance data for ring-0. The size of this area is defined + * in the PDMDEVREG::cbInstanceR0 field. */ + char achInstanceData[8]; +} PDMDEVINSRC; + +/** Current PDMDEVINSR0 version number. */ +#define PDM_DEVINSRC_VERSION PDM_VERSION_MAKE(0xff84, 4, 0) + + +/** @def PDM_DEVINS_VERSION + * Current PDMDEVINS version number. */ +/** @typedef PDMDEVINS + * The device instance structure for the current context. */ +#ifdef IN_RING3 +# define PDM_DEVINS_VERSION PDM_DEVINSR3_VERSION +typedef PDMDEVINSR3 PDMDEVINS; +#elif defined(IN_RING0) +# define PDM_DEVINS_VERSION PDM_DEVINSR0_VERSION +typedef PDMDEVINSR0 PDMDEVINS; +#elif defined(IN_RC) +# define PDM_DEVINS_VERSION PDM_DEVINSRC_VERSION +typedef PDMDEVINSRC PDMDEVINS; +#else +# error "Missing context defines: IN_RING0, IN_RING3, IN_RC" +#endif + +/** + * Get the pointer to an PCI device. + * @note Returns NULL if @a a_idxPciDev is out of bounds. + */ +#define PDMDEV_GET_PPCIDEV(a_pDevIns, a_idxPciDev) \ + ( (uintptr_t)(a_idxPciDev) < RT_ELEMENTS((a_pDevIns)->apPciDevs) ? (a_pDevIns)->apPciDevs[(uintptr_t)(a_idxPciDev)] \ + : PDMDEV_CALC_PPCIDEV(a_pDevIns, a_idxPciDev) ) + +/** + * Calc the pointer to of a given PCI device. + * @note Returns NULL if @a a_idxPciDev is out of bounds. + */ +#define PDMDEV_CALC_PPCIDEV(a_pDevIns, a_idxPciDev) \ + ( (uintptr_t)(a_idxPciDev) < (a_pDevIns)->cPciDevs \ + ? (PPDMPCIDEV)((uint8_t *)((a_pDevIns)->apPciDevs[0]) + (a_pDevIns->cbPciDev) * (uintptr_t)(a_idxPciDev)) \ + : (PPDMPCIDEV)NULL ) + + +/** + * Checks the structure versions of the device instance and device helpers, + * returning if they are incompatible. + * + * This is for use in the constructor. + * + * @param pDevIns The device instance pointer. + */ +#define PDMDEV_CHECK_VERSIONS_RETURN(pDevIns) \ + do \ + { \ + PPDMDEVINS pDevInsTypeCheck = (pDevIns); NOREF(pDevInsTypeCheck); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pDevIns)->u32Version, PDM_DEVINS_VERSION), \ + ("DevIns=%#x mine=%#x\n", (pDevIns)->u32Version, PDM_DEVINS_VERSION), \ + VERR_PDM_DEVINS_VERSION_MISMATCH); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pDevIns)->CTX_SUFF(pHlp)->u32Version, CTX_MID(PDM_DEVHLP,_VERSION)), \ + ("DevHlp=%#x mine=%#x\n", (pDevIns)->CTX_SUFF(pHlp)->u32Version, CTX_MID(PDM_DEVHLP,_VERSION)), \ + VERR_PDM_DEVHLP_VERSION_MISMATCH); \ + } while (0) + +/** + * Quietly checks the structure versions of the device instance and device + * helpers, returning if they are incompatible. + * + * This is for use in the destructor. + * + * @param pDevIns The device instance pointer. + */ +#define PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns) \ + do \ + { \ + PPDMDEVINS pDevInsTypeCheck = (pDevIns); NOREF(pDevInsTypeCheck); \ + if (RT_LIKELY(PDM_VERSION_ARE_COMPATIBLE((pDevIns)->u32Version, PDM_DEVINS_VERSION) )) \ + { /* likely */ } else return VERR_PDM_DEVINS_VERSION_MISMATCH; \ + if (RT_LIKELY(PDM_VERSION_ARE_COMPATIBLE((pDevIns)->CTX_SUFF(pHlp)->u32Version, CTX_MID(PDM_DEVHLP,_VERSION)) )) \ + { /* likely */ } else return VERR_PDM_DEVHLP_VERSION_MISMATCH; \ + } while (0) + +/** + * Wrapper around CFGMR3ValidateConfig for the root config for use in the + * constructor - returns on failure. + * + * This should be invoked after having initialized the instance data + * sufficiently for the correct operation of the destructor. The destructor is + * always called! + * + * @param pDevIns Pointer to the PDM device instance. + * @param pszValidValues Patterns describing the valid value names. See + * RTStrSimplePatternMultiMatch for details on the + * pattern syntax. + * @param pszValidNodes Patterns describing the valid node (key) names. + * Pass empty string if no valid nodes. + */ +#define PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, pszValidValues, pszValidNodes) \ + do \ + { \ + int rcValCfg = pDevIns->pHlpR3->pfnCFGMValidateConfig((pDevIns)->pCfg, "/", pszValidValues, pszValidNodes, \ + (pDevIns)->pReg->szName, (pDevIns)->iInstance); \ + if (RT_SUCCESS(rcValCfg)) \ + { /* likely */ } else return rcValCfg; \ + } while (0) + +/** @def PDMDEV_ASSERT_EMT + * Assert that the current thread is the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMDEV_ASSERT_EMT(pDevIns) pDevIns->pHlpR3->pfnAssertEMT(pDevIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDEV_ASSERT_EMT(pDevIns) do { } while (0) +#endif + +/** @def PDMDEV_ASSERT_OTHER + * Assert that the current thread is NOT the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMDEV_ASSERT_OTHER(pDevIns) pDevIns->pHlpR3->pfnAssertOther(pDevIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDEV_ASSERT_OTHER(pDevIns) do { } while (0) +#endif + +/** @def PDMDEV_ASSERT_VMLOCK_OWNER + * Assert that the current thread is owner of the VM lock. + */ +#ifdef VBOX_STRICT +# define PDMDEV_ASSERT_VMLOCK_OWNER(pDevIns) pDevIns->pHlpR3->pfnAssertVMLock(pDevIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDEV_ASSERT_VMLOCK_OWNER(pDevIns) do { } while (0) +#endif + +/** @def PDMDEV_SET_ERROR + * Set the VM error. See PDMDevHlpVMSetError() for printf like message formatting. + */ +#define PDMDEV_SET_ERROR(pDevIns, rc, pszError) \ + PDMDevHlpVMSetError(pDevIns, rc, RT_SRC_POS, "%s", pszError) + +/** @def PDMDEV_SET_RUNTIME_ERROR + * Set the VM runtime error. See PDMDevHlpVMSetRuntimeError() for printf like message formatting. + */ +#define PDMDEV_SET_RUNTIME_ERROR(pDevIns, fFlags, pszErrorId, pszError) \ + PDMDevHlpVMSetRuntimeError(pDevIns, fFlags, pszErrorId, "%s", pszError) + +/** @def PDMDEVINS_2_RCPTR + * Converts a PDM Device instance pointer to a RC PDM Device instance pointer. + */ +#ifdef IN_RC +# define PDMDEVINS_2_RCPTR(pDevIns) (pDevIns) +#else +# define PDMDEVINS_2_RCPTR(pDevIns) ( (pDevIns)->pDevInsForRC ) +#endif + +/** @def PDMDEVINS_2_R3PTR + * Converts a PDM Device instance pointer to a R3 PDM Device instance pointer. + */ +#ifdef IN_RING3 +# define PDMDEVINS_2_R3PTR(pDevIns) (pDevIns) +#else +# define PDMDEVINS_2_R3PTR(pDevIns) ( (pDevIns)->pDevInsForR3 ) +#endif + +/** @def PDMDEVINS_2_R0PTR + * Converts a PDM Device instance pointer to a R0 PDM Device instance pointer. + */ +#ifdef IN_RING0 +# define PDMDEVINS_2_R0PTR(pDevIns) (pDevIns) +#else +# define PDMDEVINS_2_R0PTR(pDevIns) ( (pDevIns)->pDevInsR0RemoveMe ) +#endif + +/** @def PDMDEVINS_DATA_2_R0_REMOVE_ME + * Converts a PDM device instance data pointer to a ring-0 one. + * @deprecated + */ +#ifdef IN_RING0 +# define PDMDEVINS_DATA_2_R0_REMOVE_ME(pDevIns, pvCC) (pvCC) +#else +# define PDMDEVINS_DATA_2_R0_REMOVE_ME(pDevIns, pvCC) ( (pDevIns)->pvInstanceDataR0 + (uintptr_t)(pvCC) - (uintptr_t)(pDevIns)->CTX_SUFF(pvInstanceData) ) +#endif + + +/** @def PDMDEVINS_2_DATA + * This is a safer edition of PDMINS_2_DATA that checks that the size of the + * target type is same as PDMDEVREG::cbInstanceShared in strict builds. + * + * @note Do no use this macro in common code working on a core structure which + * device specific code has expanded. + */ +#if defined(VBOX_STRICT) && defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define PDMDEVINS_2_DATA(a_pDevIns, a_PtrType) \ + ([](PPDMDEVINS a_pLambdaDevIns) -> a_PtrType \ + { \ + a_PtrType pLambdaRet = (a_PtrType)(a_pLambdaDevIns)->CTX_SUFF(pvInstanceData); \ + Assert(sizeof(*pLambdaRet) == a_pLambdaDevIns->pReg->cbInstanceShared); \ + return pLambdaRet; \ + }(a_pDevIns)) +#else +# define PDMDEVINS_2_DATA(a_pDevIns, a_PtrType) ( (a_PtrType)(a_pDevIns)->CTX_SUFF(pvInstanceData) ) +#endif + +/** @def PDMDEVINS_2_DATA_CC + * This is a safer edition of PDMINS_2_DATA_CC that checks that the size of the + * target type is same as PDMDEVREG::cbInstanceCC in strict builds. + * + * @note Do no use this macro in common code working on a core structure which + * device specific code has expanded. + */ +#if defined(VBOX_STRICT) && defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define PDMDEVINS_2_DATA_CC(a_pDevIns, a_PtrType) \ + ([](PPDMDEVINS a_pLambdaDevIns) -> a_PtrType \ + { \ + a_PtrType pLambdaRet = (a_PtrType)&(a_pLambdaDevIns)->achInstanceData[0]; \ + Assert(sizeof(*pLambdaRet) == a_pLambdaDevIns->pReg->cbInstanceCC); \ + return pLambdaRet; \ + }(a_pDevIns)) +#else +# define PDMDEVINS_2_DATA_CC(a_pDevIns, a_PtrType) ( (a_PtrType)(void *)&(a_pDevIns)->achInstanceData[0] ) +#endif + + +#ifdef IN_RING3 + +/** + * Combines PDMDevHlpIoPortCreate() & PDMDevHlpIoPortMap(). + */ +DECLINLINE(int) PDMDevHlpIoPortCreateAndMap(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, PFNIOMIOPORTNEWOUT pfnOut, + PFNIOMIOPORTNEWIN pfnIn, const char *pszDesc, PCIOMIOPORTDESC paExtDescs, + PIOMIOPORTHANDLE phIoPorts) +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, NULL, UINT32_MAX, + pfnOut, pfnIn, NULL, NULL, NULL, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnIoPortMap(pDevIns, *phIoPorts, Port); + return rc; +} + +/** + * Combines PDMDevHlpIoPortCreate() & PDMDevHlpIoPortMap(), but with pvUser. + */ +DECLINLINE(int) PDMDevHlpIoPortCreateUAndMap(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, PFNIOMIOPORTNEWOUT pfnOut, + PFNIOMIOPORTNEWIN pfnIn, void *pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, NULL, UINT32_MAX, + pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnIoPortMap(pDevIns, *phIoPorts, Port); + return rc; +} + +/** + * Combines PDMDevHlpIoPortCreate() & PDMDevHlpIoPortMap(), but with flags. + */ +DECLINLINE(int) PDMDevHlpIoPortCreateFlagsAndMap(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, uint32_t fFlags, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, fFlags, NULL, UINT32_MAX, + pfnOut, pfnIn, NULL, NULL, NULL, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnIoPortMap(pDevIns, *phIoPorts, Port); + return rc; +} + +/** + * Combines PDMDevHlpIoPortCreateEx() & PDMDevHlpIoPortMap(). + */ +DECLINLINE(int) PDMDevHlpIoPortCreateExAndMap(PPDMDEVINS pDevIns, RTIOPORT Port, RTIOPORT cPorts, uint32_t fFlags, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, void *pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, fFlags, NULL, UINT32_MAX, + pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnIoPortMap(pDevIns, *phIoPorts, Port); + return rc; +} + +/** + * @sa PDMDevHlpIoPortCreateEx + */ +DECLINLINE(int) PDMDevHlpIoPortCreate(PPDMDEVINS pDevIns, RTIOPORT cPorts, PPDMPCIDEV pPciDev, uint32_t iPciRegion, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, void *pvUser, const char *pszDesc, + PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, pPciDev, iPciRegion, + pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, paExtDescs, phIoPorts); +} + + +/** + * @sa PDMDevHlpIoPortCreateEx + */ +DECLINLINE(int) PDMDevHlpIoPortCreateIsa(PPDMDEVINS pDevIns, RTIOPORT cPorts, PFNIOMIOPORTNEWOUT pfnOut, + PFNIOMIOPORTNEWIN pfnIn, void *pvUser, const char *pszDesc, + PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0, NULL, UINT32_MAX, + pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, paExtDescs, phIoPorts); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoPortCreateEx + */ +DECLINLINE(int) PDMDevHlpIoPortCreateEx(PPDMDEVINS pDevIns, RTIOPORT cPorts, uint32_t fFlags, PPDMPCIDEV pPciDev, + uint32_t iPciRegion, PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, void *pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, fFlags, pPciDev, iPciRegion, + pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser, pszDesc, paExtDescs, phIoPorts); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoPortMap + */ +DECLINLINE(int) PDMDevHlpIoPortMap(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, RTIOPORT Port) +{ + return pDevIns->pHlpR3->pfnIoPortMap(pDevIns, hIoPorts, Port); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoPortUnmap + */ +DECLINLINE(int) PDMDevHlpIoPortUnmap(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortUnmap(pDevIns, hIoPorts); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoPortGetMappingAddress + */ +DECLINLINE(uint32_t) PDMDevHlpIoPortGetMappingAddress(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts) +{ + return pDevIns->pHlpR3->pfnIoPortGetMappingAddress(pDevIns, hIoPorts); +} + + +#endif /* IN_RING3 */ +#if !defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @sa PDMDevHlpIoPortSetUpContextEx + */ +DECLINLINE(int) PDMDevHlpIoPortSetUpContext(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, void *pvUser) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnIoPortSetUpContextEx(pDevIns, hIoPorts, pfnOut, pfnIn, NULL, NULL, pvUser); +} + +/** + * @copydoc PDMDEVHLPR0::pfnIoPortSetUpContextEx + */ +DECLINLINE(int) PDMDevHlpIoPortSetUpContextEx(PPDMDEVINS pDevIns, IOMIOPORTHANDLE hIoPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, + PFNIOMIOPORTNEWOUTSTRING pfnOutStr, PFNIOMIOPORTNEWINSTRING pfnInStr, void *pvUser) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnIoPortSetUpContextEx(pDevIns, hIoPorts, pfnOut, pfnIn, pfnOutStr, pfnInStr, pvUser); +} + +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ +#ifdef IN_RING3 + +/** + * @sa PDMDevHlpMmioCreateEx + */ +DECLINLINE(int) PDMDevHlpMmioCreate(PPDMDEVINS pDevIns, RTGCPHYS cbRegion, PPDMPCIDEV pPciDev, uint32_t iPciRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, void *pvUser, + uint32_t fFlags, const char *pszDesc, PIOMMMIOHANDLE phRegion) +{ + return pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, + pfnWrite, pfnRead, NULL, pvUser, pszDesc, phRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioCreateEx + */ +DECLINLINE(int) PDMDevHlpMmioCreateEx(PPDMDEVINS pDevIns, RTGCPHYS cbRegion, + uint32_t fFlags, PPDMPCIDEV pPciDev, uint32_t iPciRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, + void *pvUser, const char *pszDesc, PIOMMMIOHANDLE phRegion) +{ + return pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, + pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion); +} + +/** + * @sa PDMDevHlpMmioCreate and PDMDevHlpMmioMap + */ +DECLINLINE(int) PDMDevHlpMmioCreateAndMap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cbRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, + uint32_t fFlags, const char *pszDesc, PIOMMMIOHANDLE phRegion) +{ + int rc = pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, NULL /*pPciDev*/, UINT32_MAX /*iPciRegion*/, + pfnWrite, pfnRead, NULL /*pfnFill*/, NULL /*pvUser*/, pszDesc, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnMmioMap(pDevIns, *phRegion, GCPhys); + return rc; +} + +/** + * @sa PDMDevHlpMmioCreateEx and PDMDevHlpMmioMap + */ +DECLINLINE(int) PDMDevHlpMmioCreateExAndMap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cbRegion, uint32_t fFlags, + PPDMPCIDEV pPciDev, uint32_t iPciRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser, + const char *pszDesc, PIOMMMIOHANDLE phRegion) +{ + int rc = pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, pPciDev, iPciRegion, + pfnWrite, pfnRead, pfnFill, pvUser, pszDesc, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnMmioMap(pDevIns, *phRegion, GCPhys); + return rc; +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioMap + */ +DECLINLINE(int) PDMDevHlpMmioMap(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnMmioMap(pDevIns, hRegion, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioUnmap + */ +DECLINLINE(int) PDMDevHlpMmioUnmap(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmioUnmap(pDevIns, hRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioReduce + */ +DECLINLINE(int) PDMDevHlpMmioReduce(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS cbRegion) +{ + return pDevIns->pHlpR3->pfnMmioReduce(pDevIns, hRegion, cbRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioGetMappingAddress + */ +DECLINLINE(RTGCPHYS) PDMDevHlpMmioGetMappingAddress(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmioGetMappingAddress(pDevIns, hRegion); +} + +#endif /* IN_RING3 */ +#if !defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @sa PDMDevHlpMmioSetUpContextEx + */ +DECLINLINE(int) PDMDevHlpMmioSetUpContext(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, void *pvUser) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmioSetUpContextEx(pDevIns, hRegion, pfnWrite, pfnRead, NULL, pvUser); +} + +/** + * @copydoc PDMDEVHLPR0::pfnMmioSetUpContextEx + */ +DECLINLINE(int) PDMDevHlpMmioSetUpContextEx(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, PFNIOMMMIONEWWRITE pfnWrite, + PFNIOMMMIONEWREAD pfnRead, PFNIOMMMIONEWFILL pfnFill, void *pvUser) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmioSetUpContextEx(pDevIns, hRegion, pfnWrite, pfnRead, pfnFill, pvUser); +} + +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2Create + */ +DECLINLINE(int) PDMDevHlpMmio2Create(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iPciRegion, RTGCPHYS cbRegion, + uint32_t fFlags, const char *pszDesc, void **ppvMapping, PPGMMMIO2HANDLE phRegion) +{ + return pDevIns->pHlpR3->pfnMmio2Create(pDevIns, pPciDev, iPciRegion, cbRegion, fFlags, pszDesc, ppvMapping, phRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2Map + */ +DECLINLINE(int) PDMDevHlpMmio2Map(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnMmio2Map(pDevIns, hRegion, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2Unmap + */ +DECLINLINE(int) PDMDevHlpMmio2Unmap(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmio2Unmap(pDevIns, hRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2Reduce + */ +DECLINLINE(int) PDMDevHlpMmio2Reduce(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, RTGCPHYS cbRegion) +{ + return pDevIns->pHlpR3->pfnMmio2Reduce(pDevIns, hRegion, cbRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2GetMappingAddress + */ +DECLINLINE(RTGCPHYS) PDMDevHlpMmio2GetMappingAddress(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmio2GetMappingAddress(pDevIns, hRegion); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2QueryAndResetDirtyBitmap + */ +DECLINLINE(int) PDMDevHlpMmio2QueryAndResetDirtyBitmap(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, + void *pvBitmap, size_t cbBitmap) +{ + return pDevIns->pHlpR3->pfnMmio2QueryAndResetDirtyBitmap(pDevIns, hRegion, pvBitmap, cbBitmap); +} + +/** + * Reset the dirty bitmap tracking for an MMIO2 region. + * + * The MMIO2 region must have been created with the + * PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES flag for this to work. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param hRegion The MMIO2 region handle. + */ +DECLINLINE(int) PDMDevHlpMmio2ResetDirtyBitmap(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion) +{ + return pDevIns->pHlpR3->pfnMmio2QueryAndResetDirtyBitmap(pDevIns, hRegion, NULL, 0); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmio2ControlDirtyPageTracking + */ +DECLINLINE(int) PDMDevHlpMmio2ControlDirtyPageTracking(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, bool fEnabled) +{ + return pDevIns->pHlpR3->pfnMmio2ControlDirtyPageTracking(pDevIns, hRegion, fEnabled); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnMmioMapMmio2Page + */ +DECLINLINE(int) PDMDevHlpMmioMapMmio2Page(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion, RTGCPHYS offRegion, + uint64_t hMmio2, RTGCPHYS offMmio2, uint64_t fPageFlags) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmioMapMmio2Page(pDevIns, hRegion, offRegion, hMmio2, offMmio2, fPageFlags); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMmioResetRegion + */ +DECLINLINE(int) PDMDevHlpMmioResetRegion(PPDMDEVINS pDevIns, IOMMMIOHANDLE hRegion) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmioResetRegion(pDevIns, hRegion); +} + +#if !defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @copydoc PDMDEVHLPR0::pfnMmio2SetUpContext + */ +DECLINLINE(int) PDMDevHlpMmio2SetUpContext(PPDMDEVINS pDevIns, PGMMMIO2HANDLE hRegion, + size_t offSub, size_t cbSub, void **ppvMapping) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnMmio2SetUpContext(pDevIns, hRegion, offSub, cbSub, ppvMapping); +} + +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnROMRegister + */ +DECLINLINE(int) PDMDevHlpROMRegister(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, + const void *pvBinary, uint32_t cbBinary, uint32_t fFlags, const char *pszDesc) +{ + return pDevIns->pHlpR3->pfnROMRegister(pDevIns, GCPhysStart, cbRange, pvBinary, cbBinary, fFlags, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnROMProtectShadow + */ +DECLINLINE(int) PDMDevHlpROMProtectShadow(PPDMDEVINS pDevIns, RTGCPHYS GCPhysStart, uint32_t cbRange, PGMROMPROT enmProt) +{ + return pDevIns->pHlpR3->pfnROMProtectShadow(pDevIns, GCPhysStart, cbRange, enmProt); +} + +/** + * Register a save state data unit. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnLoadExec Execute load callback, optional. + */ +DECLINLINE(int) PDMDevHlpSSMRegister(PPDMDEVINS pDevIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVLOADEXEC pfnLoadExec) +{ + return pDevIns->pHlpR3->pfnSSMRegister(pDevIns, uVersion, cbGuess, NULL /*pszBefore*/, + NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveDone*/, + NULL /*pfnSavePrep*/, pfnSaveExec, NULL /*pfnSaveDone*/, + NULL /*pfnLoadPrep*/, pfnLoadExec, NULL /*pfnLoadDone*/); +} + +/** + * Register a save state data unit with a live save callback as well. + * + * @returns VBox status. + * @param pDevIns The device instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * @param pfnLiveExec Execute live callback, optional. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnLoadExec Execute load callback, optional. + */ +DECLINLINE(int) PDMDevHlpSSMRegister3(PPDMDEVINS pDevIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVLOADEXEC pfnLoadExec) +{ + return pDevIns->pHlpR3->pfnSSMRegister(pDevIns, uVersion, cbGuess, NULL /*pszBefore*/, + NULL /*pfnLivePrep*/, pfnLiveExec, NULL /*pfnLiveDone*/, + NULL /*pfnSavePrep*/, pfnSaveExec, NULL /*pfnSaveDone*/, + NULL /*pfnLoadPrep*/, pfnLoadExec, NULL /*pfnLoadDone*/); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSSMRegister + */ +DECLINLINE(int) PDMDevHlpSSMRegisterEx(PPDMDEVINS pDevIns, uint32_t uVersion, size_t cbGuess, const char *pszBefore, + PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote, + PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone, + PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone) +{ + return pDevIns->pHlpR3->pfnSSMRegister(pDevIns, uVersion, cbGuess, pszBefore, + pfnLivePrep, pfnLiveExec, pfnLiveVote, + pfnSavePrep, pfnSaveExec, pfnSaveDone, + pfnLoadPrep, pfnLoadExec, pfnLoadDone); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSSMRegisterLegacy + */ +DECLINLINE(int) PDMDevHlpSSMRegisterLegacy(PPDMDEVINS pDevIns, const char *pszOldName, PFNSSMDEVLOADPREP pfnLoadPrep, + PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone) +{ + return pDevIns->pHlpR3->pfnSSMRegisterLegacy(pDevIns, pszOldName, pfnLoadPrep, pfnLoadExec, pfnLoadDone); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerCreate + */ +DECLINLINE(int) PDMDevHlpTimerCreate(PPDMDEVINS pDevIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer) +{ + return pDevIns->pHlpR3->pfnTimerCreate(pDevIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnTimerFromMicro + */ +DECLINLINE(uint64_t) PDMDevHlpTimerFromMicro(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerFromMicro(pDevIns, hTimer, cMicroSecs); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerFromMilli + */ +DECLINLINE(uint64_t) PDMDevHlpTimerFromMilli(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerFromMilli(pDevIns, hTimer, cMilliSecs); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerFromNano + */ +DECLINLINE(uint64_t) PDMDevHlpTimerFromNano(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerFromNano(pDevIns, hTimer, cNanoSecs); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerGet + */ +DECLINLINE(uint64_t) PDMDevHlpTimerGet(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerGet(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerGetFreq + */ +DECLINLINE(uint64_t) PDMDevHlpTimerGetFreq(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerGetFreq(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerGetNano + */ +DECLINLINE(uint64_t) PDMDevHlpTimerGetNano(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerGetNano(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerIsActive + */ +DECLINLINE(bool) PDMDevHlpTimerIsActive(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerIsActive(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerIsLockOwner + */ +DECLINLINE(bool) PDMDevHlpTimerIsLockOwner(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerIsLockOwner(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerLockClock + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpTimerLockClock(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerLockClock(pDevIns, hTimer, rcBusy); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerLockClock2 + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpTimerLockClock2(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerLockClock2(pDevIns, hTimer, pCritSect, rcBusy); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSet + */ +DECLINLINE(int) PDMDevHlpTimerSet(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t uExpire) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSet(pDevIns, hTimer, uExpire); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetFrequencyHint + */ +DECLINLINE(int) PDMDevHlpTimerSetFrequencyHint(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint32_t uHz) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetFrequencyHint(pDevIns, hTimer, uHz); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetMicro + */ +DECLINLINE(int) PDMDevHlpTimerSetMicro(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetMicro(pDevIns, hTimer, cMicrosToNext); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetMillies + */ +DECLINLINE(int) PDMDevHlpTimerSetMillies(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetMillies(pDevIns, hTimer, cMilliesToNext); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetNano + */ +DECLINLINE(int) PDMDevHlpTimerSetNano(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetNano(pDevIns, hTimer, cNanosToNext); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetRelative + */ +DECLINLINE(int) PDMDevHlpTimerSetRelative(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerSetRelative(pDevIns, hTimer, cTicksToNext, pu64Now); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerStop + */ +DECLINLINE(int) PDMDevHlpTimerStop(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTimerStop(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerUnlockClock + */ +DECLINLINE(void) PDMDevHlpTimerUnlockClock(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + pDevIns->CTX_SUFF(pHlp)->pfnTimerUnlockClock(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerUnlockClock2 + */ +DECLINLINE(void) PDMDevHlpTimerUnlockClock2(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + pDevIns->CTX_SUFF(pHlp)->pfnTimerUnlockClock2(pDevIns, hTimer, pCritSect); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSetCritSect + */ +DECLINLINE(int) PDMDevHlpTimerSetCritSect(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + return pDevIns->pHlpR3->pfnTimerSetCritSect(pDevIns, hTimer, pCritSect); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerSave + */ +DECLINLINE(int) PDMDevHlpTimerSave(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM) +{ + return pDevIns->pHlpR3->pfnTimerSave(pDevIns, hTimer, pSSM); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerLoad + */ +DECLINLINE(int) PDMDevHlpTimerLoad(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM) +{ + return pDevIns->pHlpR3->pfnTimerLoad(pDevIns, hTimer, pSSM); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTimerDestroy + */ +DECLINLINE(int) PDMDevHlpTimerDestroy(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer) +{ + return pDevIns->pHlpR3->pfnTimerDestroy(pDevIns, hTimer); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMUtcNow + */ +DECLINLINE(PRTTIMESPEC) PDMDevHlpTMUtcNow(PPDMDEVINS pDevIns, PRTTIMESPEC pTime) +{ + return pDevIns->pHlpR3->pfnTMUtcNow(pDevIns, pTime); +} + +#endif + +/** + * Read physical memory - unknown data usage. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysRead(pDevIns, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Write to physical memory - unknown data usage. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Read physical memory - reads meta data processed by the device. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPhysReadMeta(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysRead(pDevIns, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Write to physical memory - written data was created/altered by the device. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPhysWriteMeta(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Read physical memory - read data will not be touched by the device. + * + * @returns VINF_SUCCESS (for now). + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPhysReadUser(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysRead(pDevIns, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +/** + * Write to physical memory - written data was not touched/created by the device. + * + * @returns VINF_SUCCESS for now, and later maybe VERR_EM_MEMORY. + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPhysWriteUser(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysWrite(pDevIns, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnPhysGCPhys2CCPtr + */ +DECLINLINE(int) PDMDevHlpPhysGCPhys2CCPtr(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, void **ppv, PPGMPAGEMAPLOCK pLock) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysGCPhys2CCPtr(pDevIns, GCPhys, fFlags, ppv, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysGCPhys2CCPtrReadOnly + */ +DECLINLINE(int) PDMDevHlpPhysGCPhys2CCPtrReadOnly(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, uint32_t fFlags, void const **ppv, + PPGMPAGEMAPLOCK pLock) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysGCPhys2CCPtrReadOnly(pDevIns, GCPhys, fFlags, ppv, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysReleasePageMappingLock + */ +DECLINLINE(void) PDMDevHlpPhysReleasePageMappingLock(PPDMDEVINS pDevIns, PPGMPAGEMAPLOCK pLock) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPhysReleasePageMappingLock(pDevIns, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysBulkGCPhys2CCPtr + */ +DECLINLINE(int) PDMDevHlpPhysBulkGCPhys2CCPtr(PPDMDEVINS pDevIns, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + uint32_t fFlags, void **papvPages, PPGMPAGEMAPLOCK paLocks) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysBulkGCPhys2CCPtr(pDevIns, cPages, paGCPhysPages, fFlags, papvPages, paLocks); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysBulkGCPhys2CCPtrReadOnly + */ +DECLINLINE(int) PDMDevHlpPhysBulkGCPhys2CCPtrReadOnly(PPDMDEVINS pDevIns, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + uint32_t fFlags, void const **papvPages, PPGMPAGEMAPLOCK paLocks) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysBulkGCPhys2CCPtrReadOnly(pDevIns, cPages, paGCPhysPages, fFlags, papvPages, paLocks); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysBulkReleasePageMappingLocks + */ +DECLINLINE(void) PDMDevHlpPhysBulkReleasePageMappingLocks(PPDMDEVINS pDevIns, uint32_t cPages, PPGMPAGEMAPLOCK paLocks) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPhysBulkReleasePageMappingLocks(pDevIns, cPages, paLocks); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysIsGCPhysNormal + */ +DECLINLINE(bool) PDMDevHlpPhysIsGCPhysNormal(PPDMDEVINS pDevIns, RTGCPHYS GCPhys) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysIsGCPhysNormal(pDevIns, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysChangeMemBalloon + */ +DECLINLINE(int) PDMDevHlpPhysChangeMemBalloon(PPDMDEVINS pDevIns, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPhysChangeMemBalloon(pDevIns, fInflate, cPages, paPhysPage); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCpuGetGuestMicroarch + */ +DECLINLINE(CPUMMICROARCH) PDMDevHlpCpuGetGuestMicroarch(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCpuGetGuestMicroarch(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCpuGetGuestScalableBusFrequency + */ +DECLINLINE(uint64_t) PDMDevHlpCpuGetGuestScalableBusFrequency(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCpuGetGuestScalableBusFrequency(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCpuGetGuestAddrWidths + */ +DECLINLINE(void) PDMDevHlpCpuGetGuestAddrWidths(PPDMDEVINS pDevIns, uint8_t *pcPhysAddrWidth, uint8_t *pcLinearAddrWidth) +{ + pDevIns->CTX_SUFF(pHlp)->pfnCpuGetGuestAddrWidths(pDevIns, pcPhysAddrWidth, pcLinearAddrWidth); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysReadGCVirt + */ +DECLINLINE(int) PDMDevHlpPhysReadGCVirt(PPDMDEVINS pDevIns, void *pvDst, RTGCPTR GCVirtSrc, size_t cb) +{ + return pDevIns->pHlpR3->pfnPhysReadGCVirt(pDevIns, pvDst, GCVirtSrc, cb); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysWriteGCVirt + */ +DECLINLINE(int) PDMDevHlpPhysWriteGCVirt(PPDMDEVINS pDevIns, RTGCPTR GCVirtDst, const void *pvSrc, size_t cb) +{ + return pDevIns->pHlpR3->pfnPhysWriteGCVirt(pDevIns, GCVirtDst, pvSrc, cb); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPhysGCPtr2GCPhys + */ +DECLINLINE(int) PDMDevHlpPhysGCPtr2GCPhys(PPDMDEVINS pDevIns, RTGCPTR GCPtr, PRTGCPHYS pGCPhys) +{ + return pDevIns->pHlpR3->pfnPhysGCPtr2GCPhys(pDevIns, GCPtr, pGCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMHeapAlloc + */ +DECLINLINE(void *) PDMDevHlpMMHeapAlloc(PPDMDEVINS pDevIns, size_t cb) +{ + return pDevIns->pHlpR3->pfnMMHeapAlloc(pDevIns, cb); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMHeapAllocZ + */ +DECLINLINE(void *) PDMDevHlpMMHeapAllocZ(PPDMDEVINS pDevIns, size_t cb) +{ + return pDevIns->pHlpR3->pfnMMHeapAllocZ(pDevIns, cb); +} + +/** + * Allocating string printf. + * + * @returns Pointer to the string. + * @param pDevIns The device instance. + * @param enmTag The statistics tag. + * @param pszFormat The format string. + * @param ... Format arguments. + */ +DECLINLINE(char *) RT_IPRT_FORMAT_ATTR(2, 3) PDMDevHlpMMHeapAPrintf(PPDMDEVINS pDevIns, MMTAG enmTag, const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + char *psz = pDevIns->pHlpR3->pfnMMHeapAPrintfV(pDevIns, enmTag, pszFormat, va); + va_end(va); + + return psz; +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMHeapFree + */ +DECLINLINE(void) PDMDevHlpMMHeapFree(PPDMDEVINS pDevIns, void *pv) +{ + pDevIns->pHlpR3->pfnMMHeapFree(pDevIns, pv); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMPhysGetRamSize + */ +DECLINLINE(uint64_t) PDMDevHlpMMPhysGetRamSize(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnMMPhysGetRamSize(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMPhysGetRamSizeBelow4GB + */ +DECLINLINE(uint32_t) PDMDevHlpMMPhysGetRamSizeBelow4GB(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnMMPhysGetRamSizeBelow4GB(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnMMPhysGetRamSizeAbove4GB + */ +DECLINLINE(uint64_t) PDMDevHlpMMPhysGetRamSizeAbove4GB(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnMMPhysGetRamSizeAbove4GB(pDevIns); +} +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnVMState + */ +DECLINLINE(VMSTATE) PDMDevHlpVMState(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnVMState(pDevIns); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnVMTeleportedAndNotFullyResumedYet + */ +DECLINLINE(bool) PDMDevHlpVMTeleportedAndNotFullyResumedYet(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMTeleportedAndNotFullyResumedYet(pDevIns); +} + +/** + * Set the VM error message + * + * @returns rc. + * @param pDevIns The device instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + * @sa VMSetError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) PDMDevHlpVMSetError(PPDMDEVINS pDevIns, const int rc, RT_SRC_POS_DECL, + const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + pDevIns->CTX_SUFF(pHlp)->pfnVMSetErrorV(pDevIns, rc, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + return rc; +} + +/** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + * @sa VMSetRuntimeError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 5) PDMDevHlpVMSetRuntimeError(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, ...) +{ + va_list va; + int rc; + va_start(va, pszFormat); + rc = pDevIns->CTX_SUFF(pHlp)->pfnVMSetRuntimeErrorV(pDevIns, fFlags, pszErrorId, pszFormat, va); + va_end(va); + return rc; +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMWaitForDeviceReady + */ +DECLINLINE(int) PDMDevHlpVMWaitForDeviceReady(PPDMDEVINS pDevIns, VMCPUID idCpu) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnVMWaitForDeviceReady(pDevIns, idCpu); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMNotifyCpuDeviceReady + */ +DECLINLINE(int) PDMDevHlpVMNotifyCpuDeviceReady(PPDMDEVINS pDevIns, VMCPUID idCpu) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnVMNotifyCpuDeviceReady(pDevIns, idCpu); +} + +/** + * Convenience wrapper for VMR3ReqCallU. + * + * This assumes (1) you're calling a function that returns an VBox status code + * and that you do not wish to wait for it to complete. + * + * @returns VBox status code returned by VMR3ReqCallVU. + * + * @param pDevIns The device instance. + * @param idDstCpu The destination CPU(s). Either a specific CPU ID or + * one of the following special values: + * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param ... Argument list. + * + * @remarks See remarks on VMR3ReqCallVU. + */ +DECLINLINE(int) PDMDevHlpVMReqCallNoWait(PPDMDEVINS pDevIns, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...) +{ + va_list Args; + va_start(Args, cArgs); + int rc = pDevIns->CTX_SUFF(pHlp)->pfnVMReqCallNoWaitV(pDevIns, idDstCpu, pfnFunction, cArgs, Args); + va_end(Args); + return rc; +} + +/** + * Convenience wrapper for VMR3ReqCallU. + * + * This assumes (1) you're calling a function that returns void, (2) that you + * wish to wait for ever for it to return, and (3) that it's priority request + * that can be safely be handled during async suspend and power off. + * + * @returns VBox status code of VMR3ReqCallVU. + * + * @param pDevIns The device instance. + * @param idDstCpu The destination CPU(s). Either a specific CPU ID or + * one of the following special values: + * VMCPUID_ANY, VMCPUID_ANY_QUEUE, VMCPUID_ALL or VMCPUID_ALL_REVERSE. + * @param pfnFunction Pointer to the function to call. + * @param cArgs Number of arguments following in the ellipsis. + * @param ... Argument list. + * + * @remarks See remarks on VMR3ReqCallVU. + */ +DECLINLINE(int) PDMDevHlpVMReqPriorityCallWait(PPDMDEVINS pDevIns, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...) +{ + va_list Args; + va_start(Args, cArgs); + int rc = pDevIns->CTX_SUFF(pHlp)->pfnVMReqPriorityCallWaitV(pDevIns, idDstCpu, pfnFunction, cArgs, Args); + va_end(Args); + return rc; +} + +#endif /* IN_RING3 */ + +/** + * VBOX_STRICT wrapper for pHlp->pfnDBGFStopV. + * + * @returns VBox status code which must be passed up to the VMM. This will be + * VINF_SUCCESS in non-strict builds. + * @param pDevIns The device instance. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Message. (optional) + * @param ... Message parameters. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(5, 6) PDMDevHlpDBGFStop(PPDMDEVINS pDevIns, RT_SRC_POS_DECL, const char *pszFormat, ...) +{ +#ifdef VBOX_STRICT +# ifdef IN_RING3 + int rc; + va_list args; + va_start(args, pszFormat); + rc = pDevIns->pHlpR3->pfnDBGFStopV(pDevIns, RT_SRC_POS_ARGS, pszFormat, args); + va_end(args); + return rc; +# else + NOREF(pDevIns); + NOREF(pszFile); + NOREF(iLine); + NOREF(pszFunction); + NOREF(pszFormat); + return VINF_EM_DBG_STOP; +# endif +#else + NOREF(pDevIns); + NOREF(pszFile); + NOREF(iLine); + NOREF(pszFunction); + NOREF(pszFormat); + return VINF_SUCCESS; +#endif +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFInfoRegister + */ +DECLINLINE(int) PDMDevHlpDBGFInfoRegister(PPDMDEVINS pDevIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDEV pfnHandler) +{ + return pDevIns->pHlpR3->pfnDBGFInfoRegister(pDevIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFInfoRegisterArgv + */ +DECLINLINE(int) PDMDevHlpDBGFInfoRegisterArgv(PPDMDEVINS pDevIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDEV pfnHandler) +{ + return pDevIns->pHlpR3->pfnDBGFInfoRegisterArgv(pDevIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFRegRegister + */ +DECLINLINE(int) PDMDevHlpDBGFRegRegister(PPDMDEVINS pDevIns, PCDBGFREGDESC paRegisters) +{ + return pDevIns->pHlpR3->pfnDBGFRegRegister(pDevIns, paRegisters); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFReportBugCheck + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpDBGFReportBugCheck(PPDMDEVINS pDevIns, DBGFEVENTTYPE enmEvent, uint64_t uBugCheck, + uint64_t uP1, uint64_t uP2, uint64_t uP3, uint64_t uP4) +{ + return pDevIns->pHlpR3->pfnDBGFReportBugCheck(pDevIns, enmEvent, uBugCheck, uP1, uP2, uP3, uP4); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFCoreWrite + */ +DECLINLINE(int) PDMDevHlpDBGFCoreWrite(PPDMDEVINS pDevIns, const char *pszFilename, bool fReplaceFile) +{ + return pDevIns->pHlpR3->pfnDBGFCoreWrite(pDevIns, pszFilename, fReplaceFile); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFInfoLogHlp + */ +DECLINLINE(PCDBGFINFOHLP) PDMDevHlpDBGFInfoLogHlp(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnDBGFInfoLogHlp(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDBGFRegNmQueryU64 + */ +DECLINLINE(int) PDMDevHlpDBGFRegNmQueryU64(PPDMDEVINS pDevIns, VMCPUID idDefCpu, const char *pszReg, uint64_t *pu64) +{ + return pDevIns->pHlpR3->pfnDBGFRegNmQueryU64(pDevIns, idDefCpu, pszReg, pu64); +} + + /** + * Format a set of registers. + * + * This is restricted to registers from one CPU, that specified by @a idCpu. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param idCpu The CPU ID of any CPU registers that may be + * printed, pass VMCPUID_ANY if not applicable. + * @param pszBuf The output buffer. + * @param cbBuf The size of the output buffer. + * @param pszFormat The format string. Register names are given by + * %VR{name}, they take no arguments. + * @param ... Argument list. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 5) PDMDevHlpDBGFRegPrintf(PPDMDEVINS pDevIns, VMCPUID idCpu, char *pszBuf, size_t cbBuf, + const char *pszFormat, ...) +{ + va_list Args; + va_start(Args, pszFormat); + int rc = pDevIns->pHlpR3->pfnDBGFRegPrintfV(pDevIns, idCpu, pszBuf, cbBuf, pszFormat, Args); + va_end(Args); + return rc; +} + +/** + * @copydoc PDMDEVHLPR3::pfnSTAMRegister + */ +DECLINLINE(void) PDMDevHlpSTAMRegister(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDevIns->pHlpR3->pfnSTAMRegister(pDevIns, pvSample, enmType, pszName, enmUnit, pszDesc); +} + +/** + * Same as pfnSTAMRegister except that the name is specified in a + * RTStrPrintf like fashion. + * + * @returns VBox status. + * @param pDevIns Device instance of the DMA. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is + * pointing at. + * @param enmVisibility Visibility type specifying whether unused + * statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName Sample name format string, unix path style. If + * this does not start with a '/', the default + * prefix will be prepended, otherwise it will be + * used as-is. + * @param ... Arguments to the format string. + */ +DECLINLINE(void) RT_IPRT_FORMAT_ATTR(7, 8) PDMDevHlpSTAMRegisterF(PPDMDEVINS pDevIns, void *pvSample, STAMTYPE enmType, + STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, ...) +{ + va_list va; + va_start(va, pszName); + pDevIns->pHlpR3->pfnSTAMRegisterV(pDevIns, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va); + va_end(va); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSTAMDeregisterByPrefix + */ +DECLINLINE(int) PDMDevHlpSTAMDeregisterByPrefix(PPDMDEVINS pDevIns, const char *pszPrefix) +{ + return pDevIns->pHlpR3->pfnSTAMDeregisterByPrefix(pDevIns, pszPrefix); +} + +/** + * Registers the device with the default PCI bus. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. + * This must be kept in the instance data. + * The PCI configuration must be initialized before registration. + */ +DECLINLINE(int) PDMDevHlpPCIRegister(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev) +{ + return pDevIns->pHlpR3->pfnPCIRegister(pDevIns, pPciDev, 0 /*fFlags*/, + PDMPCIDEVREG_DEV_NO_FIRST_UNUSED, PDMPCIDEVREG_FUN_NO_FIRST_UNUSED, NULL); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIRegister + */ +DECLINLINE(int) PDMDevHlpPCIRegisterEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t fFlags, + uint8_t uPciDevNo, uint8_t uPciFunNo, const char *pszName) +{ + return pDevIns->pHlpR3->pfnPCIRegister(pDevIns, pPciDev, fFlags, uPciDevNo, uPciFunNo, pszName); +} + +/** + * Initialize MSI emulation support for the first PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pMsiReg MSI emulation registration structure. + */ +DECLINLINE(int) PDMDevHlpPCIRegisterMsi(PPDMDEVINS pDevIns, PPDMMSIREG pMsiReg) +{ + return pDevIns->pHlpR3->pfnPCIRegisterMsi(pDevIns, NULL, pMsiReg); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIRegisterMsi + */ +DECLINLINE(int) PDMDevHlpPCIRegisterMsiEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, PPDMMSIREG pMsiReg) +{ + return pDevIns->pHlpR3->pfnPCIRegisterMsi(pDevIns, pPciDev, pMsiReg); +} + +/** + * Registers a I/O port region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param hIoPorts Handle to the I/O port region. + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterIo(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cbRegion, IOMIOPORTHANDLE hIoPorts) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, NULL, iRegion, cbRegion, PCI_ADDRESS_SPACE_IO, + PDMPCIDEV_IORGN_F_IOPORT_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, hIoPorts, NULL); +} + +/** + * Registers a I/O port region for the default PCI device, custom map/unmap. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param pfnMapUnmap Callback for doing the mapping, optional. The + * callback will be invoked holding only the PDM lock. + * The device lock will _not_ be taken (due to lock + * order). + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterIoCustom(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cbRegion, + PFNPCIIOREGIONMAP pfnMapUnmap) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, NULL, iRegion, cbRegion, PCI_ADDRESS_SPACE_IO, + PDMPCIDEV_IORGN_F_NO_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + UINT64_MAX, pfnMapUnmap); +} + +/** + * Combines PDMDevHlpIoPortCreate and PDMDevHlpPCIIORegionRegisterIo, creating + * and registering an I/O port region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance to register the ports with. + * @param cPorts The count of I/O ports in the region (the size). + * @param iPciRegion The PCI device region. + * @param pfnOut Pointer to function which is gonna handle OUT + * operations. Optional. + * @param pfnIn Pointer to function which is gonna handle IN operations. + * Optional. + * @param pvUser User argument to pass to the callbacks. + * @param pszDesc Pointer to description string. This must not be freed. + * @param paExtDescs Extended per-port descriptions, optional. Partial range + * coverage is allowed. This must not be freed. + * @param phIoPorts Where to return the I/O port range handle. + * + */ +DECLINLINE(int) PDMDevHlpPCIIORegionCreateIo(PPDMDEVINS pDevIns, uint32_t iPciRegion, RTIOPORT cPorts, + PFNIOMIOPORTNEWOUT pfnOut, PFNIOMIOPORTNEWIN pfnIn, void *pvUser, + const char *pszDesc, PCIOMIOPORTDESC paExtDescs, PIOMIOPORTHANDLE phIoPorts) + +{ + int rc = pDevIns->pHlpR3->pfnIoPortCreateEx(pDevIns, cPorts, 0 /*fFlags*/, pDevIns->apPciDevs[0], iPciRegion << 16, + pfnOut, pfnIn, NULL, NULL, pvUser, pszDesc, paExtDescs, phIoPorts); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pDevIns->apPciDevs[0], iPciRegion, cPorts, PCI_ADDRESS_SPACE_IO, + PDMPCIDEV_IORGN_F_IOPORT_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + *phIoPorts, NULL /*pfnMapUnmap*/); + return rc; +} + +/** + * Registers an MMIO region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param hMmioRegion Handle to the MMIO region. + * @param pfnMapUnmap Callback for doing the mapping, optional. The + * callback will be invoked holding only the PDM lock. + * The device lock will _not_ be taken (due to lock + * order). + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterMmio(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, + IOMMMIOHANDLE hMmioRegion, PFNPCIIOREGIONMAP pfnMapUnmap) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, NULL, iRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + hMmioRegion, pfnMapUnmap); +} + +/** + * Registers an MMIO region for the default PCI device, extended version. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param hMmioRegion Handle to the MMIO region. + * @param pfnMapUnmap Callback for doing the mapping, optional. The + * callback will be invoked holding only the PDM lock. + * The device lock will _not_ be taken (due to lock + * order). + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterMmioEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, IOMMMIOHANDLE hMmioRegion, + PFNPCIIOREGIONMAP pfnMapUnmap) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pPciDev, iRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + hMmioRegion, pfnMapUnmap); +} + +/** + * Combines PDMDevHlpMmioCreate and PDMDevHlpPCIIORegionRegisterMmio, creating + * and registering an MMIO region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance to register the ports with. + * @param cbRegion The size of the region in bytes. + * @param iPciRegion The PCI device region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param fFlags Flags, IOMMMIO_FLAGS_XXX. + * @param pfnWrite Pointer to function which is gonna handle Write + * operations. + * @param pfnRead Pointer to function which is gonna handle Read + * operations. + * @param pvUser User argument to pass to the callbacks. + * @param pszDesc Pointer to description string. This must not be freed. + * @param phRegion Where to return the MMIO region handle. + * + */ +DECLINLINE(int) PDMDevHlpPCIIORegionCreateMmio(PPDMDEVINS pDevIns, uint32_t iPciRegion, RTGCPHYS cbRegion, PCIADDRESSSPACE enmType, + PFNIOMMMIONEWWRITE pfnWrite, PFNIOMMMIONEWREAD pfnRead, void *pvUser, + uint32_t fFlags, const char *pszDesc, PIOMMMIOHANDLE phRegion) + +{ + int rc = pDevIns->pHlpR3->pfnMmioCreateEx(pDevIns, cbRegion, fFlags, pDevIns->apPciDevs[0], iPciRegion << 16, + pfnWrite, pfnRead, NULL /*pfnFill*/, pvUser, pszDesc, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pDevIns->apPciDevs[0], iPciRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + *phRegion, NULL /*pfnMapUnmap*/); + return rc; +} + + +/** + * Registers an MMIO2 region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param iRegion The region number. + * @param cbRegion Size of the region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param hMmio2Region Handle to the MMIO2 region. + */ +DECLINLINE(int) PDMDevHlpPCIIORegionRegisterMmio2(PPDMDEVINS pDevIns, uint32_t iRegion, RTGCPHYS cbRegion, + PCIADDRESSSPACE enmType, PGMMMIO2HANDLE hMmio2Region) +{ + return pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, NULL, iRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO2_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + hMmio2Region, NULL); +} + +/** + * Combines PDMDevHlpMmio2Create and PDMDevHlpPCIIORegionRegisterMmio2, creating + * and registering an MMIO2 region for the default PCI device, extended edition. + * + * @returns VBox status code. + * @param pDevIns The device instance to register the ports with. + * @param cbRegion The size of the region in bytes. + * @param iPciRegion The PCI device region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param pszDesc Pointer to description string. This must not be freed. + * @param ppvMapping Where to store the address of the ring-3 mapping of + * the memory. + * @param phRegion Where to return the MMIO2 region handle. + * + */ +DECLINLINE(int) PDMDevHlpPCIIORegionCreateMmio2(PPDMDEVINS pDevIns, uint32_t iPciRegion, RTGCPHYS cbRegion, + PCIADDRESSSPACE enmType, const char *pszDesc, + void **ppvMapping, PPGMMMIO2HANDLE phRegion) + +{ + int rc = pDevIns->pHlpR3->pfnMmio2Create(pDevIns, pDevIns->apPciDevs[0], iPciRegion << 16, cbRegion, 0 /*fFlags*/, + pszDesc, ppvMapping, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pDevIns->apPciDevs[0], iPciRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO2_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + *phRegion, NULL /*pfnCallback*/); + return rc; +} + +/** + * Combines PDMDevHlpMmio2Create and PDMDevHlpPCIIORegionRegisterMmio2, creating + * and registering an MMIO2 region for the default PCI device. + * + * @returns VBox status code. + * @param pDevIns The device instance to register the ports with. + * @param cbRegion The size of the region in bytes. + * @param iPciRegion The PCI device region. + * @param enmType PCI_ADDRESS_SPACE_MEM or + * PCI_ADDRESS_SPACE_MEM_PREFETCH, optionally or-ing in + * PCI_ADDRESS_SPACE_BAR64 or PCI_ADDRESS_SPACE_BAR32. + * @param fMmio2Flags PGMPHYS_MMIO2_FLAGS_XXX (see pgm.h). + * @param pfnMapUnmap Callback for doing the mapping, optional. The + * callback will be invoked holding only the PDM lock. + * The device lock will _not_ be taken (due to lock + * order). + * @param pszDesc Pointer to description string. This must not be freed. + * @param ppvMapping Where to store the address of the ring-3 mapping of + * the memory. + * @param phRegion Where to return the MMIO2 region handle. + * + */ +DECLINLINE(int) PDMDevHlpPCIIORegionCreateMmio2Ex(PPDMDEVINS pDevIns, uint32_t iPciRegion, RTGCPHYS cbRegion, + PCIADDRESSSPACE enmType, uint32_t fMmio2Flags, PFNPCIIOREGIONMAP pfnMapUnmap, + const char *pszDesc, void **ppvMapping, PPGMMMIO2HANDLE phRegion) + +{ + int rc = pDevIns->pHlpR3->pfnMmio2Create(pDevIns, pDevIns->apPciDevs[0], iPciRegion << 16, cbRegion, fMmio2Flags, + pszDesc, ppvMapping, phRegion); + if (RT_SUCCESS(rc)) + rc = pDevIns->pHlpR3->pfnPCIIORegionRegister(pDevIns, pDevIns->apPciDevs[0], iPciRegion, cbRegion, enmType, + PDMPCIDEV_IORGN_F_MMIO2_HANDLE | PDMPCIDEV_IORGN_F_NEW_STYLE, + *phRegion, pfnMapUnmap); + return rc; +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIInterceptConfigAccesses + */ +DECLINLINE(int) PDMDevHlpPCIInterceptConfigAccesses(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + PFNPCICONFIGREAD pfnRead, PFNPCICONFIGWRITE pfnWrite) +{ + return pDevIns->pHlpR3->pfnPCIInterceptConfigAccesses(pDevIns, pPciDev, pfnRead, pfnWrite); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIConfigRead + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpPCIConfigRead(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t uAddress, + unsigned cb, uint32_t *pu32Value) +{ + return pDevIns->pHlpR3->pfnPCIConfigRead(pDevIns, pPciDev, uAddress, cb, pu32Value); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIConfigWrite + */ +DECLINLINE(VBOXSTRICTRC) PDMDevHlpPCIConfigWrite(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t uAddress, + unsigned cb, uint32_t u32Value) +{ + return pDevIns->pHlpR3->pfnPCIConfigWrite(pDevIns, pPciDev, uAddress, cb, u32Value); +} + +#endif /* IN_RING3 */ + +/** + * Bus master physical memory read from the default PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysRead(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, NULL, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Bus master physical memory read - unknown data usage. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, pPciDev, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Bus master physical memory read from the default PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadMeta(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, NULL, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Bus master physical memory read - reads meta data processed by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadMetaEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, pPciDev, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Bus master physical memory read from the default PCI device - read data will not be touched by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadUser(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, NULL, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +/** + * Bus master physical memory read - read data will not be touched by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_READ_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address start reading from. + * @param pvBuf Where to put the read bits. + * @param cbRead How many bytes to read. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysReadUserEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysRead(pDevIns, pPciDev, GCPhys, pvBuf, cbRead, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +/** + * Bus master physical memory write from the default PCI device - unknown data usage. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWrite(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, NULL, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Bus master physical memory write - unknown data usage. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, pPciDev, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DEFAULT); +} + +/** + * Bus master physical memory write from the default PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteMeta(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, NULL, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Bus master physical memory write - written data was created/altered by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteMetaEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, pPciDev, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_META); +} + +/** + * Bus master physical memory write from the default PCI device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteUser(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, NULL, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +/** + * Bus master physical memory write - written data was not touched/created by the device. + * + * @returns VINF_SUCCESS or VERR_PGM_PCI_PHYS_WRITE_BM_DISABLED, later maybe + * VERR_EM_MEMORY. The informational status shall NOT be propagated! + * @param pDevIns The device instance. + * @param pPciDev The PCI device structure. If NULL the default + * PCI device for this device instance is used. + * @param GCPhys Physical address to write to. + * @param pvBuf What to write. + * @param cbWrite How many bytes to write. + * @thread Any thread, but the call may involve the emulation thread. + */ +DECLINLINE(int) PDMDevHlpPCIPhysWriteUserEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysWrite(pDevIns, pPciDev, GCPhys, pvBuf, cbWrite, PDM_DEVHLP_PHYS_RW_F_DATA_USER); +} + +#ifdef IN_RING3 +/** + * @copydoc PDMDEVHLPR3::pfnPCIPhysGCPhys2CCPtr + */ +DECLINLINE(int) PDMDevHlpPCIPhysGCPhys2CCPtr(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, uint32_t fFlags, + void **ppv, PPGMPAGEMAPLOCK pLock) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysGCPhys2CCPtr(pDevIns, pPciDev, GCPhys, fFlags, ppv, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIPhysGCPhys2CCPtrReadOnly + */ +DECLINLINE(int) PDMDevHlpPCIPhysGCPhys2CCPtrReadOnly(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, RTGCPHYS GCPhys, uint32_t fFlags, + void const **ppv, PPGMPAGEMAPLOCK pLock) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysGCPhys2CCPtrReadOnly(pDevIns, pPciDev, GCPhys, fFlags, ppv, pLock); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIPhysBulkGCPhys2CCPtr + */ +DECLINLINE(int) PDMDevHlpPCIPhysBulkGCPhys2CCPtr(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t cPages, + PCRTGCPHYS paGCPhysPages, uint32_t fFlags, void **papvPages, + PPGMPAGEMAPLOCK paLocks) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysBulkGCPhys2CCPtr(pDevIns, pPciDev, cPages, paGCPhysPages, fFlags, papvPages, + paLocks); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIPhysBulkGCPhys2CCPtrReadOnly + */ +DECLINLINE(int) PDMDevHlpPCIPhysBulkGCPhys2CCPtrReadOnly(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t cPages, + PCRTGCPHYS paGCPhysPages, uint32_t fFlags, void const **papvPages, + PPGMPAGEMAPLOCK paLocks) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIPhysBulkGCPhys2CCPtrReadOnly(pDevIns, pPciDev, cPages, paGCPhysPages, fFlags, + papvPages, paLocks); +} +#endif /* IN_RING3 */ + +/** + * Sets the IRQ for the default PCI device. + * + * @param pDevIns The device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. See the PDM_IRQ_LEVEL_* \#defines. + * @thread Any thread, but will involve the emulation thread. + */ +DECLINLINE(void) PDMDevHlpPCISetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, NULL, iIrq, iLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCISetIrq + */ +DECLINLINE(void) PDMDevHlpPCISetIrqEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, pPciDev, iIrq, iLevel); +} + +/** + * Sets the IRQ for the given PCI device, but doesn't wait for EMT to process + * the request when not called from EMT. + * + * @param pDevIns The device instance. + * @param iIrq IRQ number to set. + * @param iLevel IRQ level. + * @thread Any thread, but will involve the emulation thread. + */ +DECLINLINE(void) PDMDevHlpPCISetIrqNoWait(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, NULL, iIrq, iLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCISetIrqNoWait + */ +DECLINLINE(void) PDMDevHlpPCISetIrqNoWaitEx(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnPCISetIrq(pDevIns, pPciDev, iIrq, iLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnISASetIrq + */ +DECLINLINE(void) PDMDevHlpISASetIrq(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnISASetIrq(pDevIns, iIrq, iLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnISASetIrqNoWait + */ +DECLINLINE(void) PDMDevHlpISASetIrqNoWait(PPDMDEVINS pDevIns, int iIrq, int iLevel) +{ + pDevIns->CTX_SUFF(pHlp)->pfnISASetIrq(pDevIns, iIrq, iLevel); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnDriverAttach + */ +DECLINLINE(int) PDMDevHlpDriverAttach(PPDMDEVINS pDevIns, uint32_t iLun, PPDMIBASE pBaseInterface, PPDMIBASE *ppBaseInterface, const char *pszDesc) +{ + return pDevIns->pHlpR3->pfnDriverAttach(pDevIns, iLun, pBaseInterface, ppBaseInterface, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDriverDetach + */ +DECLINLINE(int) PDMDevHlpDriverDetach(PPDMDEVINS pDevIns, PPDMDRVINS pDrvIns, uint32_t fFlags) +{ + return pDevIns->pHlpR3->pfnDriverDetach(pDevIns, pDrvIns, fFlags); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDriverReconfigure + */ +DECLINLINE(int) PDMDevHlpDriverReconfigure(PPDMDEVINS pDevIns, uint32_t iLun, uint32_t cDepth, + const char * const *papszDrivers, PCFGMNODE *papConfigs, uint32_t fFlags) +{ + return pDevIns->pHlpR3->pfnDriverReconfigure(pDevIns, iLun, cDepth, papszDrivers, papConfigs, fFlags); +} + +/** + * Reconfigures with a single driver reattachement, no config, noflags. + * @sa PDMDevHlpDriverReconfigure + */ +DECLINLINE(int) PDMDevHlpDriverReconfigure1(PPDMDEVINS pDevIns, uint32_t iLun, const char *pszDriver0) +{ + return pDevIns->pHlpR3->pfnDriverReconfigure(pDevIns, iLun, 1, &pszDriver0, NULL, 0); +} + +/** + * Reconfigures with a two drivers reattachement, no config, noflags. + * @sa PDMDevHlpDriverReconfigure + */ +DECLINLINE(int) PDMDevHlpDriverReconfigure2(PPDMDEVINS pDevIns, uint32_t iLun, const char *pszDriver0, const char *pszDriver1) +{ + char const * apszDrivers[2]; + apszDrivers[0] = pszDriver0; + apszDrivers[1] = pszDriver1; + return pDevIns->pHlpR3->pfnDriverReconfigure(pDevIns, iLun, 2, apszDrivers, NULL, 0); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueueCreate + */ +DECLINLINE(int) PDMDevHlpQueueCreate(PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDEV pfnCallback, bool fRZEnabled, const char *pszName, PDMQUEUEHANDLE *phQueue) +{ + return pDevIns->pHlpR3->pfnQueueCreate(pDevIns, cbItem, cItems, cMilliesInterval, pfnCallback, fRZEnabled, pszName, phQueue); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnQueueAlloc + */ +DECLINLINE(PPDMQUEUEITEMCORE) PDMDevHlpQueueAlloc(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnQueueAlloc(pDevIns, hQueue); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueueInsert + */ +DECLINLINE(int) PDMDevHlpQueueInsert(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnQueueInsert(pDevIns, hQueue, pItem); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueueFlushIfNecessary + */ +DECLINLINE(bool) PDMDevHlpQueueFlushIfNecessary(PPDMDEVINS pDevIns, PDMQUEUEHANDLE hQueue) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnQueueFlushIfNecessary(pDevIns, hQueue); +} + +#ifdef IN_RING3 +/** + * @copydoc PDMDEVHLPR3::pfnTaskCreate + */ +DECLINLINE(int) PDMDevHlpTaskCreate(PPDMDEVINS pDevIns, uint32_t fFlags, const char *pszName, + PFNPDMTASKDEV pfnCallback, void *pvUser, PDMTASKHANDLE *phTask) +{ + return pDevIns->pHlpR3->pfnTaskCreate(pDevIns, fFlags, pszName, pfnCallback, pvUser, phTask); +} +#endif + +/** + * @copydoc PDMDEVHLPR3::pfnTaskTrigger + */ +DECLINLINE(int) PDMDevHlpTaskTrigger(PPDMDEVINS pDevIns, PDMTASKHANDLE hTask) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTaskTrigger(pDevIns, hTask); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventCreate + */ +DECLINLINE(int) PDMDevHlpSUPSemEventCreate(PPDMDEVINS pDevIns, PSUPSEMEVENT phEvent) +{ + return pDevIns->pHlpR3->pfnSUPSemEventCreate(pDevIns, phEvent); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventClose + */ +DECLINLINE(int) PDMDevHlpSUPSemEventClose(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent) +{ + return pDevIns->pHlpR3->pfnSUPSemEventClose(pDevIns, hEvent); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventSignal + */ +DECLINLINE(int) PDMDevHlpSUPSemEventSignal(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventSignal(pDevIns, hEvent); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventWaitNoResume + */ +DECLINLINE(int) PDMDevHlpSUPSemEventWaitNoResume(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint32_t cMillies) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventWaitNoResume(pDevIns, hEvent, cMillies); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventWaitNsAbsIntr + */ +DECLINLINE(int) PDMDevHlpSUPSemEventWaitNsAbsIntr(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t uNsTimeout) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventWaitNsAbsIntr(pDevIns, hEvent, uNsTimeout); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventWaitNsRelIntr + */ +DECLINLINE(int) PDMDevHlpSUPSemEventWaitNsRelIntr(PPDMDEVINS pDevIns, SUPSEMEVENT hEvent, uint64_t cNsTimeout) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventWaitNsRelIntr(pDevIns, hEvent, cNsTimeout); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventGetResolution + */ +DECLINLINE(uint32_t) PDMDevHlpSUPSemEventGetResolution(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventGetResolution(pDevIns); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiCreate + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiCreate(PPDMDEVINS pDevIns, PSUPSEMEVENTMULTI phEventMulti) +{ + return pDevIns->pHlpR3->pfnSUPSemEventMultiCreate(pDevIns, phEventMulti); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiClose + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiClose(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti) +{ + return pDevIns->pHlpR3->pfnSUPSemEventMultiClose(pDevIns, hEventMulti); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiSignal + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiSignal(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiSignal(pDevIns, hEventMulti); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiReset + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiReset(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiReset(pDevIns, hEventMulti); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiWaitNoResume + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiWaitNoResume(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint32_t cMillies) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiWaitNsRelIntr(pDevIns, hEventMulti, cMillies); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiWaitNsAbsIntr + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiWaitNsAbsIntr(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t uNsTimeout) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiWaitNsAbsIntr(pDevIns, hEventMulti, uNsTimeout); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiWaitNsRelIntr + */ +DECLINLINE(int) PDMDevHlpSUPSemEventMultiWaitNsRelIntr(PPDMDEVINS pDevIns, SUPSEMEVENTMULTI hEventMulti, uint64_t cNsTimeout) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiWaitNsRelIntr(pDevIns, hEventMulti, cNsTimeout); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSUPSemEventMultiGetResolution + */ +DECLINLINE(uint32_t) PDMDevHlpSUPSemEventMultiGetResolution(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSUPSemEventMultiGetResolution(pDevIns); +} + +#ifdef IN_RING3 + +/** + * Initializes a PDM critical section. + * + * The PDM critical sections are derived from the IPRT critical sections, but + * works in RC and R0 as well. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect Pointer to the critical section. + * @param SRC_POS Use RT_SRC_POS. + * @param pszNameFmt Format string for naming the critical section. + * For statistics and lock validation. + * @param ... Arguments for the format string. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) PDMDevHlpCritSectInit(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, ...) +{ + int rc; + va_list va; + va_start(va, pszNameFmt); + rc = pDevIns->pHlpR3->pfnCritSectInit(pDevIns, pCritSect, RT_SRC_POS_ARGS, pszNameFmt, va); + va_end(va); + return rc; +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnCritSectGetNop + */ +DECLINLINE(PPDMCRITSECT) PDMDevHlpCritSectGetNop(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectGetNop(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSetDeviceCritSect + */ +DECLINLINE(int) PDMDevHlpSetDeviceCritSect(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnSetDeviceCritSect(pDevIns, pCritSect); +} + +/** + * Enters a PDM critical section. + * + * @returns VINF_SUCCESS if entered successfully. + * @returns rcBusy when encountering a busy critical section in RC/R0. + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pDevIns The device instance. + * @param pCritSect The PDM critical section to enter. + * @param rcBusy The status code to return when we're in RC or R0 + * and the section is busy. Pass VINF_SUCCESS to + * acquired the critical section thru a ring-3 + * call if necessary. + * + * @note Even callers setting @a rcBusy to VINF_SUCCESS must either handle + * possible failures in ring-0 or at least apply + * PDM_CRITSECT_RELEASE_ASSERT_RC_DEV() to the return value of this + * function. + * + * @sa PDMCritSectEnter + */ +DECLINLINE(DECL_CHECK_RETURN(int)) PDMDevHlpCritSectEnter(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectEnter(pDevIns, pCritSect, rcBusy); +} + +/** + * Enters a PDM critical section, with location information for debugging. + * + * @returns VINF_SUCCESS if entered successfully. + * @returns rcBusy when encountering a busy critical section in RC/R0. + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pDevIns The device instance. + * @param pCritSect The PDM critical section to enter. + * @param rcBusy The status code to return when we're in RC or R0 + * and the section is busy. Pass VINF_SUCCESS to + * acquired the critical section thru a ring-3 + * call if necessary. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where to lock is being + * acquired from. Optional. + * @sa PDMCritSectEnterDebug + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectEnterDebug(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectEnterDebug(pDevIns, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS); +} + +/** + * Try enter a critical section. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pDevIns The device instance. + * @param pCritSect The critical section. + * @sa PDMCritSectTryEnter + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectTryEnter(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectTryEnter(pDevIns, pCritSect); +} + +/** + * Try enter a critical section, with location information for debugging. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_SEM_BUSY if the critsect was owned. + * @retval VERR_SEM_NESTED if nested enter on a no nesting section. (Asserted.) + * @retval VERR_SEM_DESTROYED if the critical section is delete before or + * during the operation. + * + * @param pDevIns The device instance. + * @param pCritSect The critical section. + * @param uId Some kind of locking location ID. Typically a + * return address up the stack. Optional (0). + * @param SRC_POS The source position where to lock is being + * acquired from. Optional. + * @sa PDMCritSectTryEnterDebug + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectTryEnterDebug(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectTryEnterDebug(pDevIns, pCritSect, uId, RT_SRC_POS_ARGS); +} + +/** + * Leaves a critical section entered with PDMCritSectEnter(). + * + * @returns Indication whether we really exited the critical section. + * @retval VINF_SUCCESS if we really exited. + * @retval VINF_SEM_NESTED if we only reduced the nesting count. + * @retval VERR_NOT_OWNER if you somehow ignore release assertions. + * + * @param pDevIns The device instance. + * @param pCritSect The PDM critical section to leave. + * @sa PDMCritSectLeave + */ +DECLINLINE(int) PDMDevHlpCritSectLeave(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectLeave(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectIsOwner + */ +DECLINLINE(bool) PDMDevHlpCritSectIsOwner(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectIsOwner(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectIsInitialized + */ +DECLINLINE(bool) PDMDevHlpCritSectIsInitialized(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectIsInitialized(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectHasWaiters + */ +DECLINLINE(bool) PDMDevHlpCritSectHasWaiters(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectHasWaiters(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectGetRecursion + */ +DECLINLINE(uint32_t) PDMDevHlpCritSectGetRecursion(PPDMDEVINS pDevIns, PCPDMCRITSECT pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectGetRecursion(pDevIns, pCritSect); +} + +#if defined(IN_RING3) || defined(IN_RING0) +/** + * @see PDMHCCritSectScheduleExitEvent + */ +DECLINLINE(int) PDMDevHlpCritSectScheduleExitEvent(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectScheduleExitEvent(pDevIns, pCritSect, hEventToSignal); +} +#endif + +/* Strict build: Remap the two enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMDevHlpCritSectEnter(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectEnterDebug((pDevIns), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDevHlpCritSectTryEnter(pDevIns, pCritSect) PDMDevHlpCritSectTryEnterDebug((pDevIns), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMDevHlpCritSectEnter(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectEnterDebug((pDevIns), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMDevHlpCritSectTryEnter(pDevIns, pCritSect) PDMDevHlpCritSectTryEnterDebug((pDevIns), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * Deletes the critical section. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect The PDM critical section to destroy. + * @sa PDMR3CritSectDelete + */ +DECLINLINE(int) PDMDevHlpCritSectDelete(PPDMDEVINS pDevIns, PPDMCRITSECT pCritSect) +{ + return pDevIns->pHlpR3->pfnCritSectDelete(pDevIns, pCritSect); +} + +/** + * Initializes a PDM read/write critical section. + * + * The PDM read/write critical sections are derived from the IPRT critical + * sections, but works in RC and R0 as well. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect Pointer to the read/write critical section. + * @param SRC_POS Use RT_SRC_POS. + * @param pszNameFmt Format string for naming the critical section. + * For statistics and lock validation. + * @param ... Arguments for the format string. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) PDMDevHlpCritSectRwInit(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RT_SRC_POS_DECL, + const char *pszNameFmt, ...) +{ + int rc; + va_list va; + va_start(va, pszNameFmt); + rc = pDevIns->pHlpR3->pfnCritSectRwInit(pDevIns, pCritSect, RT_SRC_POS_ARGS, pszNameFmt, va); + va_end(va); + return rc; +} + +/** + * Deletes the read/write critical section. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pCritSect The PDM read/write critical section to destroy. + * @sa PDMR3CritSectRwDelete + */ +DECLINLINE(int) PDMDevHlpCritSectRwDelete(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->pHlpR3->pfnCritSectRwDelete(pDevIns, pCritSect); +} + +#endif /* IN_RING3 */ + +/** + * @sa PDMCritSectRwEnterShared, PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + */ +DECLINLINE(DECL_CHECK_RETURN(int)) PDMDevHlpCritSectRwEnterShared(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwEnterShared(pDevIns, pCritSect, rcBusy); +} + +/** + * @sa PDMCritSectRwEnterSharedDebug, PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwEnterSharedDebug(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwEnterSharedDebug(pDevIns, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS); +} + +/** + * @sa PDMCritSectRwTryEnterShared + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwTryEnterShared(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwTryEnterShared(pDevIns, pCritSect); +} + +/** + * @sa PDMCritSectRwTryEnterSharedDebug + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwTryEnterSharedDebug(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwTryEnterSharedDebug(pDevIns, pCritSect, uId, RT_SRC_POS_ARGS); +} + +/** + * @sa PDMCritSectRwLeaveShared + */ +DECLINLINE(int) PDMDevHlpCritSectRwLeaveShared(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwLeaveShared(pDevIns, pCritSect); +} + +/** + * @sa PDMCritSectRwEnterExcl, PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + */ +DECLINLINE(DECL_CHECK_RETURN(int)) PDMDevHlpCritSectRwEnterExcl(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwEnterExcl(pDevIns, pCritSect, rcBusy); +} + +/** + * @sa PDMCritSectRwEnterExclDebug, PDM_CRITSECT_RELEASE_ASSERT_RC_DEV + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwEnterExclDebug(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwEnterExclDebug(pDevIns, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS); +} + +/** + * @sa PDMCritSectRwTryEnterExcl + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwTryEnterExcl(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwTryEnterExcl(pDevIns, pCritSect); +} + +/** + * @sa PDMCritSectRwTryEnterExclDebug + */ +DECLINLINE(DECL_CHECK_RETURN(int)) +PDMDevHlpCritSectRwTryEnterExclDebug(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwTryEnterExclDebug(pDevIns, pCritSect, uId, RT_SRC_POS_ARGS); +} + +/** + * @sa PDMCritSectRwLeaveExcl + */ +DECLINLINE(int) PDMDevHlpCritSectRwLeaveExcl(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwLeaveExcl(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwIsWriteOwner + */ +DECLINLINE(bool) PDMDevHlpCritSectRwIsWriteOwner(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwIsWriteOwner(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwIsReadOwner + */ +DECLINLINE(bool) PDMDevHlpCritSectRwIsReadOwner(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect, bool fWannaHear) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwIsReadOwner(pDevIns, pCritSect, fWannaHear); +} + +/** + * @see PDMCritSectRwGetWriteRecursion + */ +DECLINLINE(uint32_t) PDMDevHlpCritSectRwGetWriteRecursion(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwGetWriteRecursion(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwGetWriterReadRecursion + */ +DECLINLINE(uint32_t) PDMDevHlpCritSectRwGetWriterReadRecursion(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwGetWriterReadRecursion(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwGetReadCount + */ +DECLINLINE(uint32_t) PDMDevHlpCritSectRwGetReadCount(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwGetReadCount(pDevIns, pCritSect); +} + +/** + * @see PDMCritSectRwIsInitialized + */ +DECLINLINE(bool) PDMDevHlpCritSectRwIsInitialized(PPDMDEVINS pDevIns, PPDMCRITSECTRW pCritSect) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnCritSectRwIsInitialized(pDevIns, pCritSect); +} + +/* Strict build: Remap the two enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMDevHlpCritSectRwEnterShared(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectRwEnterSharedDebug((pDevIns), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDevHlpCritSectRwTryEnterShared(pDevIns, pCritSect) PDMDevHlpCritSectRwTryEnterSharedDebug((pDevIns), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDevHlpCritSectRwEnterExcl(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectRwEnterExclDebug((pDevIns), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDevHlpCritSectRwTryEnterExcl(pDevIns, pCritSect) PDMDevHlpCritSectRwTryEnterExclDebug((pDevIns), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMDevHlpCritSectRwEnterShared(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectRwEnterSharedDebug((pDevIns), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMDevHlpCritSectRwTryEnterShared(pDevIns, pCritSect) PDMDevHlpCritSectRwTryEnterSharedDebug((pDevIns), (pCritSect), 0, RT_SRC_POS) +# define PDMDevHlpCritSectRwEnterExcl(pDevIns, pCritSect, rcBusy) PDMDevHlpCritSectRwEnterExclDebug((pDevIns), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMDevHlpCritSectRwTryEnterExcl(pDevIns, pCritSect) PDMDevHlpCritSectRwTryEnterExclDebug((pDevIns), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @copydoc PDMDEVHLPR3::pfnThreadCreate + */ +DECLINLINE(int) PDMDevHlpThreadCreate(PPDMDEVINS pDevIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDEV pfnThread, + PFNPDMTHREADWAKEUPDEV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName) +{ + return pDevIns->pHlpR3->pfnThreadCreate(pDevIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName); +} + +/** + * @copydoc PDMR3ThreadDestroy + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadDestroy(PPDMDEVINS pDevIns, PPDMTHREAD pThread, int *pRcThread) +{ + return pDevIns->pHlpR3->pfnThreadDestroy(pThread, pRcThread); +} + +/** + * @copydoc PDMR3ThreadIAmSuspending + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadIAmSuspending(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + return pDevIns->pHlpR3->pfnThreadIAmSuspending(pThread); +} + +/** + * @copydoc PDMR3ThreadIAmRunning + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadIAmRunning(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + return pDevIns->pHlpR3->pfnThreadIAmRunning(pThread); +} + +/** + * @copydoc PDMR3ThreadSleep + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadSleep(PPDMDEVINS pDevIns, PPDMTHREAD pThread, RTMSINTERVAL cMillies) +{ + return pDevIns->pHlpR3->pfnThreadSleep(pThread, cMillies); +} + +/** + * @copydoc PDMR3ThreadSuspend + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadSuspend(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + return pDevIns->pHlpR3->pfnThreadSuspend(pThread); +} + +/** + * @copydoc PDMR3ThreadResume + * @param pDevIns The device instance. + */ +DECLINLINE(int) PDMDevHlpThreadResume(PPDMDEVINS pDevIns, PPDMTHREAD pThread) +{ + return pDevIns->pHlpR3->pfnThreadResume(pThread); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSetAsyncNotification + */ +DECLINLINE(int) PDMDevHlpSetAsyncNotification(PPDMDEVINS pDevIns, PFNPDMDEVASYNCNOTIFY pfnAsyncNotify) +{ + return pDevIns->pHlpR3->pfnSetAsyncNotification(pDevIns, pfnAsyncNotify); +} + +/** + * @copydoc PDMDEVHLPR3::pfnAsyncNotificationCompleted + */ +DECLINLINE(void) PDMDevHlpAsyncNotificationCompleted(PPDMDEVINS pDevIns) +{ + pDevIns->pHlpR3->pfnAsyncNotificationCompleted(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnA20Set + */ +DECLINLINE(void) PDMDevHlpA20Set(PPDMDEVINS pDevIns, bool fEnable) +{ + pDevIns->pHlpR3->pfnA20Set(pDevIns, fEnable); +} + +/** + * @copydoc PDMDEVHLPR3::pfnRTCRegister + */ +DECLINLINE(int) PDMDevHlpRTCRegister(PPDMDEVINS pDevIns, PCPDMRTCREG pRtcReg, PCPDMRTCHLP *ppRtcHlp) +{ + return pDevIns->pHlpR3->pfnRTCRegister(pDevIns, pRtcReg, ppRtcHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPCIBusRegister + */ +DECLINLINE(int) PDMDevHlpPCIBusRegister(PPDMDEVINS pDevIns, PPDMPCIBUSREGR3 pPciBusReg, PCPDMPCIHLPR3 *ppPciHlp, uint32_t *piBus) +{ + return pDevIns->pHlpR3->pfnPCIBusRegister(pDevIns, pPciBusReg, ppPciHlp, piBus); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIommuRegister + */ +DECLINLINE(int) PDMDevHlpIommuRegister(PPDMDEVINS pDevIns, PPDMIOMMUREGR3 pIommuReg, PCPDMIOMMUHLPR3 *ppIommuHlp, uint32_t *pidxIommu) +{ + return pDevIns->pHlpR3->pfnIommuRegister(pDevIns, pIommuReg, ppIommuHlp, pidxIommu); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPICRegister + */ +DECLINLINE(int) PDMDevHlpPICRegister(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp) +{ + return pDevIns->pHlpR3->pfnPICRegister(pDevIns, pPicReg, ppPicHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnApicRegister + */ +DECLINLINE(int) PDMDevHlpApicRegister(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnApicRegister(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnIoApicRegister + */ +DECLINLINE(int) PDMDevHlpIoApicRegister(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp) +{ + return pDevIns->pHlpR3->pfnIoApicRegister(pDevIns, pIoApicReg, ppIoApicHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnHpetRegister + */ +DECLINLINE(int) PDMDevHlpHpetRegister(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, PCPDMHPETHLPR3 *ppHpetHlpR3) +{ + return pDevIns->pHlpR3->pfnHpetRegister(pDevIns, pHpetReg, ppHpetHlpR3); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPciRawRegister + */ +DECLINLINE(int) PDMDevHlpPciRawRegister(PPDMDEVINS pDevIns, PPDMPCIRAWREG pPciRawReg, PCPDMPCIRAWHLPR3 *ppPciRawHlpR3) +{ + return pDevIns->pHlpR3->pfnPciRawRegister(pDevIns, pPciRawReg, ppPciRawHlpR3); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMACRegister + */ +DECLINLINE(int) PDMDevHlpDMACRegister(PPDMDEVINS pDevIns, PPDMDMACREG pDmacReg, PCPDMDMACHLP *ppDmacHlp) +{ + return pDevIns->pHlpR3->pfnDMACRegister(pDevIns, pDmacReg, ppDmacHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMARegister + */ +DECLINLINE(int) PDMDevHlpDMARegister(PPDMDEVINS pDevIns, unsigned uChannel, PFNDMATRANSFERHANDLER pfnTransferHandler, void *pvUser) +{ + return pDevIns->pHlpR3->pfnDMARegister(pDevIns, uChannel, pfnTransferHandler, pvUser); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMAReadMemory + */ +DECLINLINE(int) PDMDevHlpDMAReadMemory(PPDMDEVINS pDevIns, unsigned uChannel, void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbRead) +{ + return pDevIns->pHlpR3->pfnDMAReadMemory(pDevIns, uChannel, pvBuffer, off, cbBlock, pcbRead); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMAWriteMemory + */ +DECLINLINE(int) PDMDevHlpDMAWriteMemory(PPDMDEVINS pDevIns, unsigned uChannel, const void *pvBuffer, uint32_t off, uint32_t cbBlock, uint32_t *pcbWritten) +{ + return pDevIns->pHlpR3->pfnDMAWriteMemory(pDevIns, uChannel, pvBuffer, off, cbBlock, pcbWritten); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMASetDREQ + */ +DECLINLINE(int) PDMDevHlpDMASetDREQ(PPDMDEVINS pDevIns, unsigned uChannel, unsigned uLevel) +{ + return pDevIns->pHlpR3->pfnDMASetDREQ(pDevIns, uChannel, uLevel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMAGetChannelMode + */ +DECLINLINE(uint8_t) PDMDevHlpDMAGetChannelMode(PPDMDEVINS pDevIns, unsigned uChannel) +{ + return pDevIns->pHlpR3->pfnDMAGetChannelMode(pDevIns, uChannel); +} + +/** + * @copydoc PDMDEVHLPR3::pfnDMASchedule + */ +DECLINLINE(void) PDMDevHlpDMASchedule(PPDMDEVINS pDevIns) +{ + pDevIns->pHlpR3->pfnDMASchedule(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCMOSWrite + */ +DECLINLINE(int) PDMDevHlpCMOSWrite(PPDMDEVINS pDevIns, unsigned iReg, uint8_t u8Value) +{ + return pDevIns->pHlpR3->pfnCMOSWrite(pDevIns, iReg, u8Value); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCMOSRead + */ +DECLINLINE(int) PDMDevHlpCMOSRead(PPDMDEVINS pDevIns, unsigned iReg, uint8_t *pu8Value) +{ + return pDevIns->pHlpR3->pfnCMOSRead(pDevIns, iReg, pu8Value); +} + +/** + * @copydoc PDMDEVHLPR3::pfnCallR0 + */ +DECLINLINE(int) PDMDevHlpCallR0(PPDMDEVINS pDevIns, uint32_t uOperation, uint64_t u64Arg) +{ + return pDevIns->pHlpR3->pfnCallR0(pDevIns, uOperation, u64Arg); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMGetSuspendReason + */ +DECLINLINE(VMSUSPENDREASON) PDMDevHlpVMGetSuspendReason(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMGetSuspendReason(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMGetResumeReason + */ +DECLINLINE(VMRESUMEREASON) PDMDevHlpVMGetResumeReason(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMGetResumeReason(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGetUVM + */ +DECLINLINE(PUVM) PDMDevHlpGetUVM(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetUVM(pDevIns); +} + +#endif /* IN_RING3 || DOXYGEN_RUNNING */ + +#if !defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @copydoc PDMDEVHLPR0::pfnPCIBusSetUpContext + */ +DECLINLINE(int) PDMDevHlpPCIBusSetUpContext(PPDMDEVINS pDevIns, CTX_SUFF(PPDMPCIBUSREG) pPciBusReg, CTX_SUFF(PCPDMPCIHLP) *ppPciHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPCIBusSetUpContext(pDevIns, pPciBusReg, ppPciHlp); +} + +/** + * @copydoc PDMDEVHLPR0::pfnIommuSetUpContext + */ +DECLINLINE(int) PDMDevHlpIommuSetUpContext(PPDMDEVINS pDevIns, CTX_SUFF(PPDMIOMMUREG) pIommuReg, CTX_SUFF(PCPDMIOMMUHLP) *ppIommuHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnIommuSetUpContext(pDevIns, pIommuReg, ppIommuHlp); +} + +/** + * @copydoc PDMDEVHLPR0::pfnPICSetUpContext + */ +DECLINLINE(int) PDMDevHlpPICSetUpContext(PPDMDEVINS pDevIns, PPDMPICREG pPicReg, PCPDMPICHLP *ppPicHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPICSetUpContext(pDevIns, pPicReg, ppPicHlp); +} + +/** + * @copydoc PDMDEVHLPR0::pfnApicSetUpContext + */ +DECLINLINE(int) PDMDevHlpApicSetUpContext(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnApicSetUpContext(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR0::pfnIoApicSetUpContext + */ +DECLINLINE(int) PDMDevHlpIoApicSetUpContext(PPDMDEVINS pDevIns, PPDMIOAPICREG pIoApicReg, PCPDMIOAPICHLP *ppIoApicHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnIoApicSetUpContext(pDevIns, pIoApicReg, ppIoApicHlp); +} + +/** + * @copydoc PDMDEVHLPR0::pfnHpetSetUpContext + */ +DECLINLINE(int) PDMDevHlpHpetSetUpContext(PPDMDEVINS pDevIns, PPDMHPETREG pHpetReg, CTX_SUFF(PCPDMHPETHLP) *ppHpetHlp) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnHpetSetUpContext(pDevIns, pHpetReg, ppHpetHlp); +} + +#endif /* !IN_RING3 || DOXYGEN_RUNNING */ + +/** + * @copydoc PDMDEVHLPR3::pfnGetVM + */ +DECLINLINE(PVMCC) PDMDevHlpGetVM(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetVM(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGetVMCPU + */ +DECLINLINE(PVMCPUCC) PDMDevHlpGetVMCPU(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetVMCPU(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGetCurrentCpuId + */ +DECLINLINE(VMCPUID) PDMDevHlpGetCurrentCpuId(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetCurrentCpuId(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMTimeVirtGet + */ +DECLINLINE(uint64_t) PDMDevHlpTMTimeVirtGet(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTMTimeVirtGet(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMTimeVirtGetFreq + */ +DECLINLINE(uint64_t) PDMDevHlpTMTimeVirtGetFreq(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTMTimeVirtGetFreq(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnTMTimeVirtGetFreq + */ +DECLINLINE(uint64_t) PDMDevHlpTMTimeVirtGetNano(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTMTimeVirtGetNano(pDevIns); +} + +#ifdef IN_RING3 +/** + * @copydoc PDMDEVHLPR3::pfnTMCpuTicksPerSecond + */ +DECLINLINE(uint64_t) PDMDevHlpTMCpuTicksPerSecond(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnTMCpuTicksPerSecond(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnRegisterVMMDevHeap + */ +DECLINLINE(int) PDMDevHlpRegisterVMMDevHeap(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTR3PTR pvHeap, unsigned cbHeap) +{ + return pDevIns->pHlpR3->pfnRegisterVMMDevHeap(pDevIns, GCPhys, pvHeap, cbHeap); +} + +/** + * @copydoc PDMDEVHLPR3::pfnFirmwareRegister + */ +DECLINLINE(int) PDMDevHlpFirmwareRegister(PPDMDEVINS pDevIns, PCPDMFWREG pFwReg, PCPDMFWHLPR3 *ppFwHlp) +{ + return pDevIns->pHlpR3->pfnFirmwareRegister(pDevIns, pFwReg, ppFwHlp); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMReset + */ +DECLINLINE(int) PDMDevHlpVMReset(PPDMDEVINS pDevIns, uint32_t fFlags) +{ + return pDevIns->pHlpR3->pfnVMReset(pDevIns, fFlags); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMSuspend + */ +DECLINLINE(int) PDMDevHlpVMSuspend(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMSuspend(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMSuspendSaveAndPowerOff + */ +DECLINLINE(int) PDMDevHlpVMSuspendSaveAndPowerOff(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMSuspendSaveAndPowerOff(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMPowerOff + */ +DECLINLINE(int) PDMDevHlpVMPowerOff(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnVMPowerOff(pDevIns); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnA20IsEnabled + */ +DECLINLINE(bool) PDMDevHlpA20IsEnabled(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnA20IsEnabled(pDevIns); +} + +#ifdef IN_RING3 +/** + * @copydoc PDMDEVHLPR3::pfnGetCpuId + */ +DECLINLINE(void) PDMDevHlpGetCpuId(PPDMDEVINS pDevIns, uint32_t iLeaf, uint32_t *pEax, uint32_t *pEbx, uint32_t *pEcx, uint32_t *pEdx) +{ + pDevIns->pHlpR3->pfnGetCpuId(pDevIns, iLeaf, pEax, pEbx, pEcx, pEdx); +} +#endif + +/** + * @copydoc PDMDEVHLPR3::pfnGetMainExecutionEngine + */ +DECLINLINE(uint8_t) PDMDevHlpGetMainExecutionEngine(PPDMDEVINS pDevIns) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGetMainExecutionEngine(pDevIns); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnGetSupDrvSession + */ +DECLINLINE(PSUPDRVSESSION) PDMDevHlpGetSupDrvSession(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnGetSupDrvSession(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueryGenericUserObject + */ +DECLINLINE(void *) PDMDevHlpQueryGenericUserObject(PPDMDEVINS pDevIns, PCRTUUID pUuid) +{ + return pDevIns->pHlpR3->pfnQueryGenericUserObject(pDevIns, pUuid); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalTypeRegister + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalTypeRegister(PPDMDEVINS pDevIns, PGMPHYSHANDLERKIND enmKind, + PFNPGMPHYSHANDLER pfnHandler, const char *pszDesc, + PPGMPHYSHANDLERTYPE phType) +{ + return pDevIns->pHlpR3->pfnPGMHandlerPhysicalTypeRegister(pDevIns, enmKind, pfnHandler, pszDesc, phType); +} + +#elif defined(IN_RING0) + +/** + * @copydoc PDMDEVHLPR0::pfnPGMHandlerPhysicalTypeSetUpContext + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalTypeSetUpContext(PPDMDEVINS pDevIns, PGMPHYSHANDLERKIND enmKind, + PFNPGMPHYSHANDLER pfnHandler, PFNPGMRZPHYSPFHANDLER pfnPfHandler, + const char *pszDesc, PGMPHYSHANDLERTYPE hType) +{ + return pDevIns->pHlpR0->pfnPGMHandlerPhysicalTypeSetUpContext(pDevIns, enmKind, pfnHandler, pfnPfHandler, pszDesc, hType); +} + +#endif +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalRegister + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalRegister(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, + PGMPHYSHANDLERTYPE hType, R3PTRTYPE(const char *) pszDesc) +{ + return pDevIns->pHlpR3->pfnPGMHandlerPhysicalRegister(pDevIns, GCPhys, GCPhysLast, hType, pszDesc); +} + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalDeregister + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalDeregister(PPDMDEVINS pDevIns, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnPGMHandlerPhysicalDeregister(pDevIns, GCPhys); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalPageTempOff + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalPageTempOff(PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnPGMHandlerPhysicalPageTempOff(pDevIns, GCPhys, GCPhysPage); +} + +#ifdef IN_RING3 + +/** + * @copydoc PDMDEVHLPR3::pfnPGMHandlerPhysicalReset + */ +DECLINLINE(int) PDMDevHlpPGMHandlerPhysicalReset(PPDMDEVINS pDevIns, RTGCPHYS GCPhys) +{ + return pDevIns->pHlpR3->pfnPGMHandlerPhysicalReset(pDevIns, GCPhys); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMMRegisterPatchMemory + */ +DECLINLINE(int) PDMDevHlpVMMRegisterPatchMemory(PPDMDEVINS pDevIns, RTGCPTR GCPtrPatchMem, uint32_t cbPatchMem) +{ + return pDevIns->pHlpR3->pfnVMMRegisterPatchMemory(pDevIns, GCPtrPatchMem, cbPatchMem); +} + +/** + * @copydoc PDMDEVHLPR3::pfnVMMDeregisterPatchMemory + */ +DECLINLINE(int) PDMDevHlpVMMDeregisterPatchMemory(PPDMDEVINS pDevIns, RTGCPTR GCPtrPatchMem, uint32_t cbPatchMem) +{ + return pDevIns->pHlpR3->pfnVMMDeregisterPatchMemory(pDevIns, GCPtrPatchMem, cbPatchMem); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSharedModuleRegister + */ +DECLINLINE(int) PDMDevHlpSharedModuleRegister(PPDMDEVINS pDevIns, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule, + uint32_t cRegions, VMMDEVSHAREDREGIONDESC const *paRegions) +{ + return pDevIns->pHlpR3->pfnSharedModuleRegister(pDevIns, enmGuestOS, pszModuleName, pszVersion, + GCBaseAddr, cbModule, cRegions, paRegions); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSharedModuleUnregister + */ +DECLINLINE(int) PDMDevHlpSharedModuleUnregister(PPDMDEVINS pDevIns, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule) +{ + return pDevIns->pHlpR3->pfnSharedModuleUnregister(pDevIns, pszModuleName, pszVersion, GCBaseAddr, cbModule); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSharedModuleGetPageState + */ +DECLINLINE(int) PDMDevHlpSharedModuleGetPageState(PPDMDEVINS pDevIns, RTGCPTR GCPtrPage, bool *pfShared, + uint64_t *pfPageFlags) +{ + return pDevIns->pHlpR3->pfnSharedModuleGetPageState(pDevIns, GCPtrPage, pfShared, pfPageFlags); +} + +/** + * @copydoc PDMDEVHLPR3::pfnSharedModuleCheckAll + */ +DECLINLINE(int) PDMDevHlpSharedModuleCheckAll(PPDMDEVINS pDevIns) +{ + return pDevIns->pHlpR3->pfnSharedModuleCheckAll(pDevIns); +} + +/** + * @copydoc PDMDEVHLPR3::pfnQueryLun + */ +DECLINLINE(int) PDMDevHlpQueryLun(PPDMDEVINS pDevIns, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase) +{ + return pDevIns->pHlpR3->pfnQueryLun(pDevIns, pszDevice, iInstance, iLun, ppBase); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGIMDeviceRegister + */ +DECLINLINE(void) PDMDevHlpGIMDeviceRegister(PPDMDEVINS pDevIns, PGIMDEBUG pDbg) +{ + pDevIns->pHlpR3->pfnGIMDeviceRegister(pDevIns, pDbg); +} + +/** + * @copydoc PDMDEVHLPR3::pfnGIMGetDebugSetup + */ +DECLINLINE(int) PDMDevHlpGIMGetDebugSetup(PPDMDEVINS pDevIns, PGIMDEBUGSETUP pDbgSetup) +{ + return pDevIns->pHlpR3->pfnGIMGetDebugSetup(pDevIns, pDbgSetup); +} + +#endif /* IN_RING3 */ + +/** + * @copydoc PDMDEVHLPR3::pfnGIMGetMmio2Regions + */ +DECLINLINE(PGIMMMIO2REGION) PDMDevHlpGIMGetMmio2Regions(PPDMDEVINS pDevIns, uint32_t *pcRegions) +{ + return pDevIns->CTX_SUFF(pHlp)->pfnGIMGetMmio2Regions(pDevIns, pcRegions); +} + +#ifdef IN_RING3 + +/** Wrapper around SSMR3GetU32 for simplifying getting enum values saved as uint32_t. */ +# define PDMDEVHLP_SSM_GET_ENUM32_RET(a_pHlp, a_pSSM, a_enmDst, a_EnumType) \ + do { \ + uint32_t u32GetEnumTmp = 0; \ + int rcGetEnum32Tmp = (a_pHlp)->pfnSSMGetU32((a_pSSM), &u32GetEnumTmp); \ + AssertRCReturn(rcGetEnum32Tmp, rcGetEnum32Tmp); \ + (a_enmDst) = (a_EnumType)u32GetEnumTmp; \ + AssertCompile(sizeof(a_EnumType) == sizeof(u32GetEnumTmp)); \ + } while (0) + +/** Wrapper around SSMR3GetU8 for simplifying getting enum values saved as uint8_t. */ +# define PDMDEVHLP_SSM_GET_ENUM8_RET(a_pHlp, a_pSSM, a_enmDst, a_EnumType) \ + do { \ + uint8_t bGetEnumTmp = 0; \ + int rcGetEnum32Tmp = (a_pHlp)->pfnSSMGetU8((a_pSSM), &bGetEnumTmp); \ + AssertRCReturn(rcGetEnum32Tmp, rcGetEnum32Tmp); \ + (a_enmDst) = (a_EnumType)bGetEnumTmp; \ + } while (0) + +#endif /* IN_RING3 */ + +/** Pointer to callbacks provided to the VBoxDeviceRegister() call. */ +typedef struct PDMDEVREGCB *PPDMDEVREGCB; + +/** + * Callbacks for VBoxDeviceRegister(). + */ +typedef struct PDMDEVREGCB +{ + /** Interface version. + * This is set to PDM_DEVREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a device with the current VM instance. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param pReg Pointer to the device registration record. + * This data must be permanent and readonly. + */ + DECLR3CALLBACKMEMBER(int, pfnRegister,(PPDMDEVREGCB pCallbacks, PCPDMDEVREG pReg)); +} PDMDEVREGCB; + +/** Current version of the PDMDEVREGCB structure. */ +#define PDM_DEVREG_CB_VERSION PDM_VERSION_MAKE(0xffe3, 1, 0) + + +/** + * The VBoxDevicesRegister callback function. + * + * PDM will invoke this function after loading a device module and letting + * the module decide which devices to register and how to handle conflicts. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param u32Version VBox version number. + */ +typedef DECLCALLBACKTYPE(int, FNPDMVBOXDEVICESREGISTER,(PPDMDEVREGCB pCallbacks, uint32_t u32Version)); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmdev_h */ diff --git a/include/VBox/vmm/pdmdrv.h b/include/VBox/vmm/pdmdrv.h new file mode 100644 index 00000000..6c0ee40f --- /dev/null +++ b/include/VBox/vmm/pdmdrv.h @@ -0,0 +1,2497 @@ +/** @file + * PDM - Pluggable Device Manager, Drivers. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmdrv_h +#define VBOX_INCLUDED_vmm_pdmdrv_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#ifdef IN_RING3 +# include +# include +# include +#endif +#include +#include +#include +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_driver The PDM Drivers API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer const PDM Driver API, ring-3. */ +typedef R3PTRTYPE(struct PDMDRVHLPR3 const *) PCPDMDRVHLPR3; +/** Pointer const PDM Driver API, ring-0. */ +typedef R0PTRTYPE(struct PDMDRVHLPR0 const *) PCPDMDRVHLPR0; +/** Pointer const PDM Driver API, raw-mode context. */ +typedef RCPTRTYPE(struct PDMDRVHLPRC const *) PCPDMDRVHLPRC; + + +/** + * Construct a driver instance for a VM. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. If the registration structure + * is needed, it can be accessed thru pDrvIns->pReg. + * @param pCfg Configuration node handle for the driver. This is + * expected to be in high demand in the constructor and is + * therefore passed as an argument. When using it at other + * times, it can be accessed via pDrvIns->pCfg. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDRVCONSTRUCT,(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)); +/** Pointer to a FNPDMDRVCONSTRUCT() function. */ +typedef FNPDMDRVCONSTRUCT *PFNPDMDRVCONSTRUCT; + +/** + * Destruct a driver instance. + * + * Most VM resources are freed by the VM. This callback is provided so that + * any non-VM resources can be freed correctly. + * + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVDESTRUCT,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVDESTRUCT() function. */ +typedef FNPDMDRVDESTRUCT *PFNPDMDRVDESTRUCT; + +/** + * Driver relocation callback. + * + * This is called when the instance data has been relocated in raw-mode context + * (RC). It is also called when the RC hypervisor selects changes. The driver + * must fixup all necessary pointers and re-query all interfaces to other RC + * devices and drivers. + * + * Before the RC code is executed the first time, this function will be called + * with a 0 delta so RC pointer calculations can be one in one place. + * + * @param pDrvIns Pointer to the driver instance. + * @param offDelta The relocation delta relative to the old location. + * + * @remark A relocation CANNOT fail. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVRELOCATE,(PPDMDRVINS pDrvIns, RTGCINTPTR offDelta)); +/** Pointer to a FNPDMDRVRELOCATE() function. */ +typedef FNPDMDRVRELOCATE *PFNPDMDRVRELOCATE; + +/** + * Driver I/O Control interface. + * + * This is used by external components, such as the COM interface, to + * communicate with a driver using a driver specific interface. Generally, + * the driver interfaces are used for this task. + * + * @returns VBox status code. + * @param pDrvIns Pointer to the driver instance. + * @param uFunction Function to perform. + * @param pvIn Pointer to input data. + * @param cbIn Size of input data. + * @param pvOut Pointer to output data. + * @param cbOut Size of output data. + * @param pcbOut Where to store the actual size of the output data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDRVIOCTL,(PPDMDRVINS pDrvIns, uint32_t uFunction, + void *pvIn, uint32_t cbIn, + void *pvOut, uint32_t cbOut, uint32_t *pcbOut)); +/** Pointer to a FNPDMDRVIOCTL() function. */ +typedef FNPDMDRVIOCTL *PFNPDMDRVIOCTL; + +/** + * Power On notification. + * + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVPOWERON,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVPOWERON() function. */ +typedef FNPDMDRVPOWERON *PFNPDMDRVPOWERON; + +/** + * Reset notification. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVRESET,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVRESET() function. */ +typedef FNPDMDRVRESET *PFNPDMDRVRESET; + +/** + * Suspend notification. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVSUSPEND,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVSUSPEND() function. */ +typedef FNPDMDRVSUSPEND *PFNPDMDRVSUSPEND; + +/** + * Resume notification. + * + * @returns VBox status. + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVRESUME,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVRESUME() function. */ +typedef FNPDMDRVRESUME *PFNPDMDRVRESUME; + +/** + * Power Off notification. + * + * This is always called when VMR3PowerOff is called. + * There will be no callback when hot plugging devices or when replumbing the driver + * stack. + * + * @param pDrvIns The driver instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVPOWEROFF,(PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMDRVPOWEROFF() function. */ +typedef FNPDMDRVPOWEROFF *PFNPDMDRVPOWEROFF; + +/** + * Attach command. + * + * This is called to let the driver attach to a driver at runtime. This is not + * called during VM construction, the driver constructor have to do this by + * calling PDMDrvHlpAttach. + * + * This is like plugging in the keyboard or mouse after turning on the PC. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + */ +typedef DECLCALLBACKTYPE(int, FNPDMDRVATTACH,(PPDMDRVINS pDrvIns, uint32_t fFlags)); +/** Pointer to a FNPDMDRVATTACH() function. */ +typedef FNPDMDRVATTACH *PFNPDMDRVATTACH; + +/** + * Detach notification. + * + * This is called when a driver below it in the chain is detaching itself + * from it. The driver should adjust it's state to reflect this. + * + * This is like ejecting a cdrom or floppy. + * + * @param pDrvIns The driver instance. + * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG or 0. + */ +typedef DECLCALLBACKTYPE(void, FNPDMDRVDETACH,(PPDMDRVINS pDrvIns, uint32_t fFlags)); +/** Pointer to a FNPDMDRVDETACH() function. */ +typedef FNPDMDRVDETACH *PFNPDMDRVDETACH; + + + +/** + * PDM Driver Registration Structure. + * + * This structure is used when registering a driver from VBoxInitDrivers() (in + * host ring-3 context). PDM will continue use till the VM is terminated. + */ +typedef struct PDMDRVREG +{ + /** Structure version. PDM_DRVREG_VERSION defines the current version. */ + uint32_t u32Version; + /** Driver name. */ + char szName[32]; + /** Name of the raw-mode context module (no path). + * Only evalutated if PDM_DRVREG_FLAGS_RC is set. */ + char szRCMod[32]; + /** Name of the ring-0 module (no path). + * Only evalutated if PDM_DRVREG_FLAGS_R0 is set. */ + char szR0Mod[32]; + /** The description of the driver. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** Flags, combination of the PDM_DRVREG_FLAGS_* \#defines. */ + uint32_t fFlags; + /** Driver class(es), combination of the PDM_DRVREG_CLASS_* \#defines. */ + uint32_t fClass; + /** Maximum number of instances (per VM). */ + uint32_t cMaxInstances; + /** Size of the instance data. */ + uint32_t cbInstance; + + /** Construct instance - required. */ + PFNPDMDRVCONSTRUCT pfnConstruct; + /** Destruct instance - optional. */ + PFNPDMDRVDESTRUCT pfnDestruct; + /** Relocation command - optional. */ + PFNPDMDRVRELOCATE pfnRelocate; + /** I/O control - optional. */ + PFNPDMDRVIOCTL pfnIOCtl; + /** Power on notification - optional. */ + PFNPDMDRVPOWERON pfnPowerOn; + /** Reset notification - optional. */ + PFNPDMDRVRESET pfnReset; + /** Suspend notification - optional. */ + PFNPDMDRVSUSPEND pfnSuspend; + /** Resume notification - optional. */ + PFNPDMDRVRESUME pfnResume; + /** Attach command - optional. */ + PFNPDMDRVATTACH pfnAttach; + /** Detach notification - optional. */ + PFNPDMDRVDETACH pfnDetach; + /** Power off notification - optional. */ + PFNPDMDRVPOWEROFF pfnPowerOff; + /** @todo */ + PFNRT pfnSoftReset; + /** Initialization safty marker. */ + uint32_t u32VersionEnd; +} PDMDRVREG; +/** Pointer to a PDM Driver Structure. */ +typedef PDMDRVREG *PPDMDRVREG; +/** Const pointer to a PDM Driver Structure. */ +typedef PDMDRVREG const *PCPDMDRVREG; + +/** Current DRVREG version number. */ +#define PDM_DRVREG_VERSION PDM_VERSION_MAKE(0xf0ff, 1, 0) + +/** PDM Driver Flags. + * @{ */ +/** @def PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT + * The bit count for the current host. */ +#if HC_ARCH_BITS == 32 +# define PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT UINT32_C(0x00000001) +#elif HC_ARCH_BITS == 64 +# define PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT UINT32_C(0x00000002) +#else +# error Unsupported HC_ARCH_BITS value. +#endif +/** The host bit count mask. */ +#define PDM_DRVREG_FLAGS_HOST_BITS_MASK UINT32_C(0x00000003) +/** This flag is used to indicate that the driver has a RC component. */ +#define PDM_DRVREG_FLAGS_RC UINT32_C(0x00000010) +/** This flag is used to indicate that the driver has a R0 component. */ +#define PDM_DRVREG_FLAGS_R0 UINT32_C(0x00000020) + +/** @} */ + + +/** PDM Driver Classes. + * @{ */ +/** Mouse input driver. */ +#define PDM_DRVREG_CLASS_MOUSE RT_BIT(0) +/** Keyboard input driver. */ +#define PDM_DRVREG_CLASS_KEYBOARD RT_BIT(1) +/** Display driver. */ +#define PDM_DRVREG_CLASS_DISPLAY RT_BIT(2) +/** Network transport driver. */ +#define PDM_DRVREG_CLASS_NETWORK RT_BIT(3) +/** Block driver. */ +#define PDM_DRVREG_CLASS_BLOCK RT_BIT(4) +/** Media driver. */ +#define PDM_DRVREG_CLASS_MEDIA RT_BIT(5) +/** Mountable driver. */ +#define PDM_DRVREG_CLASS_MOUNTABLE RT_BIT(6) +/** Audio driver. */ +#define PDM_DRVREG_CLASS_AUDIO RT_BIT(7) +/** VMMDev driver. */ +#define PDM_DRVREG_CLASS_VMMDEV RT_BIT(8) +/** Status driver. */ +#define PDM_DRVREG_CLASS_STATUS RT_BIT(9) +/** ACPI driver. */ +#define PDM_DRVREG_CLASS_ACPI RT_BIT(10) +/** USB related driver. */ +#define PDM_DRVREG_CLASS_USB RT_BIT(11) +/** ISCSI Transport related driver. */ +#define PDM_DRVREG_CLASS_ISCSITRANSPORT RT_BIT(12) +/** Char driver. */ +#define PDM_DRVREG_CLASS_CHAR RT_BIT(13) +/** Stream driver. */ +#define PDM_DRVREG_CLASS_STREAM RT_BIT(14) +/** SCSI driver. */ +#define PDM_DRVREG_CLASS_SCSI RT_BIT(15) +/** Generic raw PCI device driver. */ +#define PDM_DRVREG_CLASS_PCIRAW RT_BIT(16) +/** @} */ + + +/** + * PDM Driver Instance. + * + * @implements PDMIBASE + */ +typedef struct PDMDRVINS +{ + /** Structure version. PDM_DRVINS_VERSION defines the current version. */ + uint32_t u32Version; + /** Driver instance number. */ + uint32_t iInstance; + + /** Pointer the PDM Driver API. */ + RCPTRTYPE(PCPDMDRVHLPRC) pHlpRC; + /** Pointer to driver instance data. */ + RCPTRTYPE(void *) pvInstanceDataRC; + + /** Pointer the PDM Driver API. */ + R0PTRTYPE(PCPDMDRVHLPR0) pHlpR0; + /** Pointer to driver instance data. */ + R0PTRTYPE(void *) pvInstanceDataR0; + + /** Pointer the PDM Driver API. */ + R3PTRTYPE(PCPDMDRVHLPR3) pHlpR3; + /** Pointer to driver instance data. */ + R3PTRTYPE(void *) pvInstanceDataR3; + + /** Pointer to driver registration structure. */ + R3PTRTYPE(PCPDMDRVREG) pReg; + /** Configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfg; + + /** Pointer to the base interface of the device/driver instance above. */ + R3PTRTYPE(PPDMIBASE) pUpBase; + /** Pointer to the base interface of the driver instance below. */ + R3PTRTYPE(PPDMIBASE) pDownBase; + + /** The base interface of the driver. + * The driver constructor initializes this. */ + PDMIBASE IBase; + + /** Tracing indicator. */ + uint32_t fTracing; + /** The tracing ID of this device. */ + uint32_t idTracing; +#if HC_ARCH_BITS == 32 + /** Align the internal data more naturally. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 7 : 0]; +#endif + + /** Internal data. */ + union + { +#ifdef PDMDRVINSINT_DECLARED + PDMDRVINSINT s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 40 + 32 : 72 + 24]; + } Internal; + + /** Driver instance data. The size of this area is defined + * in the PDMDRVREG::cbInstanceData field. */ + char achInstanceData[4]; +} PDMDRVINS; + +/** Current DRVREG version number. */ +#define PDM_DRVINS_VERSION PDM_VERSION_MAKE(0xf0fe, 2, 0) + +/** Converts a pointer to the PDMDRVINS::IBase to a pointer to PDMDRVINS. */ +#define PDMIBASE_2_PDMDRV(pInterface) ( (PPDMDRVINS)((char *)(pInterface) - RT_UOFFSETOF(PDMDRVINS, IBase)) ) + +/** @def PDMDRVINS_2_RCPTR + * Converts a PDM Driver instance pointer a RC PDM Driver instance pointer. + */ +#define PDMDRVINS_2_RCPTR(pDrvIns) ( (RCPTRTYPE(PPDMDRVINS))((RTRCUINTPTR)(pDrvIns)->pvInstanceDataRC - (RTRCUINTPTR)RT_UOFFSETOF(PDMDRVINS, achInstanceData)) ) + +/** @def PDMDRVINS_2_R3PTR + * Converts a PDM Driver instance pointer a R3 PDM Driver instance pointer. + */ +#define PDMDRVINS_2_R3PTR(pDrvIns) ( (R3PTRTYPE(PPDMDRVINS))((RTHCUINTPTR)(pDrvIns)->pvInstanceDataR3 - RT_UOFFSETOF(PDMDRVINS, achInstanceData)) ) + +/** @def PDMDRVINS_2_R0PTR + * Converts a PDM Driver instance pointer a R0 PDM Driver instance pointer. + */ +#define PDMDRVINS_2_R0PTR(pDrvIns) ( (R0PTRTYPE(PPDMDRVINS))((RTR0UINTPTR)(pDrvIns)->pvInstanceDataR0 - RT_UOFFSETOF(PDMDRVINS, achInstanceData)) ) + + + +/** + * Checks the structure versions of the drive instance and driver helpers, + * returning if they are incompatible. + * + * Intended for the constructor. + * + * @param pDrvIns Pointer to the PDM driver instance. + */ +#define PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns) \ + do \ + { \ + PPDMDRVINS pDrvInsTypeCheck = (pDrvIns); NOREF(pDrvInsTypeCheck); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->u32Version, PDM_DRVINS_VERSION), \ + ("DrvIns=%#x mine=%#x\n", (pDrvIns)->u32Version, PDM_DRVINS_VERSION), \ + VERR_PDM_DRVINS_VERSION_MISMATCH); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->pHlpR3->u32Version, PDM_DRVHLPR3_VERSION), \ + ("DrvHlp=%#x mine=%#x\n", (pDrvIns)->pHlpR3->u32Version, PDM_DRVHLPR3_VERSION), \ + VERR_PDM_DRVHLPR3_VERSION_MISMATCH); \ + } while (0) + +/** + * Quietly checks the structure versions of the drive instance and driver + * helpers, returning if they are incompatible. + * + * Intended for the destructor. + * + * @param pDrvIns Pointer to the PDM driver instance. + */ +#define PDMDRV_CHECK_VERSIONS_RETURN_VOID(pDrvIns) \ + do \ + { \ + PPDMDRVINS pDrvInsTypeCheck = (pDrvIns); NOREF(pDrvInsTypeCheck); \ + if (RT_LIKELY( PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->u32Version, PDM_DRVINS_VERSION) \ + && PDM_VERSION_ARE_COMPATIBLE((pDrvIns)->pHlpR3->u32Version, PDM_DRVHLPR3_VERSION)) ) \ + { /* likely */ } else return; \ + } while (0) + +/** + * Wrapper around CFGMR3ValidateConfig for the root config for use in the + * constructor - returns on failure. + * + * This should be invoked after having initialized the instance data + * sufficiently for the correct operation of the destructor. The destructor is + * always called! + * + * @param pDrvIns Pointer to the PDM driver instance. + * @param pszValidValues Patterns describing the valid value names. See + * RTStrSimplePatternMultiMatch for details on the + * pattern syntax. + * @param pszValidNodes Patterns describing the valid node (key) names. + * Pass empty string if no valid nodess. + */ +#define PDMDRV_VALIDATE_CONFIG_RETURN(pDrvIns, pszValidValues, pszValidNodes) \ + do \ + { \ + int rcValCfg = pDrvIns->pHlpR3->pfnCFGMValidateConfig((pDrvIns)->pCfg, "/", pszValidValues, pszValidNodes, \ + (pDrvIns)->pReg->szName, (pDrvIns)->iInstance); \ + if (RT_SUCCESS(rcValCfg)) \ + { /* likely */ } else return rcValCfg; \ + } while (0) + + + +/** + * USB hub registration structure. + */ +typedef struct PDMUSBHUBREG +{ + /** Structure version number. PDM_USBHUBREG_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Request the hub to attach of the specified device. + * + * @returns VBox status code. + * @param pDrvIns The hub instance. + * @param pUsbIns The device to attach. + * @param pszCaptureFilename Path to the file for USB traffic capturing, optional. + * @param piPort Where to store the port number the device was attached to. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnAttachDevice,(PPDMDRVINS pDrvIns, PPDMUSBINS pUsbIns, const char *pszCaptureFilename, uint32_t *piPort)); + + /** + * Request the hub to detach of the specified device. + * + * The device has previously been attached to the hub with the + * pfnAttachDevice call. This call is not currently expected to + * fail. + * + * @returns VBox status code. + * @param pDrvIns The hub instance. + * @param pUsbIns The device to detach. + * @param iPort The port number returned by the attach call. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnDetachDevice,(PPDMDRVINS pDrvIns, PPDMUSBINS pUsbIns, uint32_t iPort)); + + /** Counterpart to u32Version, same value. */ + uint32_t u32TheEnd; +} PDMUSBHUBREG; +/** Pointer to a const USB hub registration structure. */ +typedef const PDMUSBHUBREG *PCPDMUSBHUBREG; + +/** Current PDMUSBHUBREG version number. */ +#define PDM_USBHUBREG_VERSION PDM_VERSION_MAKE(0xf0fd, 2, 0) + + +/** + * USB hub helpers. + * This is currently just a place holder. + */ +typedef struct PDMUSBHUBHLP +{ + /** Structure version. PDM_USBHUBHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMUSBHUBHLP; +/** Pointer to PCI helpers. */ +typedef PDMUSBHUBHLP *PPDMUSBHUBHLP; +/** Pointer to const PCI helpers. */ +typedef const PDMUSBHUBHLP *PCPDMUSBHUBHLP; +/** Pointer to const PCI helpers pointer. */ +typedef PCPDMUSBHUBHLP *PPCPDMUSBHUBHLP; + +/** Current PDMUSBHUBHLP version number. */ +#define PDM_USBHUBHLP_VERSION PDM_VERSION_MAKE(0xf0fc, 1, 0) + + +/** + * PDM Driver API - raw-mode context variant. + */ +typedef struct PDMDRVHLPRC +{ + /** Structure version. PDM_DRVHLPRC_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLRCCALLBACKMEMBER(bool, pfnAssertEMT,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLRCCALLBACKMEMBER(bool, pfnAssertOther,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLRCCALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLRCCALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLRCCALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLRCCALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + /** @} */ + + /** + * Obtains bandwidth in a bandwidth group. + * + * @returns True if bandwidth was allocated, false if not. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter that allocates bandwidth. + * @param cbTransfer Number of bytes to allocate. + */ + DECLRCCALLBACKMEMBER(bool, pfnNetShaperAllocateBandwidth,(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDRVHLPRC; +/** Current PDMDRVHLPRC version number. */ +#define PDM_DRVHLPRC_VERSION PDM_VERSION_MAKE(0xf0f9, 6, 0) + + +/** + * PDM Driver API, ring-0 context. + */ +typedef struct PDMDRVHLPR0 +{ + /** Structure version. PDM_DRVHLPR0_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR0CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR0CALLBACKMEMBER(bool, pfnAssertOther,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLR0CALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR0CALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR0CALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR0CALLBACKMEMBER(int, pfnCritSectScheduleExitEvent,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)); + /** @} */ + + /** + * Obtains bandwidth in a bandwidth group. + * + * @returns True if bandwidth was allocated, false if not. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter that allocates bandwidth. + * @param cbTransfer Number of bytes to allocate. + */ + DECLR0CALLBACKMEMBER(bool, pfnNetShaperAllocateBandwidth,(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer)); + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDRVHLPR0; +/** Current DRVHLP version number. */ +#define PDM_DRVHLPR0_VERSION PDM_VERSION_MAKE(0xf0f8, 6, 0) + + +#ifdef IN_RING3 + +/** + * PDM Driver API. + */ +typedef struct PDMDRVHLPR3 +{ + /** Structure version. PDM_DRVHLPR3_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Attaches a driver (chain) to the driver. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG or 0. + * @param ppBaseInterface Where to store the pointer to the base interface. + */ + DECLR3CALLBACKMEMBER(int, pfnAttach,(PPDMDRVINS pDrvIns, uint32_t fFlags, PPDMIBASE *ppBaseInterface)); + + /** + * Detach the driver the drivers below us. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG or 0. + */ + DECLR3CALLBACKMEMBER(int, pfnDetach,(PPDMDRVINS pDrvIns, uint32_t fFlags)); + + /** + * Detach the driver from the driver above it and destroy this + * driver and all drivers below it. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags PDM_TACH_FLAGS_NOT_HOT_PLUG or 0. + */ + DECLR3CALLBACKMEMBER(int, pfnDetachSelf,(PPDMDRVINS pDrvIns, uint32_t fFlags)); + + /** + * Prepare a media mount. + * + * The driver must not have anything attached to itself + * when calling this function as the purpose is to set up the configuration + * of an future attachment. + * + * @returns VBox status code + * @param pDrvIns Driver instance. + * @param pszFilename Pointer to filename. If this is NULL it assumed that the caller have + * constructed a configuration which can be attached to the bottom driver. + * @param pszCoreDriver Core driver name. NULL will cause autodetection. Ignored if pszFilanem is NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnMountPrepare,(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver)); + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pDrvIns Driver instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertOther,(PPDMDRVINS pDrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetErrorV,(PPDMDRVINS pDrvIns, int rc, RT_SRC_POS_DECL, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetRuntimeErrorV,(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(4, 0)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pDrvIns The driver instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLR3CALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMDRVINS pDrvIns)); + + /** + * Checks if the VM was teleported and hasn't been fully resumed yet. + * + * @returns true / false. + * @param pDrvIns The driver instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnVMTeleportedAndNotFullyResumedYet,(PPDMDRVINS pDrvIns)); + + /** + * Gets the support driver session. + * + * This is intended for working using the semaphore API. + * + * @returns Support driver session handle. + * @param pDrvIns The driver instance. + */ + DECLR3CALLBACKMEMBER(PSUPDRVSESSION, pfnGetSupDrvSession,(PPDMDRVINS pDrvIns)); + + /** @name Exported PDM Queue Functions + * @{ */ + /** + * Create a queue. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param cbItem Size a queue item. + * @param cItems Number of items in the queue. + * @param cMilliesInterval Number of milliseconds between polling the queue. + * If 0 then the emulation thread will be notified whenever an item arrives. + * @param pfnCallback The consumer function. + * @param pszName The queue base name. The instance number will be + * appended automatically. + * @param phQueue Where to store the queue handle on success. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueueCreate,(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDRV pfnCallback, const char *pszName, PDMQUEUEHANDLE *phQueue)); + + DECLR3CALLBACKMEMBER(PPDMQUEUEITEMCORE, pfnQueueAlloc,(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue)); + DECLR3CALLBACKMEMBER(int, pfnQueueInsert,(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem)); + DECLR3CALLBACKMEMBER(bool, pfnQueueFlushIfNecessary,(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue)); + /** @} */ + + /** + * Query the virtual timer frequency. + * + * @returns Frequency in Hz. + * @param pDrvIns Driver instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMGetVirtualFreq,(PPDMDRVINS pDrvIns)); + + /** + * Query the virtual time. + * + * @returns The current virtual time. + * @param pDrvIns Driver instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMGetVirtualTime,(PPDMDRVINS pDrvIns)); + + /** + * Creates a timer. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param enmClock The clock to use on this timer. + * @param pfnCallback Callback function. + * @param pvUser The user argument to the callback. + * @param fFlags Timer creation flags, see grp_tm_timer_flags. + * @param pszDesc Pointer to description string which must stay around + * until the timer is fully destroyed (i.e. a bit after TMTimerDestroy()). + * @param phTimer Where to store the timer handle on success. + * @thread EMT + * + * @todo Need to add a bunch of timer helpers for this to be useful again. + * Will do when required. + */ + DECLR3CALLBACKMEMBER(int, pfnTimerCreate,(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)); + + /** + * Destroys a timer. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param hTimer The timer handle to destroy. + */ + DECLR3CALLBACKMEMBER(int, pfnTimerDestroy,(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer)); + + /** + * Register a save state data unit. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * + * @param pfnLivePrep Prepare live save callback, optional. + * @param pfnLiveExec Execute live save callback, optional. + * @param pfnLiveVote Vote live save callback, optional. + * + * @param pfnSavePrep Prepare save callback, optional. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnSaveDone Done save callback, optional. + * + * @param pfnLoadPrep Prepare load callback, optional. + * @param pfnLoadExec Execute load callback, optional. + * @param pfnLoadDone Done load callback, optional. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMRegister,(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote, + PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone, + PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone)); + + /** + * Deregister a save state data unit. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param pszName Data unit name. + * @param uInstance The instance identifier of the data unit. + * This must together with the name be unique. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMDeregister,(PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance)); + + /** @name Exported SSM Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnSSMPutStruct,(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStructEx,(PSSMHANDLE pSSM, const void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutBool,(PSSMHANDLE pSSM, bool fBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU8,(PSSMHANDLE pSSM, uint8_t u8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS8,(PSSMHANDLE pSSM, int8_t i8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU16,(PSSMHANDLE pSSM, uint16_t u16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS16,(PSSMHANDLE pSSM, int16_t i16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU32,(PSSMHANDLE pSSM, uint32_t u32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS32,(PSSMHANDLE pSSM, int32_t i32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU64,(PSSMHANDLE pSSM, uint64_t u64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS64,(PSSMHANDLE pSSM, int64_t i64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU128,(PSSMHANDLE pSSM, uint128_t u128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS128,(PSSMHANDLE pSSM, int128_t i128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutUInt,(PSSMHANDLE pSSM, RTUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSInt,(PSSMHANDLE pSSM, RTINT i)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUInt,(PSSMHANDLE pSSM, RTGCUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntReg,(PSSMHANDLE pSSM, RTGCUINTREG u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys32,(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys64,(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys,(PSSMHANDLE pSSM, RTGCPHYS GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPtr,(PSSMHANDLE pSSM, RTGCPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntPtr,(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutRCPtr,(PSSMHANDLE pSSM, RTRCPTR RCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutIOPort,(PSSMHANDLE pSSM, RTIOPORT IOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSel,(PSSMHANDLE pSSM, RTSEL Sel)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutMem,(PSSMHANDLE pSSM, const void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStrZ,(PSSMHANDLE pSSM, const char *psz)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStruct,(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStructEx,(PSSMHANDLE pSSM, void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBool,(PSSMHANDLE pSSM, bool *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBoolV,(PSSMHANDLE pSSM, bool volatile *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8,(PSSMHANDLE pSSM, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8V,(PSSMHANDLE pSSM, uint8_t volatile *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8,(PSSMHANDLE pSSM, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8V,(PSSMHANDLE pSSM, int8_t volatile *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16,(PSSMHANDLE pSSM, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16V,(PSSMHANDLE pSSM, uint16_t volatile *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16,(PSSMHANDLE pSSM, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16V,(PSSMHANDLE pSSM, int16_t volatile *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32,(PSSMHANDLE pSSM, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32V,(PSSMHANDLE pSSM, uint32_t volatile *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32,(PSSMHANDLE pSSM, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32V,(PSSMHANDLE pSSM, int32_t volatile *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64,(PSSMHANDLE pSSM, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64V,(PSSMHANDLE pSSM, uint64_t volatile *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64,(PSSMHANDLE pSSM, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64V,(PSSMHANDLE pSSM, int64_t volatile *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128,(PSSMHANDLE pSSM, uint128_t *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128V,(PSSMHANDLE pSSM, uint128_t volatile *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128,(PSSMHANDLE pSSM, int128_t *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128V,(PSSMHANDLE pSSM, int128_t volatile *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32,(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32V,(PSSMHANDLE pSSM, RTGCPHYS32 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64,(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64V,(PSSMHANDLE pSSM, RTGCPHYS64 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys,(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhysV,(PSSMHANDLE pSSM, RTGCPHYS volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetUInt,(PSSMHANDLE pSSM, PRTUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSInt,(PSSMHANDLE pSSM, PRTINT pi)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUInt,(PSSMHANDLE pSSM, PRTGCUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntReg,(PSSMHANDLE pSSM, PRTGCUINTREG pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPtr,(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntPtr,(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetRCPtr,(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetIOPort,(PSSMHANDLE pSSM, PRTIOPORT pIOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSel,(PSSMHANDLE pSSM, PRTSEL pSel)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetMem,(PSSMHANDLE pSSM, void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZ,(PSSMHANDLE pSSM, char *psz, size_t cbMax)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZEx,(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkip,(PSSMHANDLE pSSM, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkipToEndOfUnit,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadError,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadErrorV,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgError,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgErrorV,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMHandleGetStatus,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(SSMAFTER, pfnSSMHandleGetAfter,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(bool, pfnSSMHandleIsLiveSave,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleMaxDowntime,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleHostBits,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleRevision,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleVersion,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(const char *, pfnSSMHandleHostOSAndArch,(PSSMHANDLE pSSM)); + /** @} */ + + /** @name Exported CFGM Functions. + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCFGMExists,( PCFGMNODE pNode, const char *pszName)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryType,( PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySize,( PCFGMNODE pNode, const char *pszName, size_t *pcb)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryInteger,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryIntegerDef,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryString,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPassword,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPasswordDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBytes,( PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64Def,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64,( PCFGMNODE pNode, const char *pszName, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64Def,( PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32Def,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32,( PCFGMNODE pNode, const char *pszName, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32Def,( PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16Def,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16,( PCFGMNODE pNode, const char *pszName, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16Def,( PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8Def,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8,( PCFGMNODE pNode, const char *pszName, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8Def,( PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBool,( PCFGMNODE pNode, const char *pszName, bool *pf)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBoolDef,( PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPort,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPortDef,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUInt,( PCFGMNODE pNode, const char *pszName, unsigned int *pu)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUIntDef,( PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySInt,( PCFGMNODE pNode, const char *pszName, signed int *pi)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySIntDef,( PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtr,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrDef,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrU,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrUDef,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrS,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrSDef,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAlloc,( PCFGMNODE pNode, const char *pszName, char **ppszString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAllocDef,(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetParent,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChild,(PCFGMNODE pNode, const char *pszPath)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildF,(PCFGMNODE pNode, const char *pszPathFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildFV,(PCFGMNODE pNode, const char *pszPathFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetFirstChild,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetNextChild,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetName,(PCFGMNODE pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetNameLen,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreChildrenValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetFirstValue,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetNextValue,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetValueName,(PCFGMLEAF pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetValueNameLen,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(CFGMVALUETYPE, pfnCFGMGetValueType,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreValuesValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(int, pfnCFGMValidateConfig,(PCFGMNODE pNode, const char *pszNode, + const char *pszValidValues, const char *pszValidNodes, + const char *pszWho, uint32_t uInstance)); + /** @} */ + + /** + * Free memory allocated with pfnMMHeapAlloc() and pfnMMHeapAllocZ(). + * + * @param pDrvIns Driver instance. + * @param pv Pointer to the memory to free. + */ + DECLR3CALLBACKMEMBER(void, pfnMMHeapFree,(PPDMDRVINS pDrvIns, void *pv)); + + /** + * Register an info handler with DBGF. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param pszName Data unit name. + * @param pszDesc The description of the info and any arguments + * the handler may take. + * @param pfnHandler The handler function to be called to display the + * info. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoRegister,(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler)); + + /** + * Register an info handler with DBGF, argv style. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param pszName Data unit name. + * @param pszDesc The description of the info and any arguments + * the handler may take. + * @param pfnHandler The handler function to be called to display the + * info. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoRegisterArgv,(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDRV pfnHandler)); + + /** + * Deregister an info handler from DBGF. + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param pszName Data unit name. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoDeregister,(PPDMDRVINS pDrvIns, const char *pszName)); + + /** + * Registers a statistics sample if statistics are enabled. + * + * @param pDrvIns Driver instance. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "//". + * Further nesting is possible. If this does not start + * with a '/', the default prefix will be prepended, + * otherwise it will be used as-is. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegister,(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName, + STAMUNIT enmUnit, const char *pszDesc)); + + /** + * Same as pfnSTAMRegister except that the name is specified in a + * RTStrPrintf like fashion. + * + * @param pDrvIns Driver instance. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName The sample name format string. If this does not start + * with a '/', the default prefix will be prepended, + * otherwise it will be used as-is. + * @param ... Arguments to the format string. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegisterF,(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, + const char *pszName, ...) RT_IPRT_FORMAT_ATTR(7, 8)); + + /** + * Same as pfnSTAMRegister except that the name is specified in a + * RTStrPrintfV like fashion. + * + * @param pDrvIns Driver instance. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName The sample name format string. If this does not + * start with a '/', the default prefix will be prepended, + * otherwise it will be used as-is. + * @param args Arguments to the format string. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegisterV,(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, const char *pszDesc, + const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(7, 0)); + + /** + * Deregister a statistic item previously registered with pfnSTAMRegister, + * pfnSTAMRegisterF or pfnSTAMRegisterV + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param pvSample Pointer to the sample. + */ + DECLR3CALLBACKMEMBER(int, pfnSTAMDeregister,(PPDMDRVINS pDrvIns, void *pvSample)); + + /** + * Calls the HC R0 VMM entry point, in a safer but slower manner than + * SUPR3CallVMMR0. + * + * When entering using this call the R0 components can call into the host kernel + * (i.e. use the SUPR0 and RT APIs). + * + * See VMMR0Entry() for more details. + * + * @returns error code specific to uFunction. + * @param pDrvIns The driver instance. + * @param uOperation Operation to execute. + * This is limited to services. + * @param pvArg Pointer to argument structure or if cbArg is 0 just an value. + * @param cbArg The size of the argument. This is used to copy whatever the argument + * points at into a kernel buffer to avoid problems like the user page + * being invalidated while we're executing the call. + */ + DECLR3CALLBACKMEMBER(int, pfnSUPCallVMMR0Ex,(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg)); + + /** + * Registers a USB HUB. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param fVersions Indicates the kinds of USB devices that can be attached to this HUB. + * @param cPorts The number of ports. + * @param pUsbHubReg The hub callback structure that PDMUsb uses to interact with it. + * @param ppUsbHubHlp The helper callback structure that the hub uses to talk to PDMUsb. + * + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnUSBRegisterHub,(PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp)); + + /** + * Set up asynchronous handling of a suspend, reset or power off notification. + * + * This shall only be called when getting the notification. It must be called + * for each one. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pfnAsyncNotify The callback. + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnSetAsyncNotification, (PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify)); + + /** + * Notify EMT(0) that the driver has completed the asynchronous notification + * handling. + * + * This can be called at any time, spurious calls will simply be ignored. + * + * @param pDrvIns The driver instance. + * @thread Any + */ + DECLR3CALLBACKMEMBER(void, pfnAsyncNotificationCompleted, (PPDMDRVINS pDrvIns)); + + /** + * Creates a PDM thread. + * + * This differs from the RTThreadCreate() API in that PDM takes care of suspending, + * resuming, and destroying the thread as the VM state changes. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param ppThread Where to store the thread 'handle'. + * @param pvUser The user argument to the thread function. + * @param pfnThread The thread function. + * @param pfnWakeup The wakup callback. This is called on the EMT thread when + * a state change is pending. + * @param cbStack See RTThreadCreate. + * @param enmType See RTThreadCreate. + * @param pszName See RTThreadCreate. + */ + DECLR3CALLBACKMEMBER(int, pfnThreadCreate,(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread, + PFNPDMTHREADWAKEUPDRV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)); + + /** @name Exported PDM Thread Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnThreadDestroy,(PPDMTHREAD pThread, int *pRcThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmSuspending,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmRunning,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadSleep,(PPDMTHREAD pThread, RTMSINTERVAL cMillies)); + DECLR3CALLBACKMEMBER(int, pfnThreadSuspend,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadResume,(PPDMTHREAD pThread)); + /** @} */ + + /** + * Creates an async completion template for a driver instance. + * + * The template is used when creating new completion tasks. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param ppTemplate Where to store the template pointer on success. + * @param pfnCompleted The completion callback routine. + * @param pvTemplateUser Template user argument. + * @param pszDesc Description. + */ + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionTemplateCreate,(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, + PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser, + const char *pszDesc)); + + /** @name Exported PDM Async Completion Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionTemplateDestroy,(PPDMASYNCCOMPLETIONTEMPLATE pTemplate)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpCreateForFile,(PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint, + const char *pszFilename, uint32_t fFlags, + PPDMASYNCCOMPLETIONTEMPLATE pTemplate)); + DECLR3CALLBACKMEMBER(void, pfnAsyncCompletionEpClose,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpGetSize,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t *pcbSize)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpSetSize,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpSetBwMgr,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpFlush,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser, PPPDMASYNCCOMPLETIONTASK ppTask)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpRead,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbRead, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask)); + DECLR3CALLBACKMEMBER(int, pfnAsyncCompletionEpWrite,(PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbWrite, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask)); + /** @} */ + + + /** + * Attaches a network filter driver to a named bandwidth group. + * + * @returns VBox status code. + * @retval VERR_ALREADY_INITIALIZED if already attached to a group. + * @param pDrvIns The driver instance. + * @param pszBwGroup Name of the bandwidth group to attach to. + * @param pFilter Pointer to the filter we attach. + */ + DECLR3CALLBACKMEMBER(int, pfnNetShaperAttach,(PPDMDRVINS pDrvIns, const char *pszBwGroup, PPDMNSFILTER pFilter)); + + /** + * Detaches a network filter driver from its current bandwidth group (if any). + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter we attach. + */ + DECLR3CALLBACKMEMBER(int, pfnNetShaperDetach,(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter)); + + /** + * Obtains bandwidth in a bandwidth group. + * + * @returns True if bandwidth was allocated, false if not. + * @param pDrvIns The driver instance. + * @param pFilter Pointer to the filter that allocates bandwidth. + * @param cbTransfer Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(bool, pfnNetShaperAllocateBandwidth,(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer)); + + /** + * Resolves the symbol for a raw-mode context interface. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pvInterface The interface structure. + * @param cbInterface The size of the interface structure. + * @param pszSymPrefix What to prefix the symbols in the list with before + * resolving them. This must start with 'drv' and + * contain the driver name. + * @param pszSymList List of symbols corresponding to the interface. + * There is generally a there is generally a define + * holding this list associated with the interface + * definition (INTERFACE_SYM_LIST). For more details + * see PDMR3LdrGetInterfaceSymbols. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnLdrGetRCInterfaceSymbols,(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface, + const char *pszSymPrefix, const char *pszSymList)); + + /** + * Resolves the symbol for a ring-0 context interface. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pvInterface The interface structure. + * @param cbInterface The size of the interface structure. + * @param pszSymPrefix What to prefix the symbols in the list with before + * resolving them. This must start with 'drv' and + * contain the driver name. + * @param pszSymList List of symbols corresponding to the interface. + * There is generally a there is generally a define + * holding this list associated with the interface + * definition (INTERFACE_SYM_LIST). For more details + * see PDMR3LdrGetInterfaceSymbols. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnLdrGetR0InterfaceSymbols,(PPDMDRVINS pDrvIns, void *pvInterface, size_t cbInterface, + const char *pszSymPrefix, const char *pszSymList)); + /** + * Initializes a PDM critical section. + * + * The PDM critical sections are derived from the IPRT critical sections, but + * works in both RC and R0 as well as R3. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pCritSect Pointer to the critical section. + * @param SRC_POS Use RT_SRC_POS. + * @param pszName The base name of the critical section. Will be + * mangeled with the instance number. For + * statistics and lock validation. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnCritSectInit,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, const char *pszName)); + + /** @name Exported PDM Critical Section Functions + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCritSectYield,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy)); + DECLR3CALLBACKMEMBER(int, pfnCritSectEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectTryEnter,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectTryEnterDebug,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL)); + DECLR3CALLBACKMEMBER(int, pfnCritSectLeave,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectIsOwner,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectIsInitialized,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(bool, pfnCritSectHasWaiters,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(uint32_t, pfnCritSectGetRecursion,(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnCritSectScheduleExitEvent,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal)); + DECLR3CALLBACKMEMBER(int, pfnCritSectDelete,(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect)); + /** @} */ + + /** + * Call the ring-0 request handler routine of the driver. + * + * For this to work, the driver must be ring-0 enabled and export a request + * handler function. The name of the function must be the driver name in the + * PDMDRVREG struct prefixed with 'drvR0' and suffixed with 'ReqHandler'. + * The driver name will be capitalized. It shall take the exact same + * arguments as this function and be declared using PDMBOTHCBDECL. See + * FNPDMDRVREQHANDLERR0. + * + * @returns VBox status code. + * @retval VERR_SYMBOL_NOT_FOUND if the driver doesn't export the required + * handler function. + * @retval VERR_ACCESS_DENIED if the driver isn't ring-0 capable. + * + * @param pDrvIns The driver instance. + * @param uOperation The operation to perform. + * @param u64Arg 64-bit integer argument. + * @thread Any + */ + DECLR3CALLBACKMEMBER(int, pfnCallR0,(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg)); + + /** + * Creates a block cache for a driver driver instance. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param ppBlkCache Where to store the handle to the block cache. + * @param pfnXferComplete The I/O transfer complete callback. + * @param pfnXferEnqueue The I/O request enqueue callback. + * @param pfnXferEnqueueDiscard The discard request enqueue callback. + * @param pcszId Unique ID used to identify the user. + */ + DECLR3CALLBACKMEMBER(int, pfnBlkCacheRetain, (PPDMDRVINS pDrvIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard, + const char *pcszId)); + + /** @name Exported PDM Block Cache Functions + * @{ */ + DECLR3CALLBACKMEMBER(void, pfnBlkCacheRelease,(PPDMBLKCACHE pBlkCache)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheClear,(PPDMBLKCACHE pBlkCache)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheSuspend,(PPDMBLKCACHE pBlkCache)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheResume,(PPDMBLKCACHE pBlkCache)); + DECLR3CALLBACKMEMBER(void, pfnBlkCacheIoXferComplete,(PPDMBLKCACHE pBlkCache, PPDMBLKCACHEIOXFER hIoXfer, int rcIoXfer)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheRead,(PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheWrite,(PPDMBLKCACHE pBlkCache, uint64_t off, PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheFlush,(PPDMBLKCACHE pBlkCache, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnBlkCacheDiscard,(PPDMBLKCACHE pBlkCache, PCRTRANGE paRanges, unsigned cRanges, void *pvUser)); + /** @} */ + + /** + * Gets the reason for the most recent VM suspend. + * + * @returns The suspend reason. VMSUSPENDREASON_INVALID is returned if no + * suspend has been made or if the pDrvIns is invalid. + * @param pDrvIns The driver instance. + */ + DECLR3CALLBACKMEMBER(VMSUSPENDREASON, pfnVMGetSuspendReason,(PPDMDRVINS pDrvIns)); + + /** + * Gets the reason for the most recent VM resume. + * + * @returns The resume reason. VMRESUMEREASON_INVALID is returned if no + * resume has been made or if the pDrvIns is invalid. + * @param pDrvIns The driver instance. + */ + DECLR3CALLBACKMEMBER(VMRESUMEREASON, pfnVMGetResumeReason,(PPDMDRVINS pDrvIns)); + + /** @name Space reserved for minor interface changes. + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnTimerSetMillies,(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)); + + /** + * Deregister zero or more samples given their name prefix. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pszPrefix The name prefix of the samples to remove. If this does + * not start with a '/', the default prefix will be + * prepended, otherwise it will be used as-is. + */ + DECLR3CALLBACKMEMBER(int, pfnSTAMDeregisterByPrefix,(PPDMDRVINS pDrvIns, const char *pszPrefix)); + + /** + * Queries a generic object from the VMM user. + * + * @returns Pointer to the object if found, NULL if not. + * @param pDrvIns The driver instance. + * @param pUuid The UUID of what's being queried. The UUIDs and + * the usage conventions are defined by the user. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryGenericUserObject,(PPDMDRVINS pDrvIns, PCRTUUID pUuid)); + + DECLR3CALLBACKMEMBER(void, pfnReserved0,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved1,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved2,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved3,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved4,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved5,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved6,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved7,(PPDMDRVINS pDrvIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved8,(PPDMDRVINS pDrvIns)); + /** @} */ + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMDRVHLPR3; +/** Current DRVHLP version number. */ +#define PDM_DRVHLPR3_VERSION PDM_VERSION_MAKE(0xf0fb, 16, 0) + + +/** + * Set the VM error message + * + * @returns rc. + * @param pDrvIns Driver instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + * @sa PDMDRV_SET_ERROR, PDMDrvHlpVMSetErrorV, VMSetError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) PDMDrvHlpVMSetError(PPDMDRVINS pDrvIns, const int rc, RT_SRC_POS_DECL, + const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + pDrvIns->CTX_SUFF(pHlp)->pfnVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + return rc; +} + +/** @def PDMDRV_SET_ERROR + * Set the VM error. See PDMDrvHlpVMSetError() for printf like message formatting. + */ +#define PDMDRV_SET_ERROR(pDrvIns, rc, pszError) \ + PDMDrvHlpVMSetError(pDrvIns, rc, RT_SRC_POS, "%s", pszError) + +/** + * @copydoc PDMDRVHLPR3::pfnVMSetErrorV + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 0) PDMDrvHlpVMSetErrorV(PPDMDRVINS pDrvIns, const int rc, RT_SRC_POS_DECL, + const char *pszFormat, va_list va) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnVMSetErrorV(pDrvIns, rc, RT_SRC_POS_ARGS, pszFormat, va); +} + + +/** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pDrvIns Driver instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + * @sa PDMDRV_SET_RUNTIME_ERROR, PDMDrvHlpVMSetRuntimeErrorV, + * VMSetRuntimeError + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 5) PDMDrvHlpVMSetRuntimeError(PPDMDRVINS pDrvIns, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, ...) +{ + va_list va; + int rc; + va_start(va, pszFormat); + rc = pDrvIns->CTX_SUFF(pHlp)->pfnVMSetRuntimeErrorV(pDrvIns, fFlags, pszErrorId, pszFormat, va); + va_end(va); + return rc; +} + +/** @def PDMDRV_SET_RUNTIME_ERROR + * Set the VM runtime error. See PDMDrvHlpVMSetRuntimeError() for printf like message formatting. + */ +#define PDMDRV_SET_RUNTIME_ERROR(pDrvIns, fFlags, pszErrorId, pszError) \ + PDMDrvHlpVMSetRuntimeError(pDrvIns, fFlags, pszErrorId, "%s", pszError) + +/** + * @copydoc PDMDRVHLPR3::pfnVMSetRuntimeErrorV + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(4, 0) PDMDrvHlpVMSetRuntimeErrorV(PPDMDRVINS pDrvIns, uint32_t fFlags, + const char *pszErrorId, const char *pszFormat, va_list va) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnVMSetRuntimeErrorV(pDrvIns, fFlags, pszErrorId, pszFormat, va); +} + +#endif /* IN_RING3 */ + +/** @def PDMDRV_ASSERT_EMT + * Assert that the current thread is the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMDRV_ASSERT_EMT(pDrvIns) pDrvIns->CTX_SUFF(pHlp)->pfnAssertEMT(pDrvIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDRV_ASSERT_EMT(pDrvIns) do { } while (0) +#endif + +/** @def PDMDRV_ASSERT_OTHER + * Assert that the current thread is NOT the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMDRV_ASSERT_OTHER(pDrvIns) pDrvIns->CTX_SUFF(pHlp)->pfnAssertOther(pDrvIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMDRV_ASSERT_OTHER(pDrvIns) do { } while (0) +#endif + + +#ifdef IN_RING3 + +/** + * @copydoc PDMDRVHLPR3::pfnAttach + */ +DECLINLINE(int) PDMDrvHlpAttach(PPDMDRVINS pDrvIns, uint32_t fFlags, PPDMIBASE *ppBaseInterface) +{ + return pDrvIns->pHlpR3->pfnAttach(pDrvIns, fFlags, ppBaseInterface); +} + +/** + * Check that there is no driver below the us that we should attach to. + * + * @returns VERR_PDM_NO_ATTACHED_DRIVER if there is no driver. + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpNoAttach(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnAttach(pDrvIns, 0, NULL); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDetach + */ +DECLINLINE(int) PDMDrvHlpDetach(PPDMDRVINS pDrvIns, uint32_t fFlags) +{ + return pDrvIns->pHlpR3->pfnDetach(pDrvIns, fFlags); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDetachSelf + */ +DECLINLINE(int) PDMDrvHlpDetachSelf(PPDMDRVINS pDrvIns, uint32_t fFlags) +{ + return pDrvIns->pHlpR3->pfnDetachSelf(pDrvIns, fFlags); +} + +/** + * @copydoc PDMDRVHLPR3::pfnMountPrepare + */ +DECLINLINE(int) PDMDrvHlpMountPrepare(PPDMDRVINS pDrvIns, const char *pszFilename, const char *pszCoreDriver) +{ + return pDrvIns->pHlpR3->pfnMountPrepare(pDrvIns, pszFilename, pszCoreDriver); +} + +/** + * @copydoc PDMDRVHLPR3::pfnVMState + */ +DECLINLINE(VMSTATE) PDMDrvHlpVMState(PPDMDRVINS pDrvIns) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnVMState(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnVMTeleportedAndNotFullyResumedYet + */ +DECLINLINE(bool) PDMDrvHlpVMTeleportedAndNotFullyResumedYet(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnVMTeleportedAndNotFullyResumedYet(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnGetSupDrvSession + */ +DECLINLINE(PSUPDRVSESSION) PDMDrvHlpGetSupDrvSession(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnGetSupDrvSession(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueueCreate + */ +DECLINLINE(int) PDMDrvHlpQueueCreate(PPDMDRVINS pDrvIns, uint32_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEDRV pfnCallback, const char *pszName, PDMQUEUEHANDLE *phQueue) +{ + return pDrvIns->pHlpR3->pfnQueueCreate(pDrvIns, cbItem, cItems, cMilliesInterval, pfnCallback, pszName, phQueue); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueueAlloc + */ +DECLINLINE(PPDMQUEUEITEMCORE) PDMDrvHlpQueueAlloc(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnQueueAlloc(pDrvIns, hQueue); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueueInsert + */ +DECLINLINE(int) PDMDrvHlpQueueInsert(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue, PPDMQUEUEITEMCORE pItem) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnQueueInsert(pDrvIns, hQueue, pItem); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueueFlushIfNecessary + */ +DECLINLINE(bool) PDMDrvHlpQueueFlushIfNecessary(PPDMDRVINS pDrvIns, PDMQUEUEHANDLE hQueue) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnQueueFlushIfNecessary(pDrvIns, hQueue); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTMGetVirtualFreq + */ +DECLINLINE(uint64_t) PDMDrvHlpTMGetVirtualFreq(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnTMGetVirtualFreq(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTMGetVirtualTime + */ +DECLINLINE(uint64_t) PDMDrvHlpTMGetVirtualTime(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnTMGetVirtualTime(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTimerCreate + */ +DECLINLINE(int) PDMDrvHlpTMTimerCreate(PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer) + +{ + return pDrvIns->pHlpR3->pfnTimerCreate(pDrvIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTimerDestroy + */ +DECLINLINE(int) PDMDrvHlpTimerDestroy(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer) + +{ + return pDrvIns->pHlpR3->pfnTimerDestroy(pDrvIns, hTimer); +} + +/** + * @copydoc PDMDRVHLPR3::pfnTimerSetMillies + */ +DECLINLINE(int) PDMDrvHlpTimerSetMillies(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext) + +{ + return pDrvIns->pHlpR3->pfnTimerSetMillies(pDrvIns, hTimer, cMilliesToNext); +} + +/** + * Register a save state data unit. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnLoadExec Execute load callback, optional. + */ +DECLINLINE(int) PDMDrvHlpSSMRegister(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVLOADEXEC pfnLoadExec) +{ + return pDrvIns->pHlpR3->pfnSSMRegister(pDrvIns, uVersion, cbGuess, + NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/, + NULL /*pfnSavePrep*/, pfnSaveExec, NULL /*pfnSaveDone*/, + NULL /*pfnLoadPrep*/, pfnLoadExec, NULL /*pfnLoadDone*/); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSSMRegister + */ +DECLINLINE(int) PDMDrvHlpSSMRegisterEx(PPDMDRVINS pDrvIns, uint32_t uVersion, size_t cbGuess, + PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote, + PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone, + PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone) +{ + return pDrvIns->pHlpR3->pfnSSMRegister(pDrvIns, uVersion, cbGuess, + pfnLivePrep, pfnLiveExec, pfnLiveVote, + pfnSavePrep, pfnSaveExec, pfnSaveDone, + pfnLoadPrep, pfnLoadExec, pfnLoadDone); +} + +/** + * Register a load done callback. + * + * @returns VBox status. + * @param pDrvIns Driver instance. + * @param pfnLoadDone Done load callback, optional. + */ +DECLINLINE(int) PDMDrvHlpSSMRegisterLoadDone(PPDMDRVINS pDrvIns, PFNSSMDRVLOADDONE pfnLoadDone) +{ + return pDrvIns->pHlpR3->pfnSSMRegister(pDrvIns, 0 /*uVersion*/, 0 /*cbGuess*/, + NULL /*pfnLivePrep*/, NULL /*pfnLiveExec*/, NULL /*pfnLiveVote*/, + NULL /*pfnSavePrep*/, NULL /*pfnSaveExec*/, NULL /*pfnSaveDone*/, + NULL /*pfnLoadPrep*/, NULL /*pfnLoadExec*/, pfnLoadDone); +} + +/** + * @copydoc PDMDRVHLPR3::pfnMMHeapFree + */ +DECLINLINE(void) PDMDrvHlpMMHeapFree(PPDMDRVINS pDrvIns, void *pv) +{ + pDrvIns->pHlpR3->pfnMMHeapFree(pDrvIns, pv); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDBGFInfoRegister + */ +DECLINLINE(int) PDMDrvHlpDBGFInfoRegister(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler) +{ + return pDrvIns->pHlpR3->pfnDBGFInfoRegister(pDrvIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDBGFInfoRegisterArgv + */ +DECLINLINE(int) PDMDrvHlpDBGFInfoRegisterArgv(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVDRV pfnHandler) +{ + return pDrvIns->pHlpR3->pfnDBGFInfoRegisterArgv(pDrvIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDRVHLPR3::pfnDBGFInfoRegister + */ +DECLINLINE(int) PDMDrvHlpDBGFInfoDeregister(PPDMDRVINS pDrvIns, const char *pszName, const char *pszDesc, PFNDBGFHANDLERDRV pfnHandler) +{ + return pDrvIns->pHlpR3->pfnDBGFInfoRegister(pDrvIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSTAMRegister + */ +DECLINLINE(void) PDMDrvHlpSTAMRegister(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDrvIns->pHlpR3->pfnSTAMRegister(pDrvIns, pvSample, enmType, pszName, enmUnit, pszDesc); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSTAMRegisterF + */ +DECLINLINE(void) RT_IPRT_FORMAT_ATTR(7, 8) PDMDrvHlpSTAMRegisterF(PPDMDRVINS pDrvIns, void *pvSample, STAMTYPE enmType, + STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, ...) +{ + va_list va; + va_start(va, pszName); + pDrvIns->pHlpR3->pfnSTAMRegisterV(pDrvIns, pvSample, enmType, enmVisibility, enmUnit, pszDesc, pszName, va); + va_end(va); +} + +/** + * Convenience wrapper that registers counter which is always visible. + * + * @param pDrvIns The driver instance. + * @param pCounter Pointer to the counter variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/-/". + * @param enmUnit The unit. + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegCounterEx(PPDMDRVINS pDrvIns, PSTAMCOUNTER pCounter, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDrvIns->pHlpR3->pfnSTAMRegisterF(pDrvIns, pCounter, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, enmUnit, pszDesc, + "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszName); +} + +/** + * Convenience wrapper that registers counter which is always visible and has + * the STAMUNIT_COUNT unit. + * + * @param pDrvIns The driver instance. + * @param pCounter Pointer to the counter variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/-/". + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegCounter(PPDMDRVINS pDrvIns, PSTAMCOUNTER pCounter, const char *pszName, const char *pszDesc) +{ + PDMDrvHlpSTAMRegCounterEx(pDrvIns, pCounter, pszName, STAMUNIT_COUNT, pszDesc); +} + +/** + * Convenience wrapper that registers profiling sample which is always visible. + * + * @param pDrvIns The driver instance. + * @param pProfile Pointer to the profiling variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/-/". + * @param enmUnit The unit. + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegProfileEx(PPDMDRVINS pDrvIns, PSTAMPROFILE pProfile, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDrvIns->pHlpR3->pfnSTAMRegisterF(pDrvIns, pProfile, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, enmUnit, pszDesc, + "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszName); +} + +/** + * Convenience wrapper that registers profiling sample which is always visible + * hand counts ticks per call (STAMUNIT_TICKS_PER_CALL). + * + * @param pDrvIns The driver instance. + * @param pProfile Pointer to the profiling variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/-/". + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegProfile(PPDMDRVINS pDrvIns, PSTAMPROFILE pProfile, const char *pszName, const char *pszDesc) +{ + PDMDrvHlpSTAMRegProfileEx(pDrvIns, pProfile, pszName, STAMUNIT_TICKS_PER_CALL, pszDesc); +} + +/** + * Convenience wrapper that registers an advanced profiling sample which is + * always visible. + * + * @param pDrvIns The driver instance. + * @param pProfile Pointer to the profiling variable. + * @param enmUnit The unit. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/-/". + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegProfileAdvEx(PPDMDRVINS pDrvIns, PSTAMPROFILEADV pProfile, const char *pszName, STAMUNIT enmUnit, const char *pszDesc) +{ + pDrvIns->pHlpR3->pfnSTAMRegisterF(pDrvIns, pProfile, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, enmUnit, pszDesc, + "/Drivers/%s-%u/%s", pDrvIns->pReg->szName, pDrvIns->iInstance, pszName); +} + +/** + * Convenience wrapper that registers an advanced profiling sample which is + * always visible. + * + * @param pDrvIns The driver instance. + * @param pProfile Pointer to the profiling variable. + * @param pszName The name of the sample. This is prefixed with + * "/Drivers/-/". + * @param pszDesc The description. + */ +DECLINLINE(void) PDMDrvHlpSTAMRegProfileAdv(PPDMDRVINS pDrvIns, PSTAMPROFILEADV pProfile, const char *pszName, const char *pszDesc) +{ + PDMDrvHlpSTAMRegProfileAdvEx(pDrvIns, pProfile, pszName, STAMUNIT_TICKS_PER_CALL, pszDesc); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSTAMDeregister + */ +DECLINLINE(int) PDMDrvHlpSTAMDeregister(PPDMDRVINS pDrvIns, void *pvSample) +{ + return pDrvIns->pHlpR3->pfnSTAMDeregister(pDrvIns, pvSample); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSTAMDeregisterByPrefix + */ +DECLINLINE(int) PDMDrvHlpSTAMDeregisterByPrefix(PPDMDRVINS pDrvIns, const char *pszPrefix) +{ + return pDrvIns->pHlpR3->pfnSTAMDeregisterByPrefix(pDrvIns, pszPrefix); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSUPCallVMMR0Ex + */ +DECLINLINE(int) PDMDrvHlpSUPCallVMMR0Ex(PPDMDRVINS pDrvIns, unsigned uOperation, void *pvArg, unsigned cbArg) +{ + return pDrvIns->pHlpR3->pfnSUPCallVMMR0Ex(pDrvIns, uOperation, pvArg, cbArg); +} + +/** + * @copydoc PDMDRVHLPR3::pfnUSBRegisterHub + */ +DECLINLINE(int) PDMDrvHlpUSBRegisterHub(PPDMDRVINS pDrvIns, uint32_t fVersions, uint32_t cPorts, PCPDMUSBHUBREG pUsbHubReg, PPCPDMUSBHUBHLP ppUsbHubHlp) +{ + return pDrvIns->pHlpR3->pfnUSBRegisterHub(pDrvIns, fVersions, cPorts, pUsbHubReg, ppUsbHubHlp); +} + +/** + * @copydoc PDMDRVHLPR3::pfnSetAsyncNotification + */ +DECLINLINE(int) PDMDrvHlpSetAsyncNotification(PPDMDRVINS pDrvIns, PFNPDMDRVASYNCNOTIFY pfnAsyncNotify) +{ + return pDrvIns->pHlpR3->pfnSetAsyncNotification(pDrvIns, pfnAsyncNotify); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncNotificationCompleted + */ +DECLINLINE(void) PDMDrvHlpAsyncNotificationCompleted(PPDMDRVINS pDrvIns) +{ + pDrvIns->pHlpR3->pfnAsyncNotificationCompleted(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnThreadCreate + */ +DECLINLINE(int) PDMDrvHlpThreadCreate(PPDMDRVINS pDrvIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADDRV pfnThread, + PFNPDMTHREADWAKEUPDRV pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName) +{ + return pDrvIns->pHlpR3->pfnThreadCreate(pDrvIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName); +} + +/** + * @copydoc PDMR3ThreadDestroy + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadDestroy(PPDMDRVINS pDrvIns, PPDMTHREAD pThread, int *pRcThread) +{ + return pDrvIns->pHlpR3->pfnThreadDestroy(pThread, pRcThread); +} + +/** + * @copydoc PDMR3ThreadIAmSuspending + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadIAmSuspending(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + return pDrvIns->pHlpR3->pfnThreadIAmSuspending(pThread); +} + +/** + * @copydoc PDMR3ThreadIAmRunning + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadIAmRunning(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + return pDrvIns->pHlpR3->pfnThreadIAmRunning(pThread); +} + +/** + * @copydoc PDMR3ThreadSleep + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadSleep(PPDMDRVINS pDrvIns, PPDMTHREAD pThread, RTMSINTERVAL cMillies) +{ + return pDrvIns->pHlpR3->pfnThreadSleep(pThread, cMillies); +} + +/** + * @copydoc PDMR3ThreadSuspend + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadSuspend(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + return pDrvIns->pHlpR3->pfnThreadSuspend(pThread); +} + +/** + * @copydoc PDMR3ThreadResume + * @param pDrvIns The driver instance. + */ +DECLINLINE(int) PDMDrvHlpThreadResume(PPDMDRVINS pDrvIns, PPDMTHREAD pThread) +{ + return pDrvIns->pHlpR3->pfnThreadResume(pThread); +} + +# ifdef VBOX_WITH_PDM_ASYNC_COMPLETION +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionTemplateCreate + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionTemplateCreate(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONTEMPLATE ppTemplate, + PFNPDMASYNCCOMPLETEDRV pfnCompleted, void *pvTemplateUser, const char *pszDesc) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionTemplateCreate(pDrvIns, ppTemplate, pfnCompleted, pvTemplateUser, pszDesc); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionTemplateDestroy + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionTemplateDestroy(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONTEMPLATE pTemplate) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionTemplateDestroy(pTemplate); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpCreateForFile + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpCreateForFile(PPDMDRVINS pDrvIns, PPPDMASYNCCOMPLETIONENDPOINT ppEndpoint, + const char *pszFilename, uint32_t fFlags, + PPDMASYNCCOMPLETIONTEMPLATE pTemplate) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpCreateForFile(ppEndpoint, pszFilename, fFlags, pTemplate); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpClose + */ +DECLINLINE(void) PDMDrvHlpAsyncCompletionEpClose(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint) +{ + pDrvIns->pHlpR3->pfnAsyncCompletionEpClose(pEndpoint); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpGetSize + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpGetSize(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t *pcbSize) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpGetSize(pEndpoint, pcbSize); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpSetSize + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpSetSize(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, uint64_t cbSize) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpSetSize(pEndpoint, cbSize); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpSetBwMgr + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpSetBwMgr(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, const char *pszBwMgr) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpSetBwMgr(pEndpoint, pszBwMgr); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpFlush + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpFlush(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpFlush(pEndpoint, pvUser, ppTask); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpRead + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpRead(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbRead, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpRead(pEndpoint, off, paSegments, cSegments, cbRead, pvUser, ppTask); +} + +/** + * @copydoc PDMDRVHLPR3::pfnAsyncCompletionEpWrite + */ +DECLINLINE(int) PDMDrvHlpAsyncCompletionEpWrite(PPDMDRVINS pDrvIns, PPDMASYNCCOMPLETIONENDPOINT pEndpoint, RTFOFF off, + PCRTSGSEG paSegments, unsigned cSegments, + size_t cbWrite, void *pvUser, + PPPDMASYNCCOMPLETIONTASK ppTask) +{ + return pDrvIns->pHlpR3->pfnAsyncCompletionEpWrite(pEndpoint, off, paSegments, cSegments, cbWrite, pvUser, ppTask); +} +# endif + +#endif /* IN_RING3 */ + +#ifdef VBOX_WITH_NETSHAPER +# ifdef IN_RING3 + +/** + * @copydoc PDMDRVHLPR3::pfnNetShaperAttach + */ +DECLINLINE(int) PDMDrvHlpNetShaperAttach(PPDMDRVINS pDrvIns, const char *pcszBwGroup, PPDMNSFILTER pFilter) +{ + return pDrvIns->pHlpR3->pfnNetShaperAttach(pDrvIns, pcszBwGroup, pFilter); +} + +/** + * @copydoc PDMDRVHLPR3::pfnNetShaperDetach + */ +DECLINLINE(int) PDMDrvHlpNetShaperDetach(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter) +{ + return pDrvIns->pHlpR3->pfnNetShaperDetach(pDrvIns, pFilter); +} + +# endif /* IN_RING3 */ + +/** + * @copydoc PDMDRVHLPR3::pfnNetShaperAllocateBandwidth + */ +DECLINLINE(bool) PDMDrvHlpNetShaperAllocateBandwidth(PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter, size_t cbTransfer) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnNetShaperAllocateBandwidth(pDrvIns, pFilter, cbTransfer); +} + +#endif /* VBOX_WITH_NETSHAPER*/ + +#ifdef IN_RING3 +/** + * @copydoc PDMDRVHLPR3::pfnCritSectInit + */ +DECLINLINE(int) PDMDrvHlpCritSectInit(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RT_SRC_POS_DECL, const char *pszName) +{ + return pDrvIns->pHlpR3->pfnCritSectInit(pDrvIns, pCritSect, RT_SRC_POS_ARGS, pszName); +} +#endif /* IN_RING3 */ + +/** + * @see PDMCritSectEnter + */ +DECLINLINE(int) PDMDrvHlpCritSectEnter(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectEnter(pDrvIns, pCritSect, rcBusy); +} + +/** + * @see PDMCritSectEnterDebug + */ +DECLINLINE(int) PDMDrvHlpCritSectEnterDebug(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, int rcBusy, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectEnterDebug(pDrvIns, pCritSect, rcBusy, uId, RT_SRC_POS_ARGS); +} + +/** + * @see PDMCritSectTryEnter + */ +DECLINLINE(int) PDMDrvHlpCritSectTryEnter(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectTryEnter(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectTryEnterDebug + */ +DECLINLINE(int) PDMDrvHlpCritSectTryEnterDebug(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, RTHCUINTPTR uId, RT_SRC_POS_DECL) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectTryEnterDebug(pDrvIns, pCritSect, uId, RT_SRC_POS_ARGS); +} + +/** + * @see PDMCritSectLeave + */ +DECLINLINE(int) PDMDrvHlpCritSectLeave(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectLeave(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectIsOwner + */ +DECLINLINE(bool) PDMDrvHlpCritSectIsOwner(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectIsOwner(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectIsInitialized + */ +DECLINLINE(bool) PDMDrvHlpCritSectIsInitialized(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectIsInitialized(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectHasWaiters + */ +DECLINLINE(bool) PDMDrvHlpCritSectHasWaiters(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectHasWaiters(pDrvIns, pCritSect); +} + +/** + * @see PDMCritSectGetRecursion + */ +DECLINLINE(uint32_t) PDMDrvHlpCritSectGetRecursion(PPDMDRVINS pDrvIns, PCPDMCRITSECT pCritSect) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectGetRecursion(pDrvIns, pCritSect); +} + +#if defined(IN_RING3) || defined(IN_RING0) +/** + * @see PDMHCCritSectScheduleExitEvent + */ +DECLINLINE(int) PDMDrvHlpCritSectScheduleExitEvent(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect, SUPSEMEVENT hEventToSignal) +{ + return pDrvIns->CTX_SUFF(pHlp)->pfnCritSectScheduleExitEvent(pDrvIns, pCritSect, hEventToSignal); +} +#endif + +/* Strict build: Remap the two enter calls to the debug versions. */ +#ifdef VBOX_STRICT +# ifdef IPRT_INCLUDED_asm_h +# define PDMDrvHlpCritSectEnter(pDrvIns, pCritSect, rcBusy) PDMDrvHlpCritSectEnterDebug((pDrvIns), (pCritSect), (rcBusy), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# define PDMDrvHlpCritSectTryEnter(pDrvIns, pCritSect) PDMDrvHlpCritSectTryEnterDebug((pDrvIns), (pCritSect), (uintptr_t)ASMReturnAddress(), RT_SRC_POS) +# else +# define PDMDrvHlpCritSectEnter(pDrvIns, pCritSect, rcBusy) PDMDrvHlpCritSectEnterDebug((pDrvIns), (pCritSect), (rcBusy), 0, RT_SRC_POS) +# define PDMDrvHlpCritSectTryEnter(pDrvIns, pCritSect) PDMDrvHlpCritSectTryEnterDebug((pDrvIns), (pCritSect), 0, RT_SRC_POS) +# endif +#endif + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) + +/** + * @see PDMR3CritSectDelete + */ +DECLINLINE(int) PDMDrvHlpCritSectDelete(PPDMDRVINS pDrvIns, PPDMCRITSECT pCritSect) +{ + return pDrvIns->pHlpR3->pfnCritSectDelete(pDrvIns, pCritSect); +} + +/** + * @copydoc PDMDRVHLPR3::pfnCallR0 + */ +DECLINLINE(int) PDMDrvHlpCallR0(PPDMDRVINS pDrvIns, uint32_t uOperation, uint64_t u64Arg) +{ + return pDrvIns->pHlpR3->pfnCallR0(pDrvIns, uOperation, u64Arg); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheRetain + */ +DECLINLINE(int) PDMDrvHlpBlkCacheRetain(PPDMDRVINS pDrvIns, PPPDMBLKCACHE ppBlkCache, + PFNPDMBLKCACHEXFERCOMPLETEDRV pfnXferComplete, + PFNPDMBLKCACHEXFERENQUEUEDRV pfnXferEnqueue, + PFNPDMBLKCACHEXFERENQUEUEDISCARDDRV pfnXferEnqueueDiscard, + const char *pcszId) +{ + return pDrvIns->pHlpR3->pfnBlkCacheRetain(pDrvIns, ppBlkCache, pfnXferComplete, pfnXferEnqueue, pfnXferEnqueueDiscard, pcszId); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheRelease + */ +DECLINLINE(void) PDMDrvHlpBlkCacheRelease(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache) +{ + pDrvIns->pHlpR3->pfnBlkCacheRelease(pBlkCache); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheClear + */ +DECLINLINE(int) PDMDrvHlpBlkCacheClear(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache) +{ + return pDrvIns->pHlpR3->pfnBlkCacheClear(pBlkCache); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheSuspend + */ +DECLINLINE(int) PDMDrvHlpBlkCacheSuspend(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache) +{ + return pDrvIns->pHlpR3->pfnBlkCacheSuspend(pBlkCache); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheResume + */ +DECLINLINE(int) PDMDrvHlpBlkCacheResume(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache) +{ + return pDrvIns->pHlpR3->pfnBlkCacheResume(pBlkCache); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheIoXferComplete + */ +DECLINLINE(void) PDMDrvHlpBlkCacheIoXferComplete(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, + PPDMBLKCACHEIOXFER hIoXfer, int rcIoXfer) +{ + pDrvIns->pHlpR3->pfnBlkCacheIoXferComplete(pBlkCache, hIoXfer, rcIoXfer); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheRead + */ +DECLINLINE(int) PDMDrvHlpBlkCacheRead(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, uint64_t off, + PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser) +{ + return pDrvIns->pHlpR3->pfnBlkCacheRead(pBlkCache, off, pSgBuf, cbRead, pvUser); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheWrite + */ +DECLINLINE(int) PDMDrvHlpBlkCacheWrite(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, uint64_t off, + PCRTSGBUF pSgBuf, size_t cbRead, void *pvUser) +{ + return pDrvIns->pHlpR3->pfnBlkCacheWrite(pBlkCache, off, pSgBuf, cbRead, pvUser); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheFlush + */ +DECLINLINE(int) PDMDrvHlpBlkCacheFlush(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, void *pvUser) +{ + return pDrvIns->pHlpR3->pfnBlkCacheFlush(pBlkCache, pvUser); +} + +/** + * @copydoc PDMDRVHLPR3::pfnBlkCacheDiscard + */ +DECLINLINE(int) PDMDrvHlpBlkCacheDiscard(PPDMDRVINS pDrvIns, PPDMBLKCACHE pBlkCache, PCRTRANGE paRanges, + unsigned cRanges, void *pvUser) +{ + return pDrvIns->pHlpR3->pfnBlkCacheDiscard(pBlkCache, paRanges, cRanges, pvUser); +} + +/** + * @copydoc PDMDRVHLPR3::pfnVMGetSuspendReason + */ +DECLINLINE(VMSUSPENDREASON) PDMDrvHlpVMGetSuspendReason(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnVMGetSuspendReason(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnVMGetResumeReason + */ +DECLINLINE(VMRESUMEREASON) PDMDrvHlpVMGetResumeReason(PPDMDRVINS pDrvIns) +{ + return pDrvIns->pHlpR3->pfnVMGetResumeReason(pDrvIns); +} + +/** + * @copydoc PDMDRVHLPR3::pfnQueryGenericUserObject + */ +DECLINLINE(void *) PDMDrvHlpQueryGenericUserObject(PPDMDRVINS pDrvIns, PCRTUUID pUuid) +{ + return pDrvIns->pHlpR3->pfnQueryGenericUserObject(pDrvIns, pUuid); +} + + +/** Pointer to callbacks provided to the VBoxDriverRegister() call. */ +typedef struct PDMDRVREGCB *PPDMDRVREGCB; +/** Pointer to const callbacks provided to the VBoxDriverRegister() call. */ +typedef const struct PDMDRVREGCB *PCPDMDRVREGCB; + +/** + * Callbacks for VBoxDriverRegister(). + */ +typedef struct PDMDRVREGCB +{ + /** Interface version. + * This is set to PDM_DRVREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a driver with the current VM instance. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param pReg Pointer to the driver registration record. + * This data must be permanent and readonly. + */ + DECLR3CALLBACKMEMBER(int, pfnRegister,(PCPDMDRVREGCB pCallbacks, PCPDMDRVREG pReg)); +} PDMDRVREGCB; + +/** Current version of the PDMDRVREGCB structure. */ +#define PDM_DRVREG_CB_VERSION PDM_VERSION_MAKE(0xf0fa, 1, 0) + + +/** + * The VBoxDriverRegister callback function. + * + * PDM will invoke this function after loading a driver module and letting + * the module decide which drivers to register and how to handle conflicts. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param u32Version VBox version number. + */ +typedef DECLCALLBACKTYPE(int, FNPDMVBOXDRIVERSREGISTER,(PCPDMDRVREGCB pCallbacks, uint32_t u32Version)); + +VMMR3DECL(int) PDMR3DrvStaticRegistration(PVM pVM, FNPDMVBOXDRIVERSREGISTER pfnCallback); + +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmdrv_h */ diff --git a/include/VBox/vmm/pdmifs.h b/include/VBox/vmm/pdmifs.h new file mode 100644 index 00000000..57ad02f2 --- /dev/null +++ b/include/VBox/vmm/pdmifs.h @@ -0,0 +1,2366 @@ +/** @file + * PDM - Pluggable Device Manager, Interfaces. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmifs_h +#define VBOX_INCLUDED_vmm_pdmifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_interfaces The PDM Interface Definitions + * @ingroup grp_pdm + * + * For historical reasons (the PDMINTERFACE enum) a lot of interface was stuffed + * together in this group instead, dragging stuff into global space that didn't + * need to be there and making this file huge (>2500 lines). Since we're using + * UUIDs as interface identifiers (IIDs) now, no only generic PDM interface will + * be added to this file. Component specific interface should be defined in the + * header file of that component. + * + * Interfaces consists of a method table (typedef'ed struct) and an interface + * ID. The typename of the method table should have an 'I' in it, be all + * capitals and according to the rules, no underscores. The interface ID is a + * \#define constructed by appending '_IID' to the typename. The IID value is a + * UUID string on the form "a2299c0d-b709-4551-aa5a-73f59ffbed74". If you stick + * to these rules, you can make use of the PDMIBASE_QUERY_INTERFACE and + * PDMIBASE_RETURN_INTERFACE when querying interface and implementing + * PDMIBASE::pfnQueryInterface respectively. + * + * In most interface descriptions the orientation of the interface is given as + * 'down' or 'up'. This refers to a model with the device on the top and the + * drivers stacked below it. Sometimes there is mention of 'main' or 'external' + * which normally means the same, i.e. the Main or VBoxBFE API. Picture the + * orientation of 'main' as horizontal. + * + * @{ + */ + + +/** @name PDMIBASE + * @{ + */ + +/** + * PDM Base Interface. + * + * Everyone implements this. + */ +typedef struct PDMIBASE +{ + /** + * Queries an interface to the driver. + * + * @returns Pointer to interface. + * @returns NULL if the interface was not supported by the driver. + * @param pInterface Pointer to this interface structure. + * @param pszIID The interface ID, a UUID string. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryInterface,(struct PDMIBASE *pInterface, const char *pszIID)); +} PDMIBASE; +/** PDMIBASE interface ID. */ +#define PDMIBASE_IID "a2299c0d-b709-4551-aa5a-73f59ffbed74" + +/** + * Helper macro for querying an interface from PDMIBASE. + * + * @returns Correctly typed PDMIBASE::pfnQueryInterface return value. + * + * @param pIBase Pointer to the base interface. + * @param InterfaceType The interface type name. The interface ID is + * derived from this by appending _IID. + */ +#define PDMIBASE_QUERY_INTERFACE(pIBase, InterfaceType) \ + ( (InterfaceType *)(pIBase)->pfnQueryInterface(pIBase, InterfaceType##_IID ) ) + +/** + * Helper macro for implementing PDMIBASE::pfnQueryInterface. + * + * Return @a pInterface if @a pszIID matches the @a InterfaceType. This will + * perform basic type checking. + * + * @param pszIID The ID of the interface that is being queried. + * @param InterfaceType The interface type name. The interface ID is + * derived from this by appending _IID. + * @param pInterface The interface address expression. + */ +#define PDMIBASE_RETURN_INTERFACE(pszIID, InterfaceType, pInterface) \ + do { \ + if (RTUuidCompare2Strs((pszIID), InterfaceType##_IID) == 0) \ + { \ + P##InterfaceType pReturnInterfaceTypeCheck = (pInterface); \ + return pReturnInterfaceTypeCheck; \ + } \ + } while (0) + +/** @} */ + + +/** @name PDMIBASERC + * @{ + */ + +/** + * PDM Base Interface for querying ring-mode context interfaces in + * ring-3. + * + * This is mandatory for drivers present in raw-mode context. + */ +typedef struct PDMIBASERC +{ + /** + * Queries an ring-mode context interface to the driver. + * + * @returns Pointer to interface. + * @returns NULL if the interface was not supported by the driver. + * @param pInterface Pointer to this interface structure. + * @param pszIID The interface ID, a UUID string. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(RTRCPTR, pfnQueryInterface,(struct PDMIBASERC *pInterface, const char *pszIID)); +} PDMIBASERC; +/** Pointer to a PDM Base Interface for query ring-mode context interfaces. */ +typedef PDMIBASERC *PPDMIBASERC; +/** PDMIBASERC interface ID. */ +#define PDMIBASERC_IID "f6a6c649-6cb3-493f-9737-4653f221aeca" + +/** + * Helper macro for querying an interface from PDMIBASERC. + * + * @returns PDMIBASERC::pfnQueryInterface return value. + * + * @param pIBaseRC Pointer to the base raw-mode context interface. Can + * be NULL. + * @param InterfaceType The interface type base name, no trailing RC. The + * interface ID is derived from this by appending _IID. + * + * @remarks Unlike PDMIBASE_QUERY_INTERFACE, this macro is not able to do any + * implicit type checking for you. + */ +#define PDMIBASERC_QUERY_INTERFACE(pIBaseRC, InterfaceType) \ + ( (P##InterfaceType##RC)((pIBaseRC) ? (pIBaseRC)->pfnQueryInterface(pIBaseRC, InterfaceType##_IID) : NIL_RTRCPTR) ) + +/** + * Helper macro for implementing PDMIBASERC::pfnQueryInterface. + * + * Return @a pInterface if @a pszIID matches the @a InterfaceType. This will + * perform basic type checking. + * + * @param pIns Pointer to the instance data. + * @param pszIID The ID of the interface that is being queried. + * @param InterfaceType The interface type base name, no trailing RC. The + * interface ID is derived from this by appending _IID. + * @param pInterface The interface address expression. This must resolve + * to some address within the instance data. + * @remarks Don't use with PDMIBASE. + */ +#define PDMIBASERC_RETURN_INTERFACE(pIns, pszIID, InterfaceType, pInterface) \ + do { \ + Assert((uintptr_t)pInterface - PDMINS_2_DATA(pIns, uintptr_t) < _4M); \ + if (RTUuidCompare2Strs((pszIID), InterfaceType##_IID) == 0) \ + { \ + InterfaceType##RC *pReturnInterfaceTypeCheck = (pInterface); \ + return (uintptr_t)pReturnInterfaceTypeCheck \ + - PDMINS_2_DATA(pIns, uintptr_t) \ + + PDMINS_2_DATA_RCPTR(pIns); \ + } \ + } while (0) + +/** @} */ + + +/** @name PDMIBASER0 + * @{ + */ + +/** + * PDM Base Interface for querying ring-0 interfaces in ring-3. + * + * This is mandatory for drivers present in ring-0 context. + */ +typedef struct PDMIBASER0 +{ + /** + * Queries an ring-0 interface to the driver. + * + * @returns Pointer to interface. + * @returns NULL if the interface was not supported by the driver. + * @param pInterface Pointer to this interface structure. + * @param pszIID The interface ID, a UUID string. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(RTR0PTR, pfnQueryInterface,(struct PDMIBASER0 *pInterface, const char *pszIID)); +} PDMIBASER0; +/** Pointer to a PDM Base Interface for query ring-0 context interfaces. */ +typedef PDMIBASER0 *PPDMIBASER0; +/** PDMIBASER0 interface ID. */ +#define PDMIBASER0_IID "9c9b99b8-7f53-4f59-a3c2-5bc9659c7944" + +/** + * Helper macro for querying an interface from PDMIBASER0. + * + * @returns PDMIBASER0::pfnQueryInterface return value. + * + * @param pIBaseR0 Pointer to the base ring-0 interface. Can be NULL. + * @param InterfaceType The interface type base name, no trailing R0. The + * interface ID is derived from this by appending _IID. + * + * @remarks Unlike PDMIBASE_QUERY_INTERFACE, this macro is not able to do any + * implicit type checking for you. + */ +#define PDMIBASER0_QUERY_INTERFACE(pIBaseR0, InterfaceType) \ + ( (P##InterfaceType##R0)((pIBaseR0) ? (pIBaseR0)->pfnQueryInterface(pIBaseR0, InterfaceType##_IID) : NIL_RTR0PTR) ) + +/** + * Helper macro for implementing PDMIBASER0::pfnQueryInterface. + * + * Return @a pInterface if @a pszIID matches the @a InterfaceType. This will + * perform basic type checking. + * + * @param pIns Pointer to the instance data. + * @param pszIID The ID of the interface that is being queried. + * @param InterfaceType The interface type base name, no trailing R0. The + * interface ID is derived from this by appending _IID. + * @param pInterface The interface address expression. This must resolve + * to some address within the instance data. + * @remarks Don't use with PDMIBASE. + */ +#define PDMIBASER0_RETURN_INTERFACE(pIns, pszIID, InterfaceType, pInterface) \ + do { \ + Assert((uintptr_t)pInterface - PDMINS_2_DATA(pIns, uintptr_t) < _4M); \ + if (RTUuidCompare2Strs((pszIID), InterfaceType##_IID) == 0) \ + { \ + InterfaceType##R0 *pReturnInterfaceTypeCheck = (pInterface); \ + return (uintptr_t)pReturnInterfaceTypeCheck \ + - PDMINS_2_DATA(pIns, uintptr_t) \ + + PDMINS_2_DATA_R0PTR(pIns); \ + } \ + } while (0) + +/** @} */ + + +/** + * Dummy interface. + * + * This is used to typedef other dummy interfaces. The purpose of a dummy + * interface is to validate the logical function of a driver/device and + * full a natural interface pair. + */ +typedef struct PDMIDUMMY +{ + RTHCPTR pvDummy; +} PDMIDUMMY; + + +/** Pointer to a mouse port interface. */ +typedef struct PDMIMOUSEPORT *PPDMIMOUSEPORT; +/** + * Mouse port interface (down). + * Pair with PDMIMOUSECONNECTOR. + */ +typedef struct PDMIMOUSEPORT +{ + /** + * Puts a mouse event. + * + * This is called by the source of mouse events. The event will be passed up + * until the topmost driver, which then calls the registered event handler. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param dx The X delta. + * @param dy The Y delta. + * @param dz The Z delta. + * @param dw The W (horizontal scroll button) delta. + * @param fButtons The button states, see the PDMIMOUSEPORT_BUTTON_* \#defines. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEvent,(PPDMIMOUSEPORT pInterface, + int32_t dx, int32_t dy, int32_t dz, + int32_t dw, uint32_t fButtons)); + /** + * Puts an absolute mouse event. + * + * This is called by the source of mouse events. The event will be passed up + * until the topmost driver, which then calls the registered event handler. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param x The X value, in the range 0 to 0xffff. + * @param y The Y value, in the range 0 to 0xffff. + * @param dz The Z delta. + * @param dw The W (horizontal scroll button) delta. + * @param fButtons The button states, see the PDMIMOUSEPORT_BUTTON_* \#defines. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEventAbs,(PPDMIMOUSEPORT pInterface, + uint32_t x, uint32_t y, + int32_t dz, int32_t dw, + uint32_t fButtons)); + /** + * Puts a multi-touch absolute (touchscreen) event. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param cContacts How many touch contacts in this event. + * @param pau64Contacts Pointer to array of packed contact information. + * Each 64bit element contains: + * Bits 0..15: X coordinate in pixels (signed). + * Bits 16..31: Y coordinate in pixels (signed). + * Bits 32..39: contact identifier. + * Bit 40: "in contact" flag, which indicates that + * there is a contact with the touch surface. + * Bit 41: "in range" flag, the contact is close enough + * to the touch surface. + * All other bits are reserved for future use and must be set to 0. + * @param u32ScanTime Timestamp of this event in milliseconds. Only relative + * time between event is important. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEventTouchScreen,(PPDMIMOUSEPORT pInterface, + uint8_t cContacts, + const uint64_t *pau64Contacts, + uint32_t u32ScanTime)); + + /** + * Puts a multi-touch relative (touchpad) event. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param cContacts How many touch contacts in this event. + * @param pau64Contacts Pointer to array of packed contact information. + * Each 64bit element contains: + * Bits 0..15: Normalized X coordinate (range: 0 - 0xffff). + * Bits 16..31: Normalized Y coordinate (range: 0 - 0xffff). + * Bits 32..39: contact identifier. + * Bit 40: "in contact" flag, which indicates that + * there is a contact with the touch surface. + * All other bits are reserved for future use and must be set to 0. + * @param u32ScanTime Timestamp of this event in milliseconds. Only relative + * time between event is important. + */ + + DECLR3CALLBACKMEMBER(int, pfnPutEventTouchPad,(PPDMIMOUSEPORT pInterface, + uint8_t cContacts, + const uint64_t *pau64Contacts, + uint32_t u32ScanTime)); +} PDMIMOUSEPORT; +/** PDMIMOUSEPORT interface ID. */ +#define PDMIMOUSEPORT_IID "d2bb54b7-d877-441b-9d25-d2d3329465c2" + +/** Mouse button defines for PDMIMOUSEPORT::pfnPutEvent. + * @{ */ +#define PDMIMOUSEPORT_BUTTON_LEFT RT_BIT(0) +#define PDMIMOUSEPORT_BUTTON_RIGHT RT_BIT(1) +#define PDMIMOUSEPORT_BUTTON_MIDDLE RT_BIT(2) +#define PDMIMOUSEPORT_BUTTON_X1 RT_BIT(3) +#define PDMIMOUSEPORT_BUTTON_X2 RT_BIT(4) +/** @} */ + + +/** Pointer to a mouse connector interface. */ +typedef struct PDMIMOUSECONNECTOR *PPDMIMOUSECONNECTOR; +/** + * Mouse connector interface (up). + * Pair with PDMIMOUSEPORT. + */ +typedef struct PDMIMOUSECONNECTOR +{ + /** + * Notifies the the downstream driver of changes to the reporting modes + * supported by the driver + * + * @param pInterface Pointer to this interface structure. + * @param fRelative Whether relative mode is currently supported. + * @param fAbsolute Whether absolute mode is currently supported. + * @param fMTAbsolute Whether absolute multi-touch mode is currently supported. + * @param fMTRelative Whether relative multi-touch mode is currently supported. + */ + DECLR3CALLBACKMEMBER(void, pfnReportModes,(PPDMIMOUSECONNECTOR pInterface, bool fRelative, bool fAbsolute, bool fMTAbsolute, bool fMTRelative)); + + /** + * Flushes the mouse queue if it contains pending events. + * + * @param pInterface Pointer to this interface structure. + */ + DECLR3CALLBACKMEMBER(void, pfnFlushQueue,(PPDMIMOUSECONNECTOR pInterface)); + +} PDMIMOUSECONNECTOR; +/** PDMIMOUSECONNECTOR interface ID. */ +#define PDMIMOUSECONNECTOR_IID "ce64d7bd-fa8f-41d1-a6fb-d102a2d6bffe" + + +/** Flags for PDMIKEYBOARDPORT::pfnPutEventHid. + * @{ */ +#define PDMIKBDPORT_KEY_UP RT_BIT(31) /** Key release event if set. */ +#define PDMIKBDPORT_RELEASE_KEYS RT_BIT(30) /** Force all keys to be released. */ +/** @} */ + +/** USB HID usage pages understood by PDMIKEYBOARDPORT::pfnPutEventHid. + * @{ */ +#define USB_HID_DC_PAGE 1 /** USB HID Generic Desktop Control Usage Page. */ +#define USB_HID_KB_PAGE 7 /** USB HID Keyboard Usage Page. */ +#define USB_HID_CC_PAGE 12 /** USB HID Consumer Control Usage Page. */ +/** @} */ + + +/** Pointer to a keyboard port interface. */ +typedef struct PDMIKEYBOARDPORT *PPDMIKEYBOARDPORT; +/** + * Keyboard port interface (down). + * Pair with PDMIKEYBOARDCONNECTOR. + */ +typedef struct PDMIKEYBOARDPORT +{ + /** + * Puts a scan code based keyboard event. + * + * This is called by the source of keyboard events. The event will be passed up + * until the topmost driver, which then calls the registered event handler. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param u8ScanCode The scan code to queue. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEventScan,(PPDMIKEYBOARDPORT pInterface, uint8_t u8KeyCode)); + + /** + * Puts a USB HID usage ID based keyboard event. + * + * This is called by the source of keyboard events. The event will be passed up + * until the topmost driver, which then calls the registered event handler. + * + * @returns VBox status code. Return VERR_TRY_AGAIN if you cannot process the + * event now and want it to be repeated at a later point. + * + * @param pInterface Pointer to this interface structure. + * @param idUsage The HID usage code event to queue. + */ + DECLR3CALLBACKMEMBER(int, pfnPutEventHid,(PPDMIKEYBOARDPORT pInterface, uint32_t idUsage)); + + /** + * Forcibly releases any pressed keys. + * + * This is called by the source of keyboard events in situations when a full + * release of all currently pressed keys must be forced, e.g. when activating + * a different keyboard, or when key-up events may have been lost. + * + * @returns VBox status code. + * + * @param pInterface Pointer to this interface structure. + */ + DECLR3CALLBACKMEMBER(int, pfnReleaseKeys,(PPDMIKEYBOARDPORT pInterface)); +} PDMIKEYBOARDPORT; +/** PDMIKEYBOARDPORT interface ID. */ +#define PDMIKEYBOARDPORT_IID "2a0844f0-410b-40ab-a6ed-6575f3aa3e29" + + +/** + * Keyboard LEDs. + */ +typedef enum PDMKEYBLEDS +{ + /** No leds. */ + PDMKEYBLEDS_NONE = 0x0000, + /** Num Lock */ + PDMKEYBLEDS_NUMLOCK = 0x0001, + /** Caps Lock */ + PDMKEYBLEDS_CAPSLOCK = 0x0002, + /** Scroll Lock */ + PDMKEYBLEDS_SCROLLLOCK = 0x0004 +} PDMKEYBLEDS; + +/** Pointer to keyboard connector interface. */ +typedef struct PDMIKEYBOARDCONNECTOR *PPDMIKEYBOARDCONNECTOR; +/** + * Keyboard connector interface (up). + * Pair with PDMIKEYBOARDPORT + */ +typedef struct PDMIKEYBOARDCONNECTOR +{ + /** + * Notifies the the downstream driver about an LED change initiated by the guest. + * + * @param pInterface Pointer to this interface structure. + * @param enmLeds The new led mask. + */ + DECLR3CALLBACKMEMBER(void, pfnLedStatusChange,(PPDMIKEYBOARDCONNECTOR pInterface, PDMKEYBLEDS enmLeds)); + + /** + * Notifies the the downstream driver of changes in driver state. + * + * @param pInterface Pointer to this interface structure. + * @param fActive Whether interface wishes to get "focus". + */ + DECLR3CALLBACKMEMBER(void, pfnSetActive,(PPDMIKEYBOARDCONNECTOR pInterface, bool fActive)); + + /** + * Flushes the keyboard queue if it contains pending events. + * + * @param pInterface Pointer to this interface structure. + */ + DECLR3CALLBACKMEMBER(void, pfnFlushQueue,(PPDMIKEYBOARDCONNECTOR pInterface)); + +} PDMIKEYBOARDCONNECTOR; +/** PDMIKEYBOARDCONNECTOR interface ID. */ +#define PDMIKEYBOARDCONNECTOR_IID "db3f7bd5-953e-436f-9f8e-077905a92d82" + + + +/** Pointer to a display port interface. */ +typedef struct PDMIDISPLAYPORT *PPDMIDISPLAYPORT; +/** + * Display port interface (down). + * Pair with PDMIDISPLAYCONNECTOR. + */ +typedef struct PDMIDISPLAYPORT +{ + /** + * Update the display with any changed regions. + * + * Flushes any display changes to the memory pointed to by the + * PDMIDISPLAYCONNECTOR interface and calles PDMIDISPLAYCONNECTOR::pfnUpdateRect() + * while doing so. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnUpdateDisplay,(PPDMIDISPLAYPORT pInterface)); + + /** + * Update the entire display. + * + * Flushes the entire display content to the memory pointed to by the + * PDMIDISPLAYCONNECTOR interface and calles PDMIDISPLAYCONNECTOR::pfnUpdateRect(). + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param fFailOnResize Fail is a resize is pending. + * @thread The emulation thread - bird sees no need for EMT here! + */ + DECLR3CALLBACKMEMBER(int, pfnUpdateDisplayAll,(PPDMIDISPLAYPORT pInterface, bool fFailOnResize)); + + /** + * Return the current guest resolution and color depth in bits per pixel (bpp). + * + * As the graphics card is able to provide display updates with the bpp + * requested by the host, this method can be used to query the actual + * guest color depth. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pcBits Where to store the current guest color depth. + * @param pcx Where to store the horizontal resolution. + * @param pcy Where to store the vertical resolution. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryVideoMode,(PPDMIDISPLAYPORT pInterface, uint32_t *pcBits, uint32_t *pcx, uint32_t *pcy)); + + /** + * Sets the refresh rate and restart the timer. + * The rate is defined as the minimum interval between the return of + * one PDMIDISPLAYPORT::pfnRefresh() call to the next one. + * + * The interval timer will be restarted by this call. So at VM startup + * this function must be called to start the refresh cycle. The refresh + * rate is not saved, but have to be when resuming a loaded VM state. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param cMilliesInterval Number of millis between two refreshes. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetRefreshRate,(PPDMIDISPLAYPORT pInterface, uint32_t cMilliesInterval)); + + /** + * Create a 32-bbp screenshot of the display. + * + * This will allocate and return a 32-bbp bitmap. Size of the bitmap scanline in bytes is 4*width. + * + * The allocated bitmap buffer must be freed with pfnFreeScreenshot. + * + * @param pInterface Pointer to this interface. + * @param ppbData Where to store the pointer to the allocated + * buffer. + * @param pcbData Where to store the actual size of the bitmap. + * @param pcx Where to store the width of the bitmap. + * @param pcy Where to store the height of the bitmap. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnTakeScreenshot,(PPDMIDISPLAYPORT pInterface, uint8_t **ppbData, size_t *pcbData, uint32_t *pcx, uint32_t *pcy)); + + /** + * Free screenshot buffer. + * + * This will free the memory buffer allocated by pfnTakeScreenshot. + * + * @param pInterface Pointer to this interface. + * @param pbData Pointer to the buffer returned by + * pfnTakeScreenshot. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(void, pfnFreeScreenshot,(PPDMIDISPLAYPORT pInterface, uint8_t *pbData)); + + /** + * Copy bitmap to the display. + * + * This will convert and copy a 32-bbp bitmap (with dword aligned scanline length) to + * the memory pointed to by the PDMIDISPLAYCONNECTOR interface. + * + * @param pInterface Pointer to this interface. + * @param pvData Pointer to the bitmap bits. + * @param x The upper left corner x coordinate of the destination rectangle. + * @param y The upper left corner y coordinate of the destination rectangle. + * @param cx The width of the source and destination rectangles. + * @param cy The height of the source and destination rectangles. + * @thread The emulation thread. + * @remark This is just a convenience for using the bitmap conversions of the + * graphics device. + */ + DECLR3CALLBACKMEMBER(int, pfnDisplayBlt,(PPDMIDISPLAYPORT pInterface, const void *pvData, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)); + + /** + * Render a rectangle from guest VRAM to Framebuffer. + * + * @param pInterface Pointer to this interface. + * @param x The upper left corner x coordinate of the rectangle to be updated. + * @param y The upper left corner y coordinate of the rectangle to be updated. + * @param cx The width of the rectangle to be updated. + * @param cy The height of the rectangle to be updated. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateDisplayRect,(PPDMIDISPLAYPORT pInterface, int32_t x, int32_t y, uint32_t cx, uint32_t cy)); + + /** + * Inform the VGA device whether the Display is directly using the guest VRAM and there is no need + * to render the VRAM to the framebuffer memory. + * + * @param pInterface Pointer to this interface. + * @param fRender Whether the VRAM content must be rendered to the framebuffer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnSetRenderVRAM,(PPDMIDISPLAYPORT pInterface, bool fRender)); + + /** + * Render a bitmap rectangle from source to target buffer. + * + * @param pInterface Pointer to this interface. + * @param cx The width of the rectangle to be copied. + * @param cy The height of the rectangle to be copied. + * @param pbSrc Source frame buffer 0,0. + * @param xSrc The upper left corner x coordinate of the source rectangle. + * @param ySrc The upper left corner y coordinate of the source rectangle. + * @param cxSrc The width of the source frame buffer. + * @param cySrc The height of the source frame buffer. + * @param cbSrcLine The line length of the source frame buffer. + * @param cSrcBitsPerPixel The pixel depth of the source. + * @param pbDst Destination frame buffer 0,0. + * @param xDst The upper left corner x coordinate of the destination rectangle. + * @param yDst The upper left corner y coordinate of the destination rectangle. + * @param cxDst The width of the destination frame buffer. + * @param cyDst The height of the destination frame buffer. + * @param cbDstLine The line length of the destination frame buffer. + * @param cDstBitsPerPixel The pixel depth of the destination. + * @thread The emulation thread - bird sees no need for EMT here! + */ + DECLR3CALLBACKMEMBER(int, pfnCopyRect,(PPDMIDISPLAYPORT pInterface, uint32_t cx, uint32_t cy, + const uint8_t *pbSrc, int32_t xSrc, int32_t ySrc, uint32_t cxSrc, uint32_t cySrc, uint32_t cbSrcLine, uint32_t cSrcBitsPerPixel, + uint8_t *pbDst, int32_t xDst, int32_t yDst, uint32_t cxDst, uint32_t cyDst, uint32_t cbDstLine, uint32_t cDstBitsPerPixel)); + + /** + * Inform the VGA device of viewport changes (as a result of e.g. scrolling). + * + * @param pInterface Pointer to this interface. + * @param idScreen The screen updates are for. + * @param x The upper left corner x coordinate of the new viewport rectangle + * @param y The upper left corner y coordinate of the new viewport rectangle + * @param cx The width of the new viewport rectangle + * @param cy The height of the new viewport rectangle + * @thread GUI thread? + * + * @remarks Is allowed to be NULL. + */ + DECLR3CALLBACKMEMBER(void, pfnSetViewport,(PPDMIDISPLAYPORT pInterface, + uint32_t idScreen, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)); + + /** + * Send a video mode hint to the VGA device. + * + * @param pInterface Pointer to this interface. + * @param cx The X resolution. + * @param cy The Y resolution. + * @param cBPP The bit count. + * @param iDisplay The screen number. + * @param dx X offset into the virtual framebuffer or ~0. + * @param dy Y offset into the virtual framebuffer or ~0. + * @param fEnabled Is this screen currently enabled? + * @param fNotifyGuest Should the device send the guest an IRQ? + * Set for the last hint of a series. + * @thread Schedules on the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSendModeHint, (PPDMIDISPLAYPORT pInterface, uint32_t cx, uint32_t cy, + uint32_t cBPP, uint32_t iDisplay, uint32_t dx, + uint32_t dy, uint32_t fEnabled, uint32_t fNotifyGuest)); + + /** + * Send the guest a notification about host cursor capabilities changes. + * + * @param pInterface Pointer to this interface. + * @param fSupportsRenderCursor Whether the host can draw the guest cursor + * using the host one provided the location matches. + * @param fSupportsMoveCursor Whether the host can draw the guest cursor + * itself at any position. Implies RenderCursor. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(void, pfnReportHostCursorCapabilities, (PPDMIDISPLAYPORT pInterface, bool fSupportsRenderCursor, bool fSupportsMoveCursor)); + + /** + * Tell the graphics device about the host cursor position. + * + * @param pInterface Pointer to this interface. + * @param x X offset into the cursor range. + * @param y Y offset into the cursor range. + * @param fOutOfRange The host pointer is out of all guest windows, so + * X and Y do not currently have meaningful value. + * @thread Any. + */ + DECLR3CALLBACKMEMBER(void, pfnReportHostCursorPosition, (PPDMIDISPLAYPORT pInterface, uint32_t x, uint32_t y, bool fOutOfRange)); + + /** + * Notify the graphics device about the monitor positions since the ones we get + * from vmwgfx FIFO are not correct. + * + * In an ideal universe this method should not be here. + * + * @param pInterface Pointer to this interface. + * @param cPositions Number of monitor positions. + * @param paPositions Monitor positions (offsets/origins) array. + * @thread Any (EMT). + * @sa PDMIVMMDEVCONNECTOR::pfnUpdateMonitorPositions + */ + DECLR3CALLBACKMEMBER(void, pfnReportMonitorPositions, (PPDMIDISPLAYPORT pInterface, uint32_t cPositions, + PCRTPOINT paPositions)); + +} PDMIDISPLAYPORT; +/** PDMIDISPLAYPORT interface ID. */ +#define PDMIDISPLAYPORT_IID "471b0520-338c-11e9-bb84-6ff2c956da45" + +/** @name Flags for PDMIDISPLAYCONNECTOR::pfnVBVAReportCursorPosition. + * @{ */ +/** Is the data in the report valid? */ +#define VBVA_CURSOR_VALID_DATA RT_BIT(0) +/** Is the cursor position reported relative to a particular guest screen? */ +#define VBVA_CURSOR_SCREEN_RELATIVE RT_BIT(1) +/** @} */ + +/** Pointer to a 3D graphics notification. */ +typedef struct VBOX3DNOTIFY VBOX3DNOTIFY; +/** Pointer to a 2D graphics acceleration command. */ +typedef struct VBOXVHWACMD VBOXVHWACMD; +/** Pointer to a VBVA command header. */ +typedef struct VBVACMDHDR *PVBVACMDHDR; +/** Pointer to a const VBVA command header. */ +typedef const struct VBVACMDHDR *PCVBVACMDHDR; +/** Pointer to a VBVA screen information. */ +typedef struct VBVAINFOSCREEN *PVBVAINFOSCREEN; +/** Pointer to a const VBVA screen information. */ +typedef const struct VBVAINFOSCREEN *PCVBVAINFOSCREEN; +/** Pointer to a VBVA guest VRAM area information. */ +typedef struct VBVAINFOVIEW *PVBVAINFOVIEW; +/** Pointer to a const VBVA guest VRAM area information. */ +typedef const struct VBVAINFOVIEW *PCVBVAINFOVIEW; +typedef struct VBVAHOSTFLAGS *PVBVAHOSTFLAGS; + +/** Pointer to a display connector interface. */ +typedef struct PDMIDISPLAYCONNECTOR *PPDMIDISPLAYCONNECTOR; + +/** + * Display connector interface (up). + * Pair with PDMIDISPLAYPORT. + */ +typedef struct PDMIDISPLAYCONNECTOR +{ + /** + * Resize the display. + * This is called when the resolution changes. This usually happens on + * request from the guest os, but may also happen as the result of a reset. + * If the callback returns VINF_VGA_RESIZE_IN_PROGRESS, the caller (VGA device) + * must not access the connector and return. + * + * @returns VINF_SUCCESS if the framebuffer resize was completed, + * VINF_VGA_RESIZE_IN_PROGRESS if resize takes time and not yet finished. + * @param pInterface Pointer to this interface. + * @param cBits Color depth (bits per pixel) of the new video mode. + * @param pvVRAM Address of the guest VRAM. + * @param cbLine Size in bytes of a single scan line. + * @param cx New display width. + * @param cy New display height. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnResize,(PPDMIDISPLAYCONNECTOR pInterface, uint32_t cBits, void *pvVRAM, uint32_t cbLine, + uint32_t cx, uint32_t cy)); + + /** + * Update a rectangle of the display. + * PDMIDISPLAYPORT::pfnUpdateDisplay is the caller. + * + * @param pInterface Pointer to this interface. + * @param x The upper left corner x coordinate of the rectangle. + * @param y The upper left corner y coordinate of the rectangle. + * @param cx The width of the rectangle. + * @param cy The height of the rectangle. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateRect,(PPDMIDISPLAYCONNECTOR pInterface, uint32_t x, uint32_t y, uint32_t cx, uint32_t cy)); + + /** + * Refresh the display. + * + * The interval between these calls is set by + * PDMIDISPLAYPORT::pfnSetRefreshRate(). The driver should call + * PDMIDISPLAYPORT::pfnUpdateDisplay() if it wishes to refresh the + * display. PDMIDISPLAYPORT::pfnUpdateDisplay calls pfnUpdateRect with + * the changed rectangles. + * + * @param pInterface Pointer to this interface. + * @thread The emulation thread or timer queue thread. + */ + DECLR3CALLBACKMEMBER(void, pfnRefresh,(PPDMIDISPLAYCONNECTOR pInterface)); + + /** + * Reset the display. + * + * Notification message when the graphics card has been reset. + * + * @param pInterface Pointer to this interface. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnReset,(PPDMIDISPLAYCONNECTOR pInterface)); + + /** + * LFB video mode enter/exit. + * + * Notification message when LinearFrameBuffer video mode is enabled/disabled. + * + * @param pInterface Pointer to this interface. + * @param fEnabled false - LFB mode was disabled, + * true - an LFB mode was disabled + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnLFBModeChange,(PPDMIDISPLAYCONNECTOR pInterface, bool fEnabled)); + + /** + * Process the guest graphics adapter information. + * + * Direct notification from guest to the display connector. + * + * @param pInterface Pointer to this interface. + * @param pvVRAM Address of the guest VRAM. + * @param u32VRAMSize Size of the guest VRAM. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnProcessAdapterData,(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, uint32_t u32VRAMSize)); + + /** + * Process the guest display information. + * + * Direct notification from guest to the display connector. + * + * @param pInterface Pointer to this interface. + * @param pvVRAM Address of the guest VRAM. + * @param uScreenId The index of the guest display to be processed. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnProcessDisplayData,(PPDMIDISPLAYCONNECTOR pInterface, void *pvVRAM, unsigned uScreenId)); + + /** + * Process the guest Video HW Acceleration command. + * + * @param pInterface Pointer to this interface. + * @param enmCmd The command type (don't re-read from pCmd). + * @param fGuestCmd Set if the command origins with the guest and + * pCmd must be considered volatile. + * @param pCmd Video HW Acceleration Command to be processed. + * @retval VINF_SUCCESS - command is completed, + * @retval VINF_CALLBACK_RETURN if command will by asynchronously completed via + * complete callback. + * @retval VERR_INVALID_STATE if the command could not be processed (most + * likely because the framebuffer was disconnected) - the post should + * be retried later. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnVHWACommandProcess,(PPDMIDISPLAYCONNECTOR pInterface, int enmCmd, bool fGuestCmd, + VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *pCmd)); + + /** + * The specified screen enters VBVA mode. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @param pHostFlags Undocumented! + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVBVAEnable,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, + struct VBVAHOSTFLAGS RT_UNTRUSTED_VOLATILE_GUEST *pHostFlags)); + + /** + * The specified screen leaves VBVA mode. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @thread if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVADisable,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)); + + /** + * A sequence of pfnVBVAUpdateProcess calls begins. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @thread if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAUpdateBegin,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId)); + + /** + * Process the guest VBVA command. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @param pCmd Video HW Acceleration Command to be processed. + * @param cbCmd Undocumented! + * @thread if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAUpdateProcess,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, + struct VBVACMDHDR const RT_UNTRUSTED_VOLATILE_GUEST *pCmd, size_t cbCmd)); + + /** + * A sequence of pfnVBVAUpdateProcess calls ends. + * + * @param pInterface Pointer to this interface. + * @param uScreenId The screen updates are for. + * @param x The upper left corner x coordinate of the combined rectangle of all VBVA updates. + * @param y The upper left corner y coordinate of the rectangle. + * @param cx The width of the rectangle. + * @param cy The height of the rectangle. + * @thread if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - the emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAUpdateEnd,(PPDMIDISPLAYCONNECTOR pInterface, unsigned uScreenId, int32_t x, int32_t y, + uint32_t cx, uint32_t cy)); + + /** + * Resize the display. + * This is called when the resolution changes. This usually happens on + * request from the guest os, but may also happen as the result of a reset. + * If the callback returns VINF_VGA_RESIZE_IN_PROGRESS, the caller (VGA device) + * must not access the connector and return. + * + * @todo Merge with pfnResize. + * + * @returns VINF_SUCCESS if the framebuffer resize was completed, + * VINF_VGA_RESIZE_IN_PROGRESS if resize takes time and not yet finished. + * @param pInterface Pointer to this interface. + * @param pView The description of VRAM block for this screen. + * @param pScreen The data of screen being resized. + * @param pvVRAM Address of the guest VRAM. + * @param fResetInputMapping Whether to reset the absolute pointing device to screen position co-ordinate + * mapping. Needed for real resizes, as the caller on the guest may not know how + * to set the mapping. Not wanted when we restore a saved state and are resetting + * the mode. + * @thread if render thread mode is on (fRenderThreadMode that was passed to pfnVBVAEnable is TRUE) - the render thread pfnVBVAEnable was called in, + * otherwise - the emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVBVAResize,(PPDMIDISPLAYCONNECTOR pInterface, PCVBVAINFOVIEW pView, PCVBVAINFOSCREEN pScreen, + void *pvVRAM, bool fResetInputMapping)); + + /** + * Update the pointer shape. + * This is called when the mouse pointer shape changes. The new shape + * is passed as a caller allocated buffer that will be freed after returning + * + * @param pInterface Pointer to this interface. + * @param fVisible Visibility indicator (if false, the other parameters are undefined). + * @param fAlpha Flag whether alpha channel is being passed. + * @param xHot Pointer hot spot x coordinate. + * @param yHot Pointer hot spot y coordinate. + * @param cx Pointer width in pixels. + * @param cy Pointer height in pixels. + * @param pvShape New shape buffer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVBVAMousePointerShape,(PPDMIDISPLAYCONNECTOR pInterface, bool fVisible, bool fAlpha, + uint32_t xHot, uint32_t yHot, uint32_t cx, uint32_t cy, + const void *pvShape)); + + /** + * The guest capabilities were updated. + * + * @param pInterface Pointer to this interface. + * @param fCapabilities The new capability flag state. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAGuestCapabilityUpdate,(PPDMIDISPLAYCONNECTOR pInterface, uint32_t fCapabilities)); + + /** Read-only attributes. + * For preformance reasons some readonly attributes are kept in the interface. + * We trust the interface users to respect the readonlyness of these. + * @{ + */ + /** Pointer to the display data buffer. */ + uint8_t *pbData; + /** Size of a scanline in the data buffer. */ + uint32_t cbScanline; + /** The color depth (in bits) the graphics card is supposed to provide. */ + uint32_t cBits; + /** The display width. */ + uint32_t cx; + /** The display height. */ + uint32_t cy; + /** @} */ + + /** + * The guest display input mapping rectangle was updated. + * + * @param pInterface Pointer to this interface. + * @param xOrigin Upper left X co-ordinate relative to the first screen. + * @param yOrigin Upper left Y co-ordinate relative to the first screen. + * @param cx Rectangle width. + * @param cy Rectangle height. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAInputMappingUpdate,(PPDMIDISPLAYCONNECTOR pInterface, int32_t xOrigin, int32_t yOrigin, uint32_t cx, uint32_t cy)); + + /** + * The guest is reporting the requested location of the host pointer. + * + * @param pInterface Pointer to this interface. + * @param fFlags VBVA_CURSOR_* + * @param uScreenId The screen to which X and Y are relative if VBVA_CURSOR_SCREEN_RELATIVE is set. + * @param x Cursor X offset. + * @param y Cursor Y offset. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAReportCursorPosition,(PPDMIDISPLAYCONNECTOR pInterface, uint32_t fFlags, uint32_t uScreen, uint32_t x, uint32_t y)); + + /** + * Process the graphics device HW Acceleration command. + * + * @param pInterface Pointer to this interface. + * @param p3DNotify Acceleration Command to be processed. + * @thread The graphics device thread: FIFO for the VMSVGA device. + */ + DECLR3CALLBACKMEMBER(int, pfn3DNotifyProcess,(PPDMIDISPLAYCONNECTOR pInterface, + VBOX3DNOTIFY *p3DNotify)); +} PDMIDISPLAYCONNECTOR; +/** PDMIDISPLAYCONNECTOR interface ID. */ +#define PDMIDISPLAYCONNECTOR_IID "cdd562e4-8030-11ea-8d40-bbc8e146c565" + + +/** Pointer to a secret key interface. */ +typedef struct PDMISECKEY *PPDMISECKEY; + +/** + * Secret key interface to retrieve secret keys. + */ +typedef struct PDMISECKEY +{ + /** + * Retains a key identified by the ID. The caller will only hold a reference + * to the key and must not modify the key buffer in any way. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszId The alias/id for the key to retrieve. + * @param ppbKey Where to store the pointer to the key buffer on success. + * @param pcbKey Where to store the size of the key in bytes on success. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyRetain, (PPDMISECKEY pInterface, const char *pszId, + const uint8_t **pbKey, size_t *pcbKey)); + + /** + * Releases one reference of the key identified by the given identifier. + * The caller must not access the key buffer after calling this operation. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszId The alias/id for the key to release. + * + * @note: It is advised to release the key whenever it is not used anymore so the entity + * storing the key can do anything to make retrieving the key from memory more + * difficult like scrambling the memory buffer for instance. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyRelease, (PPDMISECKEY pInterface, const char *pszId)); + + /** + * Retains a password identified by the ID. The caller will only hold a reference + * to the password and must not modify the buffer in any way. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszId The alias/id for the password to retrieve. + * @param ppszPassword Where to store the pointer to the password on success. + */ + DECLR3CALLBACKMEMBER(int, pfnPasswordRetain, (PPDMISECKEY pInterface, const char *pszId, + const char **ppszPassword)); + + /** + * Releases one reference of the password identified by the given identifier. + * The caller must not access the password after calling this operation. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszId The alias/id for the password to release. + * + * @note: It is advised to release the password whenever it is not used anymore so the entity + * storing the password can do anything to make retrieving the password from memory more + * difficult like scrambling the memory buffer for instance. + */ + DECLR3CALLBACKMEMBER(int, pfnPasswordRelease, (PPDMISECKEY pInterface, const char *pszId)); +} PDMISECKEY; +/** PDMISECKEY interface ID. */ +#define PDMISECKEY_IID "3d698355-d995-453d-960f-31566a891df2" + +/** Pointer to a secret key helper interface. */ +typedef struct PDMISECKEYHLP *PPDMISECKEYHLP; + +/** + * Secret key helper interface for non critical functionality. + */ +typedef struct PDMISECKEYHLP +{ + /** + * Notifies the interface provider that a key couldn't be retrieved from the key store. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + */ + DECLR3CALLBACKMEMBER(int, pfnKeyMissingNotify, (PPDMISECKEYHLP pInterface)); + +} PDMISECKEYHLP; +/** PDMISECKEY interface ID. */ +#define PDMISECKEYHLP_IID "7be96168-4156-40ac-86d2-3073bf8b318e" + + +/** Pointer to a stream interface. */ +typedef struct PDMISTREAM *PPDMISTREAM; +/** + * Stream interface (up). + * Makes up the foundation for PDMICHARCONNECTOR. No pair interface. + */ +typedef struct PDMISTREAM +{ + /** + * Polls for the specified events. + * + * @returns VBox status code. + * @retval VERR_INTERRUPTED if the poll was interrupted. + * @retval VERR_TIMEOUT if the maximum waiting time was reached. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fEvts The events to poll for, see RTPOLL_EVT_XXX. + * @param pfEvts Where to return details about the events that occurred. + * @param cMillies Number of milliseconds to wait. Use + * RT_INDEFINITE_WAIT to wait for ever. + */ + DECLR3CALLBACKMEMBER(int, pfnPoll,(PPDMISTREAM pInterface, uint32_t fEvts, uint32_t *pfEvts, RTMSINTERVAL cMillies)); + + /** + * Interrupts the current poll call. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnPollInterrupt,(PPDMISTREAM pInterface)); + + /** + * Read bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the read bits. + * @param pcbRead Number of bytes to read/bytes actually read. + * @thread Any thread. + * + * @note: This is non blocking, use the poll callback to block when there is nothing to read. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMISTREAM pInterface, void *pvBuf, size_t *pcbRead)); + + /** + * Write bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the write bits. + * @param pcbWrite Number of bytes to write/bytes actually written. + * @thread Any thread. + * + * @note: This is non blocking, use the poll callback to block until there is room to write. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMISTREAM pInterface, const void *pvBuf, size_t *pcbWrite)); +} PDMISTREAM; +/** PDMISTREAM interface ID. */ +#define PDMISTREAM_IID "f9bd1ba6-c134-44cc-8259-febe14393952" + + +/** Mode of the parallel port */ +typedef enum PDMPARALLELPORTMODE +{ + /** First invalid mode. */ + PDM_PARALLEL_PORT_MODE_INVALID = 0, + /** SPP (Compatibility mode). */ + PDM_PARALLEL_PORT_MODE_SPP, + /** EPP Data mode. */ + PDM_PARALLEL_PORT_MODE_EPP_DATA, + /** EPP Address mode. */ + PDM_PARALLEL_PORT_MODE_EPP_ADDR, + /** ECP mode (not implemented yet). */ + PDM_PARALLEL_PORT_MODE_ECP, + /** 32bit hack. */ + PDM_PARALLEL_PORT_MODE_32BIT_HACK = 0x7fffffff +} PDMPARALLELPORTMODE; + +/** Pointer to a host parallel port interface. */ +typedef struct PDMIHOSTPARALLELPORT *PPDMIHOSTPARALLELPORT; +/** + * Host parallel port interface (down). + * Pair with PDMIHOSTPARALLELCONNECTOR. + */ +typedef struct PDMIHOSTPARALLELPORT +{ + /** + * Notify device/driver that an interrupt has occurred. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnNotifyInterrupt,(PPDMIHOSTPARALLELPORT pInterface)); +} PDMIHOSTPARALLELPORT; +/** PDMIHOSTPARALLELPORT interface ID. */ +#define PDMIHOSTPARALLELPORT_IID "f24b8668-e7f6-4eaa-a14c-4aa2a5f7048e" + + + +/** Pointer to a Host Parallel connector interface. */ +typedef struct PDMIHOSTPARALLELCONNECTOR *PPDMIHOSTPARALLELCONNECTOR; +/** + * Host parallel connector interface (up). + * Pair with PDMIHOSTPARALLELPORT. + */ +typedef struct PDMIHOSTPARALLELCONNECTOR +{ + /** + * Write bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the write bits. + * @param cbWrite Number of bytes to write. + * @param enmMode Mode to write the data. + * @thread Any thread. + * @todo r=klaus cbWrite only defines buffer length, method needs a way top return actually written amount of data. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMIHOSTPARALLELCONNECTOR pInterface, const void *pvBuf, + size_t cbWrite, PDMPARALLELPORTMODE enmMode)); + + /** + * Read bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the read bits. + * @param cbRead Number of bytes to read. + * @param enmMode Mode to read the data. + * @thread Any thread. + * @todo r=klaus cbRead only defines buffer length, method needs a way top return actually read amount of data. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMIHOSTPARALLELCONNECTOR pInterface, void *pvBuf, + size_t cbRead, PDMPARALLELPORTMODE enmMode)); + + /** + * Set data direction of the port (forward/reverse). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fForward Flag whether to indicate whether the port is operated in forward or reverse mode. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetPortDirection,(PPDMIHOSTPARALLELCONNECTOR pInterface, bool fForward)); + + /** + * Write control register bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fReg The new control register value. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteControl,(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t fReg)); + + /** + * Read control register bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfReg Where to store the control register bits. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnReadControl,(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t *pfReg)); + + /** + * Read status register bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfReg Where to store the status register bits. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnReadStatus,(PPDMIHOSTPARALLELCONNECTOR pInterface, uint8_t *pfReg)); + +} PDMIHOSTPARALLELCONNECTOR; +/** PDMIHOSTPARALLELCONNECTOR interface ID. */ +#define PDMIHOSTPARALLELCONNECTOR_IID "7c532602-7438-4fbc-9265-349d9f0415f9" + + +/** ACPI power source identifier */ +typedef enum PDMACPIPOWERSOURCE +{ + PDM_ACPI_POWER_SOURCE_UNKNOWN = 0, + PDM_ACPI_POWER_SOURCE_OUTLET, + PDM_ACPI_POWER_SOURCE_BATTERY +} PDMACPIPOWERSOURCE; +/** Pointer to ACPI battery state. */ +typedef PDMACPIPOWERSOURCE *PPDMACPIPOWERSOURCE; + +/** ACPI battey capacity */ +typedef enum PDMACPIBATCAPACITY +{ + PDM_ACPI_BAT_CAPACITY_MIN = 0, + PDM_ACPI_BAT_CAPACITY_MAX = 100, + PDM_ACPI_BAT_CAPACITY_UNKNOWN = 255 +} PDMACPIBATCAPACITY; +/** Pointer to ACPI battery capacity. */ +typedef PDMACPIBATCAPACITY *PPDMACPIBATCAPACITY; + +/** ACPI battery state. See ACPI 3.0 spec '_BST (Battery Status)' */ +typedef enum PDMACPIBATSTATE +{ + PDM_ACPI_BAT_STATE_CHARGED = 0x00, + PDM_ACPI_BAT_STATE_DISCHARGING = 0x01, + PDM_ACPI_BAT_STATE_CHARGING = 0x02, + PDM_ACPI_BAT_STATE_CRITICAL = 0x04 +} PDMACPIBATSTATE; +/** Pointer to ACPI battery state. */ +typedef PDMACPIBATSTATE *PPDMACPIBATSTATE; + +/** Pointer to an ACPI port interface. */ +typedef struct PDMIACPIPORT *PPDMIACPIPORT; +/** + * ACPI port interface (down). Used by both the ACPI driver and (grumble) main. + * Pair with PDMIACPICONNECTOR. + */ +typedef struct PDMIACPIPORT +{ + /** + * Send an ACPI power off event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnPowerButtonPress,(PPDMIACPIPORT pInterface)); + + /** + * Send an ACPI sleep button event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnSleepButtonPress,(PPDMIACPIPORT pInterface)); + + /** + * Check if the last power button event was handled by the guest. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfHandled Is set to true if the last power button event was handled, false otherwise. + */ + DECLR3CALLBACKMEMBER(int, pfnGetPowerButtonHandled,(PPDMIACPIPORT pInterface, bool *pfHandled)); + + /** + * Check if the guest entered the ACPI mode. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfEntered Is set to true if the guest entered the ACPI mode, false otherwise. + */ + DECLR3CALLBACKMEMBER(int, pfnGetGuestEnteredACPIMode,(PPDMIACPIPORT pInterface, bool *pfEntered)); + + /** + * Check if the given CPU is still locked by the guest. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param uCpu The CPU to check for. + * @param pfLocked Is set to true if the CPU is still locked by the guest, false otherwise. + */ + DECLR3CALLBACKMEMBER(int, pfnGetCpuStatus,(PPDMIACPIPORT pInterface, unsigned uCpu, bool *pfLocked)); + + /** + * Send an ACPI monitor hot-plug event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing + * the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnMonitorHotPlugEvent,(PPDMIACPIPORT pInterface)); + + /** + * Send a battery status change event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing + * the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnBatteryStatusChangeEvent,(PPDMIACPIPORT pInterface)); +} PDMIACPIPORT; +/** PDMIACPIPORT interface ID. */ +#define PDMIACPIPORT_IID "974cb8fb-7fda-408c-f9b4-7ff4e3b2a699" + + +/** Pointer to an ACPI connector interface. */ +typedef struct PDMIACPICONNECTOR *PPDMIACPICONNECTOR; +/** + * ACPI connector interface (up). + * Pair with PDMIACPIPORT. + */ +typedef struct PDMIACPICONNECTOR +{ + /** + * Get the current power source of the host system. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param penmPowerSource Pointer to the power source result variable. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryPowerSource,(PPDMIACPICONNECTOR, PPDMACPIPOWERSOURCE penmPowerSource)); + + /** + * Query the current battery status of the host system. + * + * @returns VBox status code? + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfPresent Is set to true if battery is present, false otherwise. + * @param penmRemainingCapacity Pointer to the battery remaining capacity (0 - 100 or 255 for unknown). + * @param penmBatteryState Pointer to the battery status. + * @param pu32PresentRate Pointer to the present rate (0..1000 of the total capacity). + */ + DECLR3CALLBACKMEMBER(int, pfnQueryBatteryStatus,(PPDMIACPICONNECTOR, bool *pfPresent, PPDMACPIBATCAPACITY penmRemainingCapacity, + PPDMACPIBATSTATE penmBatteryState, uint32_t *pu32PresentRate)); +} PDMIACPICONNECTOR; +/** PDMIACPICONNECTOR interface ID. */ +#define PDMIACPICONNECTOR_IID "5f14bf8d-1edf-4e3a-a1e1-cca9fd08e359" + +struct VMMDevDisplayDef; + +/** Pointer to a VMMDevice port interface. */ +typedef struct PDMIVMMDEVPORT *PPDMIVMMDEVPORT; +/** + * VMMDevice port interface (down). + * Pair with PDMIVMMDEVCONNECTOR. + */ +typedef struct PDMIVMMDEVPORT +{ + /** + * Return the current absolute mouse position in pixels + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pxAbs Pointer of result value, can be NULL + * @param pyAbs Pointer of result value, can be NULL + */ + DECLR3CALLBACKMEMBER(int, pfnQueryAbsoluteMouse,(PPDMIVMMDEVPORT pInterface, int32_t *pxAbs, int32_t *pyAbs)); + + /** + * Set the new absolute mouse position in pixels + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param xAbs New absolute X position + * @param yAbs New absolute Y position + * @param dz New mouse wheel vertical movement offset + * @param dw New mouse wheel horizontal movement offset + * @param fButtons New buttons state + */ + DECLR3CALLBACKMEMBER(int, pfnSetAbsoluteMouse,(PPDMIVMMDEVPORT pInterface, int32_t xAbs, int32_t yAbs, + int32_t dz, int32_t dw, uint32_t fButtons)); + + /** + * Return the current mouse capability flags + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfCapabilities Pointer of result value + */ + DECLR3CALLBACKMEMBER(int, pfnQueryMouseCapabilities,(PPDMIVMMDEVPORT pInterface, uint32_t *pfCapabilities)); + + /** + * Set the current mouse capability flag (host side) + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fCapsAdded Mask of capabilities to add to the flag + * @param fCapsRemoved Mask of capabilities to remove from the flag + */ + DECLR3CALLBACKMEMBER(int, pfnUpdateMouseCapabilities,(PPDMIVMMDEVPORT pInterface, uint32_t fCapsAdded, uint32_t fCapsRemoved)); + + /** + * Issue a display resolution change request. + * + * Note that there can only one request in the queue and that in case the guest does + * not process it, issuing another request will overwrite the previous. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cDisplays Number of displays. Can be either 1 or the number of VM virtual monitors. + * @param paDisplays Definitions of guest screens to be applied. See VMMDev.h + * @param fForce Whether to deliver the request to the guest even if the guest has + * the requested resolution already. + * @param fMayNotify Whether to send a hotplug notification to the guest if appropriate. + */ + DECLR3CALLBACKMEMBER(int, pfnRequestDisplayChange,(PPDMIVMMDEVPORT pInterface, uint32_t cDisplays, + struct VMMDevDisplayDef const *paDisplays, bool fForce, bool fMayNotify)); + + /** + * Pass credentials to guest. + * + * Note that there can only be one set of credentials and the guest may or may not + * query them and may do whatever it wants with them. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pszUsername User name, may be empty (UTF-8). + * @param pszPassword Password, may be empty (UTF-8). + * @param pszDomain Domain name, may be empty (UTF-8). + * @param fFlags VMMDEV_SETCREDENTIALS_*. + */ + DECLR3CALLBACKMEMBER(int, pfnSetCredentials,(PPDMIVMMDEVPORT pInterface, const char *pszUsername, + const char *pszPassword, const char *pszDomain, + uint32_t fFlags)); + + /** + * Notify the driver about a VBVA status change. + * + * @returns Nothing. Because it is informational callback. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fEnabled Current VBVA status. + */ + DECLR3CALLBACKMEMBER(void, pfnVBVAChange, (PPDMIVMMDEVPORT pInterface, bool fEnabled)); + + /** + * Issue a seamless mode change request. + * + * Note that there can only one request in the queue and that in case the guest does + * not process it, issuing another request will overwrite the previous. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fEnabled Seamless mode enabled or not + */ + DECLR3CALLBACKMEMBER(int, pfnRequestSeamlessChange,(PPDMIVMMDEVPORT pInterface, bool fEnabled)); + + /** + * Issue a memory balloon change request. + * + * Note that there can only one request in the queue and that in case the guest does + * not process it, issuing another request will overwrite the previous. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cMbBalloon Balloon size in megabytes + */ + DECLR3CALLBACKMEMBER(int, pfnSetMemoryBalloon,(PPDMIVMMDEVPORT pInterface, uint32_t cMbBalloon)); + + /** + * Issue a statistcs interval change request. + * + * Note that there can only one request in the queue and that in case the guest does + * not process it, issuing another request will overwrite the previous. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cSecsStatInterval Statistics query interval in seconds + * (0=disable). + */ + DECLR3CALLBACKMEMBER(int, pfnSetStatisticsInterval,(PPDMIVMMDEVPORT pInterface, uint32_t cSecsStatInterval)); + + /** + * Notify the guest about a VRDP status change. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fVRDPEnabled Current VRDP status. + * @param uVRDPExperienceLevel Which visual effects to be disabled in + * the guest. + */ + DECLR3CALLBACKMEMBER(int, pfnVRDPChange, (PPDMIVMMDEVPORT pInterface, bool fVRDPEnabled, uint32_t uVRDPExperienceLevel)); + + /** + * Notify the guest of CPU hot-unplug event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param idCpuCore The core id of the CPU to remove. + * @param idCpuPackage The package id of the CPU to remove. + */ + DECLR3CALLBACKMEMBER(int, pfnCpuHotUnplug, (PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)); + + /** + * Notify the guest of CPU hot-plug event. + * + * @returns VBox status code + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param idCpuCore The core id of the CPU to add. + * @param idCpuPackage The package id of the CPU to add. + */ + DECLR3CALLBACKMEMBER(int, pfnCpuHotPlug, (PPDMIVMMDEVPORT pInterface, uint32_t idCpuCore, uint32_t idCpuPackage)); + +} PDMIVMMDEVPORT; +/** PDMIVMMDEVPORT interface ID. */ +#define PDMIVMMDEVPORT_IID "9e004f1a-875d-11e9-a673-c77c30f53623" + + +/** Pointer to a HPET legacy notification interface. */ +typedef struct PDMIHPETLEGACYNOTIFY *PPDMIHPETLEGACYNOTIFY; +/** + * HPET legacy notification interface. + */ +typedef struct PDMIHPETLEGACYNOTIFY +{ + /** + * Notify about change of HPET legacy mode. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * @param fActivated If HPET legacy mode is activated (@c true) or + * deactivated (@c false). + */ + DECLR3CALLBACKMEMBER(void, pfnModeChanged,(PPDMIHPETLEGACYNOTIFY pInterface, bool fActivated)); +} PDMIHPETLEGACYNOTIFY; +/** PDMIHPETLEGACYNOTIFY interface ID. */ +#define PDMIHPETLEGACYNOTIFY_IID "c9ada595-4b65-4311-8b21-b10498997774" + + +/** @name Flags for PDMIVMMDEVPORT::pfnSetCredentials. + * @{ */ +/** The guest should perform a logon with the credentials. */ +#define VMMDEV_SETCREDENTIALS_GUESTLOGON RT_BIT(0) +/** The guest should prevent local logons. */ +#define VMMDEV_SETCREDENTIALS_NOLOCALLOGON RT_BIT(1) +/** The guest should verify the credentials. */ +#define VMMDEV_SETCREDENTIALS_JUDGE RT_BIT(15) +/** @} */ + +/** Forward declaration of the guest information structure. */ +struct VBoxGuestInfo; +/** Forward declaration of the guest information-2 structure. */ +struct VBoxGuestInfo2; +/** Forward declaration of the guest statistics structure */ +struct VBoxGuestStatistics; +/** Forward declaration of the guest status structure */ +struct VBoxGuestStatus; + +/** Forward declaration of the video accelerator command memory. */ +struct VBVAMEMORY; +/** Pointer to video accelerator command memory. */ +typedef struct VBVAMEMORY *PVBVAMEMORY; + +/** Pointer to a VMMDev connector interface. */ +typedef struct PDMIVMMDEVCONNECTOR *PPDMIVMMDEVCONNECTOR; +/** + * VMMDev connector interface (up). + * Pair with PDMIVMMDEVPORT. + */ +typedef struct PDMIVMMDEVCONNECTOR +{ + /** + * Update guest facility status. + * + * Called in response to VMMDevReq_ReportGuestStatus, reset or state restore. + * + * @param pInterface Pointer to this interface. + * @param uFacility The facility. + * @param uStatus The status. + * @param fFlags Flags assoicated with the update. Currently + * reserved and should be ignored. + * @param pTimeSpecTS Pointer to the timestamp of this report. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestStatus,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t uFacility, uint16_t uStatus, + uint32_t fFlags, PCRTTIMESPEC pTimeSpecTS)); + + /** + * Updates a guest user state. + * + * Called in response to VMMDevReq_ReportGuestUserState. + * + * @param pInterface Pointer to this interface. + * @param pszUser Guest user name to update status for. + * @param pszDomain Domain the guest user is bound to. Optional. + * @param uState New guest user state to notify host about. + * @param pabDetails Pointer to optional state data. + * @param cbDetails Size (in bytes) of optional state data. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestUserState,(PPDMIVMMDEVCONNECTOR pInterface, const char *pszUser, + const char *pszDomain, uint32_t uState, + const uint8_t *pabDetails, uint32_t cbDetails)); + + /** + * Reports the guest API and OS version. + * Called whenever the Additions issue a guest info report request. + * + * @param pInterface Pointer to this interface. + * @param pGuestInfo Pointer to guest information structure + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestInfo,(PPDMIVMMDEVCONNECTOR pInterface, const struct VBoxGuestInfo *pGuestInfo)); + + /** + * Reports the detailed Guest Additions version. + * + * @param pInterface Pointer to this interface. + * @param uFullVersion The guest additions version as a full version. + * Use VBOX_FULL_VERSION_GET_MAJOR, + * VBOX_FULL_VERSION_GET_MINOR and + * VBOX_FULL_VERSION_GET_BUILD to access it. + * (This will not be zero, so turn down the + * paranoia level a notch.) + * @param pszName Pointer to the sanitized version name. This can + * be empty, but will not be NULL. If not empty, + * it will contain a build type tag and/or a + * publisher tag. If both, then they are separated + * by an underscore (VBOX_VERSION_STRING fashion). + * @param uRevision The SVN revision. Can be 0. + * @param fFeatures Feature mask, currently none are defined. + * + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestInfo2,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t uFullVersion, + const char *pszName, uint32_t uRevision, uint32_t fFeatures)); + + /** + * Update the guest additions capabilities. + * This is called when the guest additions capabilities change. The new capabilities + * are given and the connector should update its internal state. + * + * @param pInterface Pointer to this interface. + * @param newCapabilities New capabilities. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateGuestCapabilities,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t newCapabilities)); + + /** + * Update the mouse capabilities. + * This is called when the mouse capabilities change. The new capabilities + * are given and the connector should update its internal state. + * + * @param pInterface Pointer to this interface. + * @param newCapabilities New capabilities. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdateMouseCapabilities,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t newCapabilities)); + + /** + * Update the pointer shape. + * This is called when the mouse pointer shape changes. The new shape + * is passed as a caller allocated buffer that will be freed after returning + * + * @param pInterface Pointer to this interface. + * @param fVisible Visibility indicator (if false, the other parameters are undefined). + * @param fAlpha Flag whether alpha channel is being passed. + * @param xHot Pointer hot spot x coordinate. + * @param yHot Pointer hot spot y coordinate. + * @param x Pointer new x coordinate on screen. + * @param y Pointer new y coordinate on screen. + * @param cx Pointer width in pixels. + * @param cy Pointer height in pixels. + * @param cbScanline Size of one scanline in bytes. + * @param pvShape New shape buffer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUpdatePointerShape,(PPDMIVMMDEVCONNECTOR pInterface, bool fVisible, bool fAlpha, + uint32_t xHot, uint32_t yHot, + uint32_t cx, uint32_t cy, + void *pvShape)); + + /** + * Enable or disable video acceleration on behalf of guest. + * + * @param pInterface Pointer to this interface. + * @param fEnable Whether to enable acceleration. + * @param pVbvaMemory Video accelerator memory. + + * @return VBox rc. VINF_SUCCESS if VBVA was enabled. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVideoAccelEnable,(PPDMIVMMDEVCONNECTOR pInterface, bool fEnable, PVBVAMEMORY pVbvaMemory)); + + /** + * Force video queue processing. + * + * @param pInterface Pointer to this interface. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnVideoAccelFlush,(PPDMIVMMDEVCONNECTOR pInterface)); + + /** + * Return whether the given video mode is supported/wanted by the host. + * + * @returns VBox status code + * @param pInterface Pointer to this interface. + * @param display The guest monitor, 0 for primary. + * @param cy Video mode horizontal resolution in pixels. + * @param cx Video mode vertical resolution in pixels. + * @param cBits Video mode bits per pixel. + * @param pfSupported Where to put the indicator for whether this mode is supported. (output) + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVideoModeSupported,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t display, uint32_t cx, uint32_t cy, uint32_t cBits, bool *pfSupported)); + + /** + * Queries by how many pixels the height should be reduced when calculating video modes + * + * @returns VBox status code + * @param pInterface Pointer to this interface. + * @param pcyReduction Pointer to the result value. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnGetHeightReduction,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcyReduction)); + + /** + * Informs about a credentials judgement result from the guest. + * + * @returns VBox status code + * @param pInterface Pointer to this interface. + * @param fFlags Judgement result flags. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetCredentialsJudgementResult,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t fFlags)); + + /** + * Set the visible region of the display + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param cRect Number of rectangles in pRect + * @param pRect Rectangle array + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetVisibleRegion,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t cRect, PRTRECT pRect)); + + /** + * Update monitor positions (offsets). + * + * Passing monitor positions from the guest to host exclusively since vmwgfx + * (linux driver) fails to do so thru the FIFO. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param cPositions Number of monitor positions + * @param paPositions Positions array + * @remarks Is allowed to be NULL. + * @thread The emulation thread. + * @sa PDMIDISPLAYPORT::pfnReportMonitorPositions + */ + DECLR3CALLBACKMEMBER(int, pfnUpdateMonitorPositions,(PPDMIVMMDEVCONNECTOR pInterface, + uint32_t cPositions, PCRTPOINT paPositions)); + + /** + * Query the visible region of the display + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pcRects Where to return the number of rectangles in + * paRects. + * @param paRects Rectangle array (set to NULL to query the number + * of rectangles) + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryVisibleRegion,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcRects, PRTRECT paRects)); + + /** + * Request the statistics interval + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pulInterval Pointer to interval in seconds + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryStatisticsInterval,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pulInterval)); + + /** + * Report new guest statistics + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pGuestStats Guest statistics + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnReportStatistics,(PPDMIVMMDEVCONNECTOR pInterface, struct VBoxGuestStatistics *pGuestStats)); + + /** + * Query the current balloon size + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pcbBalloon Balloon size + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryBalloonSize,(PPDMIVMMDEVCONNECTOR pInterface, uint32_t *pcbBalloon)); + + /** + * Query the current page fusion setting + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pfPageFusionEnabled Pointer to boolean + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIsPageFusionEnabled,(PPDMIVMMDEVCONNECTOR pInterface, bool *pfPageFusionEnabled)); + +} PDMIVMMDEVCONNECTOR; +/** PDMIVMMDEVCONNECTOR interface ID. */ +#define PDMIVMMDEVCONNECTOR_IID "aff90240-a443-434e-9132-80c186ab97d4" + + +/** + * Generic status LED core. + * Note that a unit doesn't have to support all the indicators. + */ +typedef union PDMLEDCORE +{ + /** 32-bit view. */ + uint32_t volatile u32; + /** Bit view. */ + struct + { + /** Reading/Receiving indicator. */ + uint32_t fReading : 1; + /** Writing/Sending indicator. */ + uint32_t fWriting : 1; + /** Busy indicator. */ + uint32_t fBusy : 1; + /** Error indicator. */ + uint32_t fError : 1; + } s; +} PDMLEDCORE; + +/** LED bit masks for the u32 view. + * @{ */ +/** Reading/Receiving indicator. */ +#define PDMLED_READING RT_BIT(0) +/** Writing/Sending indicator. */ +#define PDMLED_WRITING RT_BIT(1) +/** Busy indicator. */ +#define PDMLED_BUSY RT_BIT(2) +/** Error indicator. */ +#define PDMLED_ERROR RT_BIT(3) +/** @} */ + + +/** + * Generic status LED. + * Note that a unit doesn't have to support all the indicators. + */ +typedef struct PDMLED +{ + /** Just a magic for sanity checking. */ + uint32_t u32Magic; + uint32_t u32Alignment; /**< structure size alignment. */ + /** The actual LED status. + * Only the device is allowed to change this. */ + PDMLEDCORE Actual; + /** The asserted LED status which is cleared by the reader. + * The device will assert the bits but never clear them. + * The driver clears them as it sees fit. */ + PDMLEDCORE Asserted; +} PDMLED; + +/** Pointer to an LED. */ +typedef PDMLED *PPDMLED; +/** Pointer to a const LED. */ +typedef const PDMLED *PCPDMLED; + +/** Magic value for PDMLED::u32Magic. */ +#define PDMLED_MAGIC UINT32_C(0x11335577) + +/** Pointer to an LED ports interface. */ +typedef struct PDMILEDPORTS *PPDMILEDPORTS; +/** + * Interface for exporting LEDs (down). + * Pair with PDMILEDCONNECTORS. + */ +typedef struct PDMILEDPORTS +{ + /** + * Gets the pointer to the status LED of a unit. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param iLUN The unit which status LED we desire. + * @param ppLed Where to store the LED pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryStatusLed,(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)); + +} PDMILEDPORTS; +/** PDMILEDPORTS interface ID. */ +#define PDMILEDPORTS_IID "435e0cec-8549-4ca0-8c0d-98e52f1dc038" + + +/** Pointer to an LED connectors interface. */ +typedef struct PDMILEDCONNECTORS *PPDMILEDCONNECTORS; +/** + * Interface for reading LEDs (up). + * Pair with PDMILEDPORTS. + */ +typedef struct PDMILEDCONNECTORS +{ + /** + * Notification about a unit which have been changed. + * + * The driver must discard any pointers to data owned by + * the unit and requery it. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param iLUN The unit number. + */ + DECLR3CALLBACKMEMBER(void, pfnUnitChanged,(PPDMILEDCONNECTORS pInterface, unsigned iLUN)); +} PDMILEDCONNECTORS; +/** PDMILEDCONNECTORS interface ID. */ +#define PDMILEDCONNECTORS_IID "8ed63568-82a7-4193-b57b-db8085ac4495" + + +/** Pointer to a Media Notification interface. */ +typedef struct PDMIMEDIANOTIFY *PPDMIMEDIANOTIFY; +/** + * Interface for exporting Medium eject information (up). No interface pair. + */ +typedef struct PDMIMEDIANOTIFY +{ + /** + * Signals that the medium was ejected. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param iLUN The unit which had the medium ejected. + */ + DECLR3CALLBACKMEMBER(int, pfnEjected,(PPDMIMEDIANOTIFY pInterface, unsigned iLUN)); + +} PDMIMEDIANOTIFY; +/** PDMIMEDIANOTIFY interface ID. */ +#define PDMIMEDIANOTIFY_IID "fc22d53e-feb1-4a9c-b9fb-0a990a6ab288" + + +/** The special status unit number */ +#define PDM_STATUS_LUN 999 + + +#ifdef VBOX_WITH_HGCM + +/** Abstract HGCM command structure. Used only to define a typed pointer. */ +struct VBOXHGCMCMD; + +/** Pointer to HGCM command structure. This pointer is unique and identifies + * the command being processed. The pointer is passed to HGCM connector methods, + * and must be passed back to HGCM port when command is completed. + */ +typedef struct VBOXHGCMCMD *PVBOXHGCMCMD; + +/** Pointer to a HGCM port interface. */ +typedef struct PDMIHGCMPORT *PPDMIHGCMPORT; +/** + * Host-Guest communication manager port interface (down). Normally implemented + * by VMMDev. + * Pair with PDMIHGCMCONNECTOR. + */ +typedef struct PDMIHGCMPORT +{ + /** + * Notify the guest on a command completion. + * + * @returns VINF_SUCCESS or VERR_CANCELLED if the guest canceled the call. + * @param pInterface Pointer to this interface. + * @param rc The return code (VBox error code). + * @param pCmd A pointer that identifies the completed command. + */ + DECLR3CALLBACKMEMBER(int, pfnCompleted,(PPDMIHGCMPORT pInterface, int32_t rc, PVBOXHGCMCMD pCmd)); + + /** + * Checks if @a pCmd was restored & resubmitted from saved state. + * + * @returns true if restored, false if not. + * @param pInterface Pointer to this interface. + * @param pCmd The command we're checking on. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsCmdRestored,(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd)); + + /** + * Checks if @a pCmd was cancelled. + * + * @returns true if cancelled, false if not. + * @param pInterface Pointer to this interface. + * @param pCmd The command we're checking on. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsCmdCancelled,(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd)); + + /** + * Gets the VMMDevRequestHeader::fRequestor value for @a pCmd. + * + * @returns The fRequestor value, VMMDEV_REQUESTOR_LEGACY if guest does not + * support it, VMMDEV_REQUESTOR_LOWEST if invalid parameters. + * @param pInterface Pointer to this interface. + * @param pCmd The command we're in checking on. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetRequestor,(PPDMIHGCMPORT pInterface, PVBOXHGCMCMD pCmd)); + + /** + * Gets the VMMDevState::idSession value. + * + * @returns VMMDevState::idSession. + * @param pInterface Pointer to this interface. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetVMMDevSessionId,(PPDMIHGCMPORT pInterface)); + +} PDMIHGCMPORT; +/** PDMIHGCMPORT interface ID. */ +# define PDMIHGCMPORT_IID "28c0a201-68cd-4752-9404-bb42a0c09eb7" + +/* forward decl to hgvmsvc.h. */ +struct VBOXHGCMSVCPARM; +/** Pointer to a HGCM service location structure. */ +typedef struct HGCMSERVICELOCATION *PHGCMSERVICELOCATION; +/** Pointer to a HGCM connector interface. */ +typedef struct PDMIHGCMCONNECTOR *PPDMIHGCMCONNECTOR; +/** + * The Host-Guest communication manager connector interface (up). Normally + * implemented by Main::VMMDevInterface. + * Pair with PDMIHGCMPORT. + */ +typedef struct PDMIHGCMCONNECTOR +{ + /** + * Locate a service and inform it about a client connection. + * + * @param pInterface Pointer to this interface. + * @param pCmd A pointer that identifies the command. + * @param pServiceLocation Pointer to the service location structure. + * @param pu32ClientID Where to store the client id for the connection. + * @return VBox status code. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnConnect,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, PHGCMSERVICELOCATION pServiceLocation, uint32_t *pu32ClientID)); + + /** + * Disconnect from service. + * + * @param pInterface Pointer to this interface. + * @param pCmd A pointer that identifies the command. + * @param u32ClientID The client id returned by the pfnConnect call. + * @return VBox status code. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnDisconnect,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t u32ClientID)); + + /** + * Process a guest issued command. + * + * @param pInterface Pointer to this interface. + * @param pCmd A pointer that identifies the command. + * @param u32ClientID The client id returned by the pfnConnect call. + * @param u32Function Function to be performed by the service. + * @param cParms Number of parameters in the array pointed to by paParams. + * @param paParms Pointer to an array of parameters. + * @param tsArrival The STAM_GET_TS() value when the request arrived. + * @return VBox status code. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnCall,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t u32ClientID, uint32_t u32Function, + uint32_t cParms, struct VBOXHGCMSVCPARM *paParms, uint64_t tsArrival)); + + /** + * Notification about the guest cancelling a pending request. + * @param pInterface Pointer to this interface. + * @param pCmd A pointer that identifies the command. + * @param idclient The client id returned by the pfnConnect call. + */ + DECLR3CALLBACKMEMBER(void, pfnCancelled,(PPDMIHGCMCONNECTOR pInterface, PVBOXHGCMCMD pCmd, uint32_t idClient)); + +} PDMIHGCMCONNECTOR; +/** PDMIHGCMCONNECTOR interface ID. */ +# define PDMIHGCMCONNECTOR_IID "33cb5c91-6a4a-4ad9-3fec-d1f7d413c4a5" + +#endif /* VBOX_WITH_HGCM */ + + +/** Pointer to a display VBVA callbacks interface. */ +typedef struct PDMIDISPLAYVBVACALLBACKS *PPDMIDISPLAYVBVACALLBACKS; +/** + * Display VBVA callbacks interface (up). + */ +typedef struct PDMIDISPLAYVBVACALLBACKS +{ + + /** + * Informs guest about completion of processing the given Video HW Acceleration + * command, does not wait for the guest to process the command. + * + * @returns ??? + * @param pInterface Pointer to this interface. + * @param pCmd The Video HW Acceleration Command that was + * completed. + */ + DECLR3CALLBACKMEMBER(int, pfnVHWACommandCompleteAsync,(PPDMIDISPLAYVBVACALLBACKS pInterface, + VBOXVHWACMD RT_UNTRUSTED_VOLATILE_GUEST *pCmd)); +} PDMIDISPLAYVBVACALLBACKS; +/** PDMIDISPLAYVBVACALLBACKS */ +#define PDMIDISPLAYVBVACALLBACKS_IID "37f34c9c-0491-47dc-a0b3-81697c44a416" + +/** Pointer to a PCI raw connector interface. */ +typedef struct PDMIPCIRAWCONNECTOR *PPDMIPCIRAWCONNECTOR; +/** + * PCI raw connector interface (up). + */ +typedef struct PDMIPCIRAWCONNECTOR +{ + + /** + * + */ + DECLR3CALLBACKMEMBER(int, pfnDeviceConstructComplete, (PPDMIPCIRAWCONNECTOR pInterface, const char *pcszName, + uint32_t uHostPciAddress, uint32_t uGuestPciAddress, + int rc)); + +} PDMIPCIRAWCONNECTOR; +/** PDMIPCIRAWCONNECTOR interface ID. */ +#define PDMIPCIRAWCONNECTOR_IID "14aa9c6c-8869-4782-9dfc-910071a6aebf" + + +/** Pointer to a VFS connector interface. */ +typedef struct PDMIVFSCONNECTOR *PPDMIVFSCONNECTOR; +/** + * VFS connector interface (up). + */ +typedef struct PDMIVFSCONNECTOR +{ + /** + * Queries the size of the given path. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the path is not available. + * @param pInterface Pointer to this interface. + * @param pszNamespace The namespace for the path (usually driver/device name) or NULL for default namespace. + * @param pszPath The path to query the size for. + * @param pcb Where to store the size of the path in bytes on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQuerySize, (PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath, + uint64_t *pcb)); + + /** + * Reads everything from the given path and stores the data into the supplied buffer. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the path is not available. + * @retval VERR_BUFFER_OVERFLOW if the supplied buffer is too small to read everything. + * @retval VINF_BUFFER_UNDERFLOW if the supplied buffer is too large. + * @param pInterface Pointer to this interface. + * @param pszNamespace The namespace for the path (usually driver/device name) or NULL for default namespace. + * @param pszPath The path to read everything for. + * @param pvBuf Where to store the data. + * @param cbRead How much to read. + */ + DECLR3CALLBACKMEMBER(int, pfnReadAll, (PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath, + void *pvBuf, size_t cbRead)); + + /** + * Writes the supplied data to the given path, overwriting any previously existing data. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param pszNamespace The namespace for the path (usually driver/device name) or NULL for default namespace. + * @param pszPath The path to write everything to. + * @param pvBuf The data to store. + * @param cbWrite How many bytes to write. + */ + DECLR3CALLBACKMEMBER(int, pfnWriteAll, (PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath, + const void *pvBuf, size_t cbWrite)); + + /** + * Deletes the given path. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the path is not available. + * @param pszNamespace The namespace for the path (usually driver/device name) or NULL for default namespace. + * @param pszPath The path to delete. + */ + DECLR3CALLBACKMEMBER(int, pfnDelete, (PPDMIVFSCONNECTOR pInterface, const char *pszNamespace, const char *pszPath)); + + /** @todo Add standard open/read/write/close callbacks when the need arises. */ + +} PDMIVFSCONNECTOR; +/** PDMIVFSCONNECTOR interface ID. */ +#define PDMIVFSCONNECTOR_IID "a1fc51e0-414a-4e78-8388-8053b9dc6521" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmifs_h */ diff --git a/include/VBox/vmm/pdmins.h b/include/VBox/vmm/pdmins.h new file mode 100644 index 00000000..9e50b723 --- /dev/null +++ b/include/VBox/vmm/pdmins.h @@ -0,0 +1,99 @@ +/** @file + * PDM - Pluggable Device Manager, Common Instance Macros. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmins_h +#define VBOX_INCLUDED_vmm_pdmins_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/** @defgroup grp_pdm_ins Common PDM Instance Macros + * @ingroup grp_pdm + * @{ + */ + +/** @def PDMBOTHCBDECL + * Macro for declaring a callback which is static in HC and exported in GC. + */ +#if defined(IN_RC) || defined(IN_RING0) +# ifdef __cplusplus +# define PDMBOTHCBDECL(type) extern "C" DECLEXPORT(type) +# else +# define PDMBOTHCBDECL(type) DECLEXPORT(type) +# endif +#else +# define PDMBOTHCBDECL(type) static DECLCALLBACK(type) +#endif + +/** @def PDMINS_2_DATA + * Gets the shared instance data for a PDM device, USB device, or driver instance. + * @note For devices using PDMDEVINS_2_DATA is highly recommended. + */ +#define PDMINS_2_DATA(pIns, type) ( (type)(pIns)->CTX_SUFF(pvInstanceData) ) + +/** @def PDMINS_2_DATA_CC + * Gets the current context instance data for a PDM device, USB device, or driver instance. + * @note For devices using PDMDEVINS_2_DATA_CC is highly recommended. + */ +#define PDMINS_2_DATA_CC(pIns, type) ( (type)(void *)&(pIns)->achInstanceData[0] ) + +/* @def PDMINS_2_DATA_RC + * Gets the raw-mode context instance data for a PDM device instance. + */ +#define PDMINS_2_DATA_RC(pIns, type) ( (type)(pIns)->CTX_SUFF(pvInstanceDataForRC) ) + + +/** @def PDMINS_2_DATA_RCPTR + * Converts a PDM Device, USB Device, or Driver instance pointer to a RC pointer to the instance data. + * @deprecated + */ +#define PDMINS_2_DATA_RCPTR(pIns) ( (pIns)->pvInstanceDataRC ) + +/** @def PDMINS_2_DATA_R3PTR + * Converts a PDM Device, USB Device, or Driver instance pointer to a HC pointer to the instance data. + * @deprecated + */ +#define PDMINS_2_DATA_R3PTR(pIns) ( (pIns)->pvInstanceDataR3 ) + +/** @def PDMINS_2_DATA_R0PTR + * Converts a PDM Device, USB Device, or Driver instance pointer to a R0 pointer to the instance data. + * @deprecated + */ +#define PDMINS_2_DATA_R0PTR(pIns) ( (pIns)->pvInstanceDataR0 ) + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmins_h */ diff --git a/include/VBox/vmm/pdmnetifs.h b/include/VBox/vmm/pdmnetifs.h new file mode 100644 index 00000000..49e93cb5 --- /dev/null +++ b/include/VBox/vmm/pdmnetifs.h @@ -0,0 +1,456 @@ +/** @file + * PDM - Pluggable Device Manager, Network Interfaces. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmnetifs_h +#define VBOX_INCLUDED_vmm_pdmnetifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_ifs_net PDM Network Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +/** + * PDM scatter/gather buffer. + * + * @todo Promote this to VBox/types.h, VBox/vmm/pdmcommon.h or some such place. + */ +typedef struct PDMSCATTERGATHER +{ + /** Flags. */ + size_t fFlags; + /** The number of bytes used. + * This is cleared on alloc and set by the user. */ + size_t cbUsed; + /** The number of bytes available. + * This is set on alloc and not changed by the user. */ + size_t cbAvailable; + /** Private data member for the allocator side. */ + void *pvAllocator; + /** Private data member for the user side. */ + void *pvUser; + /** The number of segments + * This is set on alloc and not changed by the user. */ + size_t cSegs; + /** Variable sized array of segments. */ + PDMDATASEG aSegs[1]; +} PDMSCATTERGATHER; +/** Pointer to a PDM scatter/gather buffer. */ +typedef PDMSCATTERGATHER *PPDMSCATTERGATHER; +/** Pointer to a PDM scatter/gather buffer pointer. */ +typedef PPDMSCATTERGATHER *PPPDMSCATTERGATHER; + + +/** @name PDMSCATTERGATHER::fFlags + * @{ */ +/** Magic value. */ +#define PDMSCATTERGATHER_FLAGS_MAGIC UINT32_C(0xb1b10000) +/** Magic mask. */ +#define PDMSCATTERGATHER_FLAGS_MAGIC_MASK UINT32_C(0xffff0000) +/** Owned by owner number 1. */ +#define PDMSCATTERGATHER_FLAGS_OWNER_1 UINT32_C(0x00000001) +/** Owned by owner number 2. */ +#define PDMSCATTERGATHER_FLAGS_OWNER_2 UINT32_C(0x00000002) +/** Owned by owner number 3. */ +#define PDMSCATTERGATHER_FLAGS_OWNER_3 UINT32_C(0x00000002) +/** Owner mask. */ +#define PDMSCATTERGATHER_FLAGS_OWNER_MASK UINT32_C(0x00000003) +/** Mask of flags available to general use. + * The parties using the SG must all agree upon how to use these of course. */ +#define PDMSCATTERGATHER_FLAGS_AVL_MASK UINT32_C(0x0000f000) +/** Flags reserved for future use, MBZ. */ +#define PDMSCATTERGATHER_FLAGS_RVD_MASK UINT32_C(0x00000ff8) +/** @} */ + + +/** + * Sets the owner of a scatter/gather buffer. + * + * @param pSgBuf . + * @param uNewOwner The new owner. + */ +DECLINLINE(void) PDMScatterGatherSetOwner(PPDMSCATTERGATHER pSgBuf, uint32_t uNewOwner) +{ + pSgBuf->fFlags = (pSgBuf->fFlags & ~PDMSCATTERGATHER_FLAGS_OWNER_MASK) | uNewOwner; +} + + + +/** Pointer to a network port interface */ +typedef struct PDMINETWORKDOWN *PPDMINETWORKDOWN; +/** + * Network port interface (down). + * Pair with PDMINETWORKUP. + */ +typedef struct PDMINETWORKDOWN +{ + /** + * Wait until there is space for receiving data. We do not care how much space is available + * because pfnReceive() will re-check and notify the guest if necessary. + * + * This function must be called before the pfnRecieve() method is called. + * + * @returns VBox status code. VINF_SUCCESS means there is at least one receive descriptor available. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cMillies Number of milliseconds to wait. 0 means return immediately. + * + * @thread Non-EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnWaitReceiveAvail,(PPDMINETWORKDOWN pInterface, RTMSINTERVAL cMillies)); + + /** + * Receive data from the network. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf The available data. + * @param cb Number of bytes available in the buffer. + * + * @thread Non-EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnReceive,(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb)); + + /** + * Receive data with segmentation context from the network. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf The available data. + * @param cb Number of bytes available in the buffer. + * @param pGso Segmentation context. + * + * @thread Non-EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnReceiveGso,(PPDMINETWORKDOWN pInterface, const void *pvBuf, size_t cb, PCPDMNETWORKGSO pGso)); + + /** + * Do pending transmit work on the leaf driver's XMIT thread. + * + * When a PDMINETWORKUP::pfnBeginTransmit or PDMINETWORKUP::pfnAllocBuf call + * fails with VERR_TRY_AGAIN, the leaf drivers XMIT thread will offer to process + * the upstream device/driver when the the VERR_TRY_AGAIN condition has been + * removed. In some cases the VERR_TRY_AGAIN condition is simply being in an + * inconvenient context and the XMIT thread will start working ASAP. + * + * @param pInterface Pointer to this interface. + * @thread Non-EMT. + */ + DECLR3CALLBACKMEMBER(void, pfnXmitPending,(PPDMINETWORKDOWN pInterface)); + +} PDMINETWORKDOWN; +/** PDMINETWORKDOWN interface ID. */ +#define PDMINETWORKDOWN_IID "52b8cdbb-a087-493b-baa7-81ec3b803e06" + + +/** + * Network link state. + */ +typedef enum PDMNETWORKLINKSTATE +{ + /** Invalid state. */ + PDMNETWORKLINKSTATE_INVALID = 0, + /** The link is up. */ + PDMNETWORKLINKSTATE_UP, + /** The link is down. */ + PDMNETWORKLINKSTATE_DOWN, + /** The link is temporarily down while resuming. */ + PDMNETWORKLINKSTATE_DOWN_RESUME +} PDMNETWORKLINKSTATE; + + +/** Pointer to a network connector interface */ +typedef R3PTRTYPE(struct PDMINETWORKUP *) PPDMINETWORKUPR3; +/** Pointer to a network connector interface, ring-0 context. */ +typedef R0PTRTYPE(struct PDMINETWORKUPR0 *) PPDMINETWORKUPR0; +/** Pointer to a network connector interface, raw-mode context. */ +typedef RCPTRTYPE(struct PDMINETWORKUPRC *) PPDMINETWORKUPRC; +/** Pointer to a current context network connector interface. */ +typedef CTX_SUFF(PPDMINETWORKUP) PPDMINETWORKUP; + +/** + * Network connector interface (up). + * Pair with PDMINETWORKDOWN. + */ +typedef struct PDMINETWORKUP +{ + /** + * Begins a transmit session. + * + * The leaf driver guarantees that there are no concurrent sessions. + * + * @retval VINF_SUCCESS on success. Must always call + * PDMINETWORKUP::pfnEndXmit. + * @retval VERR_TRY_AGAIN if there is already an open transmit session or some + * important resource was unavailable (like buffer space). If it's a + * resources issue, the driver will signal its XMIT thread and have it + * work the device thru the PDMINETWORKDOWN::pfnNotifyBufAvailable + * callback method. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * @param fOnWorkerThread Set if we're being called on a work thread. Clear + * if an EMT. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBeginXmit,(PPDMINETWORKUP pInterface, bool fOnWorkerThread)); + + /** + * Get a send buffer for passing to pfnSendBuf. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_TRY_AGAIN if temporarily out of buffer space. After this + * happens, the driver will call PDMINETWORKDOWN::pfnNotifyBufAvailable + * when this is a buffer of the required size available. + * @retval VERR_NO_MEMORY if really out of buffer space. + * @retval VERR_NET_DOWN if we cannot send anything to the network at this + * point in time. Drop the frame with a xmit error. This is typically + * only seen when pausing the VM since the device keeps the link state, + * but there could of course be races. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * @param cbMin The minimum buffer size. + * @param pGso Pointer to a GSO context (only reference while in + * this call). NULL indicates no segmentation + * offloading. PDMSCATTERGATHER::pvUser is used to + * indicate that a network SG uses GSO, usually by + * pointing to a copy of @a pGso. + * @param ppSgBuf Where to return the buffer. The buffer will be + * owned by the caller, designation owner number 1. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnAllocBuf,(PPDMINETWORKUP pInterface, size_t cbMin, PCPDMNETWORKGSO pGso, + PPPDMSCATTERGATHER ppSgBuf)); + + /** + * Frees an unused buffer. + * + * @retval VINF_SUCCESS on success. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pSgBuf A buffer from PDMINETWORKUP::pfnAllocBuf or + * PDMINETWORKDOWN::pfnNotifyBufAvailable. The buffer + * ownership shall be 1. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnFreeBuf,(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)); + + /** + * Send data to the network. + * + * @retval VINF_SUCCESS on success. + * @retval VERR_NET_DOWN if the NIC is not connected to a network. pSgBuf will + * be freed. + * @retval VERR_NET_NO_BUFFER_SPACE if we're out of resources. pSgBuf will be + * freed. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * @param pSgBuf The buffer containing the data to send. The buffer + * ownership shall be 1. The buffer will always be + * consumed, regardless of the status code. + * + * @param fOnWorkerThread Set if we're being called on a work thread. Clear + * if an EMT. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSendBuf,(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)); + + /** + * Ends a transmit session. + * + * Pairs with successful PDMINETWORKUP::pfnBeginXmit calls. + * + * @param pInterface Pointer to the interface structure containing the + * called function pointer. + * + * @thread Any, but normally EMT or the XMIT thread. + */ + DECLR3CALLBACKMEMBER(void, pfnEndXmit,(PPDMINETWORKUP pInterface)); + + /** + * Set promiscuous mode. + * + * This is called when the promiscuous mode is set. This means that there doesn't have + * to be a mode change when it's called. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fPromiscuous Set if the adaptor is now in promiscuous mode. Clear if it is not. + * @thread EMT ?? + */ + DECLR3CALLBACKMEMBER(void, pfnSetPromiscuousMode,(PPDMINETWORKUP pInterface, bool fPromiscuous)); + + /** + * Notification on link status changes. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmLinkState The new link state. + * @thread EMT ?? + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyLinkChanged,(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)); + + /** @todo Add a callback that informs the driver chain about MAC address changes if we ever implement that. */ + +} PDMINETWORKUP; + +/** Ring-0 edition of PDMINETWORKUP. */ +typedef struct PDMINETWORKUPR0 +{ + /** @copydoc PDMINETWORKUP::pfnBeginXmit */ + DECLR0CALLBACKMEMBER(int, pfnBeginXmit,(PPDMINETWORKUPR0 pInterface, bool fOnWorkerThread)); + /** @copydoc PDMINETWORKUP::pfnAllocBuf */ + DECLR0CALLBACKMEMBER(int, pfnAllocBuf,(PPDMINETWORKUPR0 pInterface, size_t cbMin, PCPDMNETWORKGSO pGso, + PPPDMSCATTERGATHER ppSgBuf)); + /** @copydoc PDMINETWORKUP::pfnFreeBuf */ + DECLR0CALLBACKMEMBER(int, pfnFreeBuf,(PPDMINETWORKUPR0 pInterface, PPDMSCATTERGATHER pSgBuf)); + /** @copydoc PDMINETWORKUP::pfnSendBuf */ + DECLR0CALLBACKMEMBER(int, pfnSendBuf,(PPDMINETWORKUPR0 pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)); + /** @copydoc PDMINETWORKUP::pfnEndXmit */ + DECLR0CALLBACKMEMBER(void, pfnEndXmit,(PPDMINETWORKUPR0 pInterface)); + /** @copydoc PDMINETWORKUP::pfnSetPromiscuousMode */ + DECLR0CALLBACKMEMBER(void, pfnSetPromiscuousMode,(PPDMINETWORKUPR0 pInterface, bool fPromiscuous)); +} PDMINETWORKUPR0; + +/** Raw-mode context edition of PDMINETWORKUP. */ +typedef struct PDMINETWORKUPRC +{ + /** @copydoc PDMINETWORKUP::pfnBeginXmit */ + DECLRCCALLBACKMEMBER(int, pfnBeginXmit,(PPDMINETWORKUPRC pInterface, bool fOnWorkerThread)); + /** @copydoc PDMINETWORKUP::pfnAllocBuf */ + DECLRCCALLBACKMEMBER(int, pfnAllocBuf,(PPDMINETWORKUPRC pInterface, size_t cbMin, PCPDMNETWORKGSO pGso, + PPPDMSCATTERGATHER ppSgBuf)); + /** @copydoc PDMINETWORKUP::pfnFreeBuf */ + DECLRCCALLBACKMEMBER(int, pfnFreeBuf,(PPDMINETWORKUPRC pInterface, PPDMSCATTERGATHER pSgBuf)); + /** @copydoc PDMINETWORKUP::pfnSendBuf */ + DECLRCCALLBACKMEMBER(int, pfnSendBuf,(PPDMINETWORKUPRC pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)); + /** @copydoc PDMINETWORKUP::pfnEndXmit */ + DECLRCCALLBACKMEMBER(void, pfnEndXmit,(PPDMINETWORKUPRC pInterface)); + /** @copydoc PDMINETWORKUP::pfnSetPromiscuousMode */ + DECLRCCALLBACKMEMBER(void, pfnSetPromiscuousMode,(PPDMINETWORKUPRC pInterface, bool fPromiscuous)); +} PDMINETWORKUPRC; + +/** PDMINETWORKUP interface ID. */ +#define PDMINETWORKUP_IID "67e7e7a8-2594-4649-a1e3-7cee680c6083" +/** PDMINETWORKUP interface method names. */ +#define PDMINETWORKUP_SYM_LIST "BeginXmit;AllocBuf;FreeBuf;SendBuf;EndXmit;SetPromiscuousMode" + + +/** Pointer to a network config port interface */ +typedef struct PDMINETWORKCONFIG *PPDMINETWORKCONFIG; +/** + * Network config port interface (main). + * No interface pair. + */ +typedef struct PDMINETWORKCONFIG +{ + /** + * Gets the current Media Access Control (MAC) address. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pMac Where to store the MAC address. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnGetMac,(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)); + + /** + * Gets the new link state. + * + * @returns The current link state. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread EMT + */ + DECLR3CALLBACKMEMBER(PDMNETWORKLINKSTATE, pfnGetLinkState,(PPDMINETWORKCONFIG pInterface)); + + /** + * Sets the new link state. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param enmState The new link state + * @thread EMT + */ + DECLR3CALLBACKMEMBER(int, pfnSetLinkState,(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)); + +} PDMINETWORKCONFIG; +/** PDMINETWORKCONFIG interface ID. */ +#define PDMINETWORKCONFIG_IID "d6d909e8-716d-415d-b109-534e4478ff4e" + + +/** Pointer to a NAT configuration port. */ +typedef struct PDMINETWORKNATCONFIG *PPDMINETWORKNATCONFIG; +/** + * Network config port interface (main). + * No interface pair. + */ +typedef struct PDMINETWORKNATCONFIG +{ + /** + * Inform NAT about the adding/removing redirection rule + * + * @todo D O C U M E N T M E ! + * @todo s/u16/u/g + */ + DECLR3CALLBACKMEMBER(int, pfnRedirectRuleCommand ,(PPDMINETWORKNATCONFIG pInterface, bool fRemove, + bool fUdp, const char *pHostIp, uint16_t u16HostPort, + const char *pGuestIp, uint16_t u16GuestPort)); + /** + * Inform NAT about host DNS settings change. + * + * IHostNameResolutionConfigurationChangeEvent. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyDnsChanged, (PPDMINETWORKNATCONFIG pInterface)); + +} PDMINETWORKNATCONFIG; +/** PDMINETWORKNATCONFIG interface ID. */ +#define PDMINETWORKNATCONFIG_IID "dc961028-3523-4b52-a93b-e38168a4a9fa" +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmnetifs_h */ + diff --git a/include/VBox/vmm/pdmnetinline.h b/include/VBox/vmm/pdmnetinline.h new file mode 100644 index 00000000..0acd5fb9 --- /dev/null +++ b/include/VBox/vmm/pdmnetinline.h @@ -0,0 +1,724 @@ +/** @file + * PDM - Networking Helpers, Inlined Code. (DEV,++) + * + * This is all inlined because it's too tedious to create 2-3 libraries to + * contain it all (same bad excuse as for intnetinline.h). + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmnetinline_h +#define VBOX_INCLUDED_vmm_pdmnetinline_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +/******************************************************************************* +* Header Files * +*******************************************************************************/ +#include +#include +#include +#include +#include +#include + + +/** @defgroup grp_pdm_net_inline The PDM Networking Helper APIs + * @ingroup grp_pdm + * @{ + */ + + +/** + * Checksum type. + */ +typedef enum PDMNETCSUMTYPE +{ + /** No checksum. */ + PDMNETCSUMTYPE_NONE = 0, + /** Normal TCP checksum. */ + PDMNETCSUMTYPE_COMPLETE, + /** Checksum on pseudo header (used with GSO). */ + PDMNETCSUMTYPE_PSEUDO, + /** The usual 32-bit hack. */ + PDMNETCSUMTYPE_32_BIT_HACK = 0x7fffffff +} PDMNETCSUMTYPE; + + +/** + * Validates the GSO context. + * + * @returns true if valid, false if not (not asserted or logged). + * @param pGso The GSO context. + * @param cbGsoMax The max size of the GSO context. + * @param cbFrame The max size of the GSO frame (use to validate + * the MSS). + */ +DECLINLINE(bool) PDMNetGsoIsValid(PCPDMNETWORKGSO pGso, size_t cbGsoMax, size_t cbFrame) +{ +#define CHECK_COND_RETURN_FALSE(expr) if (RT_LIKELY(expr)) { /* likely */ } else return false + PDMNETWORKGSOTYPE enmType; + + CHECK_COND_RETURN_FALSE(cbGsoMax >= sizeof(*pGso)); + + enmType = (PDMNETWORKGSOTYPE)pGso->u8Type; + CHECK_COND_RETURN_FALSE(enmType > PDMNETWORKGSOTYPE_INVALID && enmType < PDMNETWORKGSOTYPE_END); + + /* all types requires both headers. */ + CHECK_COND_RETURN_FALSE(pGso->offHdr1 >= sizeof(RTNETETHERHDR)); + CHECK_COND_RETURN_FALSE(pGso->offHdr2 > pGso->offHdr1); + CHECK_COND_RETURN_FALSE(pGso->cbHdrsTotal > pGso->offHdr2); + + /* min size of the 1st header(s). */ + switch (enmType) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + case PDMNETWORKGSOTYPE_IPV4_UDP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->offHdr2 - pGso->offHdr1 >= RTNETIPV4_MIN_LEN); + break; + case PDMNETWORKGSOTYPE_IPV6_TCP: + case PDMNETWORKGSOTYPE_IPV6_UDP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->offHdr2 - pGso->offHdr1 >= RTNETIPV6_MIN_LEN); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->offHdr2 - pGso->offHdr1 >= RTNETIPV4_MIN_LEN + RTNETIPV6_MIN_LEN); + break; + /* These two have been rejected above already, but we need to include them to avoid gcc warnings. */ + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + break; + /* No default case! Want gcc warnings. */ + } + + /* min size of the 2nd header. */ + switch (enmType) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + case PDMNETWORKGSOTYPE_IPV6_TCP: + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->cbHdrsTotal - pGso->offHdr2 >= RTNETTCP_MIN_LEN); + break; + case PDMNETWORKGSOTYPE_IPV4_UDP: + case PDMNETWORKGSOTYPE_IPV6_UDP: + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + CHECK_COND_RETURN_FALSE((unsigned)pGso->cbHdrsTotal - pGso->offHdr2 >= RTNETUDP_MIN_LEN); + break; + /* These two have been rejected above already, but we need to include them to avoid gcc warnings. */ + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + break; + /* No default case! Want gcc warnings. */ + } + + /* There must be at more than one segment. */ + CHECK_COND_RETURN_FALSE(cbFrame > pGso->cbHdrsTotal); + CHECK_COND_RETURN_FALSE(cbFrame - pGso->cbHdrsTotal >= pGso->cbMaxSeg); + + /* Make sure the segment size is enough to fit a UDP header. */ + CHECK_COND_RETURN_FALSE(enmType != PDMNETWORKGSOTYPE_IPV4_UDP || pGso->cbMaxSeg >= RTNETUDP_MIN_LEN); + + /* Make sure the segment size is not zero. */ + CHECK_COND_RETURN_FALSE(pGso->cbMaxSeg > 0); + + return true; +#undef CHECK_COND_RETURN_FALSE +} + + +/** + * Returns the length of header for a particular segment/fragment. + * + * We cannot simply treat UDP header as a part of payload because we do not + * want to modify the payload but still need to modify the checksum field in + * UDP header. So we want to include UDP header when calculating the length + * of headers in the first segment getting it copied to a temporary buffer + * along with other headers. + * + * @returns Length of headers (including UDP header for the first fragment). + * @param pGso The GSO context. + * @param iSeg The segment index. + */ +DECLINLINE(uint8_t) pdmNetSegHdrLen(PCPDMNETWORKGSO pGso, uint32_t iSeg) +{ + return iSeg ? pGso->cbHdrsSeg : pGso->cbHdrsTotal; +} + +/** + * Returns the length of payload for a particular segment/fragment. + * + * The first segment does not contain UDP header. The size of UDP header is + * determined as the difference between the total headers size and the size + * used during segmentation. + * + * @returns Length of payload (including UDP header for the first fragment). + * @param pGso The GSO context. + * @param iSeg The segment that we're carving out (0-based). + * @param cSegs The number of segments in the GSO frame. + * @param cbFrame The size of the GSO frame. + */ +DECLINLINE(uint32_t) pdmNetSegPayloadLen(PCPDMNETWORKGSO pGso, uint32_t iSeg, uint32_t cSegs, uint32_t cbFrame) +{ + if (iSeg + 1 == cSegs) + return cbFrame - iSeg * pGso->cbMaxSeg - pdmNetSegHdrLen(pGso, iSeg); + return pGso->cbMaxSeg - (iSeg ? 0 : pGso->cbHdrsTotal - pGso->cbHdrsSeg); +} + +/** + * Calculates the number of segments a GSO frame will be segmented into. + * + * @returns Segment count. + * @param pGso The GSO context. + * @param cbFrame The GSO frame size (header proto + payload). + */ +DECLINLINE(uint32_t) PDMNetGsoCalcSegmentCount(PCPDMNETWORKGSO pGso, size_t cbFrame) +{ + size_t cbPayload; + Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame)); + cbPayload = cbFrame - pGso->cbHdrsSeg; + return (uint32_t)((cbPayload + pGso->cbMaxSeg - 1) / pGso->cbMaxSeg); +} + + +/** + * Used to find the IPv6 header when handling 4to6 tunneling. + * + * @returns Offset of the IPv6 header. + * @param pbSegHdrs The headers / frame start. + * @param offIPv4Hdr The offset of the IPv4 header. + */ +DECLINLINE(uint8_t) pgmNetGsoCalcIpv6Offset(uint8_t *pbSegHdrs, uint8_t offIPv4Hdr) +{ + PCRTNETIPV4 pIPv4Hdr = (PCRTNETIPV4)&pbSegHdrs[offIPv4Hdr]; + return offIPv4Hdr + pIPv4Hdr->ip_hl * 4; +} + + +/** + * Update an UDP header after carving out a segment + * + * @param u32PseudoSum The pseudo checksum. + * @param pbSegHdrs Pointer to the header bytes / frame start. + * @param offUdpHdr The offset into @a pbSegHdrs of the UDP header. + * @param pbPayload Pointer to the payload bytes. + * @param cbPayload The amount of payload. + * @param cbHdrs The size of all the headers. + * @param enmCsumType Whether to checksum the payload, the pseudo + * header or nothing. + * @internal + */ +DECLINLINE(void) pdmNetGsoUpdateUdpHdr(uint32_t u32PseudoSum, uint8_t *pbSegHdrs, uint8_t offUdpHdr, + uint8_t const *pbPayload, uint32_t cbPayload, uint8_t cbHdrs, + PDMNETCSUMTYPE enmCsumType) +{ + PRTNETUDP pUdpHdr = (PRTNETUDP)&pbSegHdrs[offUdpHdr]; + pUdpHdr->uh_ulen = RT_H2N_U16(cbPayload + cbHdrs - offUdpHdr); + switch (enmCsumType) + { + case PDMNETCSUMTYPE_NONE: + pUdpHdr->uh_sum = 0; + break; + case PDMNETCSUMTYPE_COMPLETE: + pUdpHdr->uh_sum = RTNetUDPChecksum(u32PseudoSum, pUdpHdr); + break; + case PDMNETCSUMTYPE_PSEUDO: + pUdpHdr->uh_sum = ~RTNetIPv4FinalizeChecksum(u32PseudoSum); + break; + default: + NOREF(pbPayload); + AssertFailed(); + break; + } +} + + +/** + * Update an UDP header after carving out an IP fragment + * + * @param u32PseudoSum The pseudo checksum. + * @param pbSegHdrs Pointer to the header bytes copy + * @param pbFrame Pointer to the frame start. + * @param offUdpHdr The offset into @a pbSegHdrs of the UDP header. + * + * @internal + */ +DECLINLINE(void) pdmNetGsoUpdateUdpHdrUfo(uint32_t u32PseudoSum, uint8_t *pbSegHdrs, const uint8_t *pbFrame, uint8_t offUdpHdr) +{ + PCRTNETUDP pcUdpHdrOrig = (PCRTNETUDP)&pbFrame[offUdpHdr]; + PRTNETUDP pUdpHdr = (PRTNETUDP)&pbSegHdrs[offUdpHdr]; + pUdpHdr->uh_sum = RTNetUDPChecksum(u32PseudoSum, pcUdpHdrOrig); +} + + +/** + * Update a TCP header after carving out a segment. + * + * @param u32PseudoSum The pseudo checksum. + * @param pbSegHdrs Pointer to the header bytes / frame start. + * @param offTcpHdr The offset into @a pbSegHdrs of the TCP header. + * @param pbPayload Pointer to the payload bytes. + * @param cbPayload The amount of payload. + * @param offPayload The offset into the payload that we're splitting + * up. We're ASSUMING that the payload follows + * immediately after the TCP header w/ options. + * @param cbHdrs The size of all the headers. + * @param fLastSeg Set if this is the last segment. + * @param enmCsumType Whether to checksum the payload, the pseudo + * header or nothing. + * @internal + */ +DECLINLINE(void) pdmNetGsoUpdateTcpHdr(uint32_t u32PseudoSum, uint8_t *pbSegHdrs, uint8_t offTcpHdr, + uint8_t const *pbPayload, uint32_t cbPayload, uint32_t offPayload, uint8_t cbHdrs, + bool fLastSeg, PDMNETCSUMTYPE enmCsumType) +{ + PRTNETTCP pTcpHdr = (PRTNETTCP)&pbSegHdrs[offTcpHdr]; + pTcpHdr->th_seq = RT_H2N_U32(RT_N2H_U32(pTcpHdr->th_seq) + offPayload); + if (!fLastSeg) + pTcpHdr->th_flags &= ~(RTNETTCP_F_FIN | RTNETTCP_F_PSH); + switch (enmCsumType) + { + case PDMNETCSUMTYPE_NONE: + pTcpHdr->th_sum = 0; + break; + case PDMNETCSUMTYPE_COMPLETE: + pTcpHdr->th_sum = RTNetTCPChecksum(u32PseudoSum, pTcpHdr, pbPayload, cbPayload); + break; + case PDMNETCSUMTYPE_PSEUDO: + pTcpHdr->th_sum = ~RTNetIPv4FinalizeChecksum(u32PseudoSum); + break; + default: + NOREF(cbHdrs); + AssertFailed(); + break; + } +} + + +/** + * Updates a IPv6 header after carving out a segment. + * + * @returns 32-bit intermediary checksum value for the pseudo header. + * @param pbSegHdrs Pointer to the header bytes. + * @param offIpHdr The offset into @a pbSegHdrs of the IP header. + * @param cbSegPayload The amount of segmented payload. Not to be + * confused with the IP payload. + * @param cbHdrs The size of all the headers. + * @param offPktHdr Offset of the protocol packet header. For the + * pseudo header checksum calulation. + * @param bProtocol The protocol type. For the pseudo header. + * @internal + */ +DECLINLINE(uint32_t) pdmNetGsoUpdateIPv6Hdr(uint8_t *pbSegHdrs, uint8_t offIpHdr, uint32_t cbSegPayload, uint8_t cbHdrs, + uint8_t offPktHdr, uint8_t bProtocol) +{ + PRTNETIPV6 pIpHdr = (PRTNETIPV6)&pbSegHdrs[offIpHdr]; + uint16_t cbPayload = (uint16_t)(cbHdrs - (offIpHdr + sizeof(RTNETIPV6)) + cbSegPayload); + pIpHdr->ip6_plen = RT_H2N_U16(cbPayload); + return RTNetIPv6PseudoChecksumEx(pIpHdr, bProtocol, (uint16_t)(cbHdrs - offPktHdr + cbSegPayload)); +} + + +/** + * Updates a IPv4 header after carving out a segment. + * + * @returns 32-bit intermediary checksum value for the pseudo header. + * @param pbSegHdrs Pointer to the header bytes. + * @param offIpHdr The offset into @a pbSegHdrs of the IP header. + * @param cbSegPayload The amount of segmented payload. + * @param iSeg The segment index. + * @param cbHdrs The size of all the headers. + * @internal + */ +DECLINLINE(uint32_t) pdmNetGsoUpdateIPv4Hdr(uint8_t *pbSegHdrs, uint8_t offIpHdr, uint32_t cbSegPayload, + uint32_t iSeg, uint8_t cbHdrs) +{ + PRTNETIPV4 pIpHdr = (PRTNETIPV4)&pbSegHdrs[offIpHdr]; + pIpHdr->ip_len = RT_H2N_U16(cbHdrs - offIpHdr + cbSegPayload); + pIpHdr->ip_id = RT_H2N_U16(RT_N2H_U16(pIpHdr->ip_id) + iSeg); + pIpHdr->ip_sum = RTNetIPv4HdrChecksum(pIpHdr); + return RTNetIPv4PseudoChecksum(pIpHdr); +} + + +/** + * Updates a IPv4 header after carving out an IP fragment. + * + * @param pbSegHdrs Pointer to the header bytes. + * @param offIpHdr The offset into @a pbSegHdrs of the IP header. + * @param cbSegPayload The amount of segmented payload. + * @param offFragment The offset of this fragment for reassembly. + * @param cbHdrs The size of all the headers. + * @param fLastFragment True if this is the last fragment of datagram. + * @internal + */ +DECLINLINE(void) pdmNetGsoUpdateIPv4HdrUfo(uint8_t *pbSegHdrs, uint8_t offIpHdr, uint32_t cbSegPayload, + uint32_t offFragment, uint8_t cbHdrs, bool fLastFragment) +{ + PRTNETIPV4 pIpHdr = (PRTNETIPV4)&pbSegHdrs[offIpHdr]; + pIpHdr->ip_len = RT_H2N_U16(cbHdrs - offIpHdr + cbSegPayload); + pIpHdr->ip_off = RT_H2N_U16((offFragment / 8) | (fLastFragment ? 0 : RTNETIPV4_FLAGS_MF)); + pIpHdr->ip_sum = RTNetIPv4HdrChecksum(pIpHdr); +} + + +/** + * Carves out the specified segment in a destructive manner. + * + * This is for sequentially carving out segments and pushing them along for + * processing or sending. To avoid allocating a temporary buffer for + * constructing the segment in, we trash the previous frame by putting the + * header at the end of it. + * + * @returns Pointer to the segment frame that we've carved out. + * @param pGso The GSO context data. + * @param pbFrame Pointer to the GSO frame. + * @param cbFrame The size of the GSO frame. + * @param pbHdrScatch Pointer to a pGso->cbHdrs sized area where we + * can save the original header prototypes on the + * first call (@a iSeg is 0) and retrieve it on + * susequent calls. (Just use a 256 bytes + * buffer to make life easy.) + * @param iSeg The segment that we're carving out (0-based). + * @param cSegs The number of segments in the GSO frame. Use + * PDMNetGsoCalcSegmentCount to find this. + * @param pcbSegFrame Where to return the size of the returned segment + * frame. + */ +DECLINLINE(void *) PDMNetGsoCarveSegmentQD(PCPDMNETWORKGSO pGso, uint8_t *pbFrame, size_t cbFrame, uint8_t *pbHdrScatch, + uint32_t iSeg, uint32_t cSegs, uint32_t *pcbSegFrame) +{ + /* + * Figure out where the payload is and where the header starts before we + * do the protocol specific carving. + * + * UDP GSO uses IPv4 fragmentation, meaning that UDP header is present in + * the first fragment only. When computing the total frame size of the + * first fragment we need to use PDMNETWORKGSO::cbHdrsTotal instead of + * PDMNETWORKGSO::cbHdrsSeg. In case of TCP GSO both cbHdrsTotal and + * cbHdrsSeg have the same value, so it will work as well. + */ + uint8_t * const pbSegHdrs = pbFrame + pGso->cbMaxSeg * iSeg; + uint8_t * const pbSegPayload = pbSegHdrs + pGso->cbHdrsSeg; + uint32_t const cbSegPayload = pdmNetSegPayloadLen(pGso, iSeg, cSegs, (uint32_t)cbFrame); + uint32_t const cbSegFrame = cbSegPayload + (iSeg ? pGso->cbHdrsSeg : pGso->cbHdrsTotal); + + /* + * Check assumptions (doing it after declaring the variables because of C). + */ + Assert(iSeg < cSegs); + Assert(cSegs == PDMNetGsoCalcSegmentCount(pGso, cbFrame)); + Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame)); + + /* + * Copy the header and do the protocol specific massaging of it. + */ + if (iSeg != 0) + memcpy(pbSegHdrs, pbHdrScatch, pGso->cbHdrsSeg); + else + memcpy(pbHdrScatch, pbSegHdrs, pGso->cbHdrsSeg); /* There is no need to save UDP header */ + + switch ((PDMNETWORKGSOTYPE)pGso->u8Type) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrsSeg), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + pGso->cbHdrsSeg, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_UDP: + if (iSeg == 0) + { + /* uh_ulen shall not exceed cbFrame - pGso->offHdr2 (offset of UDP header) */ + PRTNETUDP pUdpHdr = (PRTNETUDP)&pbFrame[pGso->offHdr2]; + Assert(pGso->offHdr2 + RT_UOFFSET_AFTER(RTNETUDP, uh_ulen) <= cbFrame); + if ((unsigned)(pGso->offHdr2 + RT_BE2H_U16(pUdpHdr->uh_ulen)) > cbFrame) + { + size_t cbUdp = cbFrame - pGso->offHdr2; + if (cbUdp >= UINT16_MAX) + pUdpHdr->uh_ulen = UINT16_MAX; + else + pUdpHdr->uh_ulen = RT_H2BE_U16((uint16_t)cbUdp); + } + /* uh_ulen shall be at least the size of UDP header */ + if (RT_BE2H_U16(pUdpHdr->uh_ulen) < sizeof(RTNETUDP)) + pUdpHdr->uh_ulen = RT_H2BE_U16(sizeof(RTNETUDP)); + pdmNetGsoUpdateUdpHdrUfo(RTNetIPv4PseudoChecksum((PRTNETIPV4)&pbFrame[pGso->offHdr1]), + pbSegHdrs, pbFrame, pGso->offHdr2); + } + pdmNetGsoUpdateIPv4HdrUfo(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg * pGso->cbMaxSeg, + pdmNetSegHdrLen(pGso, iSeg), iSeg + 1 == cSegs); + break; + case PDMNETWORKGSOTYPE_IPV6_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrsSeg, + pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + pGso->cbHdrsSeg, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV6_UDP: + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, pGso->cbHdrsSeg, + pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrsSeg, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrsSeg); + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1), + cbSegPayload, pGso->cbHdrsSeg, pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + pGso->cbHdrsSeg, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, pGso->cbHdrsSeg); + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1), + cbSegPayload, pGso->cbHdrsSeg, pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, pGso->cbHdrsSeg, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + /* no default! wnat gcc warnings. */ + break; + } + + *pcbSegFrame = cbSegFrame; + return pbSegHdrs; +} + + +/** + * Carves out the specified segment in a non-destructive manner. + * + * The segment headers and segment payload is kept separate here. The GSO frame + * is still expected to be one linear chunk of data, but we don't modify any of + * it. + * + * @returns The offset into the GSO frame of the payload. + * @param pGso The GSO context data. + * @param pbFrame Pointer to the GSO frame. Used for retrieving + * the header prototype and for checksumming the + * payload. The buffer is not modified. + * @param cbFrame The size of the GSO frame. + * @param iSeg The segment that we're carving out (0-based). + * @param cSegs The number of segments in the GSO frame. Use + * PDMNetGsoCalcSegmentCount to find this. + * @param pbSegHdrs Where to return the headers for the segment + * that's been carved out. The buffer must be at + * least pGso->cbHdrs in size, using a 256 byte + * buffer is a recommended simplification. + * @param pcbSegHdrs Where to return the size of the returned + * segment headers. + * @param pcbSegPayload Where to return the size of the returned + * segment payload. + */ +DECLINLINE(uint32_t) PDMNetGsoCarveSegment(PCPDMNETWORKGSO pGso, const uint8_t *pbFrame, size_t cbFrame, + uint32_t iSeg, uint32_t cSegs, uint8_t *pbSegHdrs, + uint32_t *pcbSegHdrs, uint32_t *pcbSegPayload) +{ + /* + * Figure out where the payload is and where the header starts before we + * do the protocol specific carving. + */ + uint32_t const cbSegHdrs = pdmNetSegHdrLen(pGso, iSeg); + uint8_t const * const pbSegPayload = pbFrame + cbSegHdrs + iSeg * pGso->cbMaxSeg; + uint32_t const cbSegPayload = pdmNetSegPayloadLen(pGso, iSeg, cSegs, (uint32_t)cbFrame); + + /* + * Check assumptions (doing it after declaring the variables because of C). + */ + Assert(iSeg < cSegs); + Assert(cSegs == PDMNetGsoCalcSegmentCount(pGso, cbFrame)); + Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame)); + + /* + * Copy the header and do the protocol specific massaging of it. + */ + memcpy(pbSegHdrs, pbFrame, pGso->cbHdrsTotal); /* include UDP header */ + + switch ((PDMNETWORKGSOTYPE)pGso->u8Type) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, cbSegHdrs), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + cbSegHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_UDP: + if (iSeg == 0) + { + /* uh_ulen shall not exceed cbFrame - pGso->offHdr2 (offset of UDP header) */ + PRTNETUDP pUdpHdr = (PRTNETUDP)&pbFrame[pGso->offHdr2]; + Assert(pGso->offHdr2 + RT_UOFFSET_AFTER(RTNETUDP, uh_ulen) <= cbFrame); + if ((unsigned)(pGso->offHdr2 + RT_BE2H_U16(pUdpHdr->uh_ulen)) > cbFrame) + { + size_t cbUdp = cbFrame - pGso->offHdr2; + if (cbUdp >= UINT16_MAX) + pUdpHdr->uh_ulen = UINT16_MAX; + else + pUdpHdr->uh_ulen = RT_H2BE_U16((uint16_t)cbUdp); + } + /* uh_ulen shall be at least the size of UDP header */ + if (RT_BE2H_U16(pUdpHdr->uh_ulen) < sizeof(RTNETUDP)) + pUdpHdr->uh_ulen = RT_H2BE_U16(sizeof(RTNETUDP)); + pdmNetGsoUpdateUdpHdrUfo(RTNetIPv4PseudoChecksum((PRTNETIPV4)&pbFrame[pGso->offHdr1]), + pbSegHdrs, pbFrame, pGso->offHdr2); + } + pdmNetGsoUpdateIPv4HdrUfo(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg * pGso->cbMaxSeg, + cbSegHdrs, iSeg + 1 == cSegs); + break; + case PDMNETWORKGSOTYPE_IPV6_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, cbSegHdrs, + pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + cbSegHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV6_UDP: + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, cbSegHdrs, + pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, cbSegHdrs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, cbSegHdrs); + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1), + cbSegPayload, cbSegHdrs, pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, iSeg * pGso->cbMaxSeg, + cbSegHdrs, iSeg + 1 == cSegs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + pdmNetGsoUpdateIPv4Hdr(pbSegHdrs, pGso->offHdr1, cbSegPayload, iSeg, cbSegHdrs); + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbSegHdrs, pgmNetGsoCalcIpv6Offset(pbSegHdrs, pGso->offHdr1), + cbSegPayload, cbSegHdrs, pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbSegHdrs, pGso->offHdr2, pbSegPayload, cbSegPayload, cbSegHdrs, PDMNETCSUMTYPE_COMPLETE); + break; + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + /* no default! wnat gcc warnings. */ + break; + } + + *pcbSegHdrs = cbSegHdrs; + *pcbSegPayload = cbSegPayload; + return cbSegHdrs + iSeg * pGso->cbMaxSeg; +} + + +/** + * Prepares the GSO frame for direct use without any segmenting. + * + * @param pGso The GSO context. + * @param pvFrame The frame to prepare. + * @param cbFrame The frame size. + * @param enmCsumType Whether to checksum the payload, the pseudo + * header or nothing. + */ +DECLINLINE(void) PDMNetGsoPrepForDirectUse(PCPDMNETWORKGSO pGso, void *pvFrame, size_t cbFrame, PDMNETCSUMTYPE enmCsumType) +{ + /* + * Figure out where the payload is and where the header starts before we + * do the protocol bits. + */ + uint8_t * const pbHdrs = (uint8_t *)pvFrame; + uint8_t * const pbPayload = pbHdrs + pGso->cbHdrsTotal; + uint32_t const cbFrame32 = (uint32_t)cbFrame; + uint32_t const cbPayload = cbFrame32 - pGso->cbHdrsTotal; + + /* + * Check assumptions (doing it after declaring the variables because of C). + */ + Assert(PDMNetGsoIsValid(pGso, sizeof(*pGso), cbFrame)); + + /* + * Get down to busienss. + */ + switch ((PDMNETWORKGSOTYPE)pGso->u8Type) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbFrame32 - pGso->cbHdrsTotal, 0, pGso->cbHdrsTotal), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, 0, pGso->cbHdrsTotal, true, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV4_UDP: + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbFrame32 - pGso->cbHdrsTotal, 0, pGso->cbHdrsTotal), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, pGso->cbHdrsTotal, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV6_TCP: + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pGso->offHdr1, cbPayload, pGso->cbHdrsTotal, + pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, 0, pGso->cbHdrsTotal, true, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV6_UDP: + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pGso->offHdr1, cbPayload, pGso->cbHdrsTotal, + pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, pGso->cbHdrsTotal, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: + pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbPayload, 0, pGso->cbHdrsTotal); + pdmNetGsoUpdateTcpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pgmNetGsoCalcIpv6Offset(pbHdrs, pGso->offHdr1), + cbPayload, pGso->cbHdrsTotal, pGso->offHdr2, RTNETIPV4_PROT_TCP), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, 0, pGso->cbHdrsTotal, true, enmCsumType); + break; + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: + pdmNetGsoUpdateIPv4Hdr(pbHdrs, pGso->offHdr1, cbPayload, 0, pGso->cbHdrsTotal); + pdmNetGsoUpdateUdpHdr(pdmNetGsoUpdateIPv6Hdr(pbHdrs, pgmNetGsoCalcIpv6Offset(pbHdrs, pGso->offHdr1), + cbPayload, pGso->cbHdrsTotal, pGso->offHdr2, RTNETIPV4_PROT_UDP), + pbHdrs, pGso->offHdr2, pbPayload, cbPayload, pGso->cbHdrsTotal, enmCsumType); + break; + case PDMNETWORKGSOTYPE_INVALID: + case PDMNETWORKGSOTYPE_END: + /* no default! wnat gcc warnings. */ + break; + } +} + + +/** + * Gets the GSO type name string. + * + * @returns Pointer to read only name string. + * @param enmType The type. + */ +DECLINLINE(const char *) PDMNetGsoTypeName(PDMNETWORKGSOTYPE enmType) +{ + switch (enmType) + { + case PDMNETWORKGSOTYPE_IPV4_TCP: return "TCPv4"; + case PDMNETWORKGSOTYPE_IPV6_TCP: return "TCPv6"; + case PDMNETWORKGSOTYPE_IPV4_UDP: return "UDPv4"; + case PDMNETWORKGSOTYPE_IPV6_UDP: return "UDPv6"; + case PDMNETWORKGSOTYPE_IPV4_IPV6_TCP: return "4to6TCP"; + case PDMNETWORKGSOTYPE_IPV4_IPV6_UDP: return "4to6UDP"; + case PDMNETWORKGSOTYPE_INVALID: return "invalid"; + case PDMNETWORKGSOTYPE_END: return "end"; + } + return "bad-gso-type"; +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmnetinline_h */ + diff --git a/include/VBox/vmm/pdmnetshaper.h b/include/VBox/vmm/pdmnetshaper.h new file mode 100644 index 00000000..dc6932bd --- /dev/null +++ b/include/VBox/vmm/pdmnetshaper.h @@ -0,0 +1,93 @@ +/** @file + * PDM - Pluggable Device Manager, Network Shaper. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmnetshaper_h +#define VBOX_INCLUDED_vmm_pdmnetshaper_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +/** @defgroup grp_pdm_net_shaper The PDM Network Shaper API + * @ingroup grp_pdm + * @{ + */ + + +#define PDM_NETSHAPER_MIN_BUCKET_SIZE UINT32_C(65536) /**< bytes */ +#define PDM_NETSHAPER_MAX_LATENCY UINT32_C(100) /**< milliseconds */ + +RT_C_DECLS_BEGIN + +/** + * A network shaper filter entry. + * + * This is used by DrvNetShaper and any similar drivers. + */ +typedef struct PDMNSFILTER +{ + /** Entry in the group's filter list. + * Both members are NULL when not associated with a group. */ + RTLISTNODER3 ListEntry; + /** The group index + 1. + * @note For safety reasons the value zero is invalid and this is 1-based + * (like pascal) rather than 0-based indexing. + * @note Volatile to prevent re-reading after validation. */ + uint32_t volatile iGroup; + /** Set when the filter fails to obtain bandwidth. + * This will then cause pIDrvNetR3 to be called before long. */ + bool fChoked; + /** Aligment padding. */ + bool afPadding[3]; + /** The driver this filter is aggregated into (ring-3). */ + R3PTRTYPE(PPDMINETWORKDOWN) pIDrvNetR3; +} PDMNSFILTER; + +VMM_INT_DECL(bool) PDMNetShaperAllocateBandwidth(PVMCC pVM, PPDMNSFILTER pFilter, size_t cbTransfer); +VMMR3_INT_DECL(int) PDMR3NsAttach(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, PPDMNSFILTER pFilter); +VMMR3_INT_DECL(int) PDMR3NsDetach(PVM pVM, PPDMDRVINS pDrvIns, PPDMNSFILTER pFilter); +VMMR3DECL(int) PDMR3NsBwGroupSetLimit(PUVM pUVM, const char *pszName, uint64_t cbPerSecMax); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmnetshaper_h */ + diff --git a/include/VBox/vmm/pdmpci.h b/include/VBox/vmm/pdmpci.h new file mode 100644 index 00000000..61493eb8 --- /dev/null +++ b/include/VBox/vmm/pdmpci.h @@ -0,0 +1,408 @@ +/** @file + * PDM - Pluggable Device Manager, raw PCI Devices. (VMM) + */ + +/* + * Copyright (C) 2010-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmpci_h +#define VBOX_INCLUDED_vmm_pdmpci_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_pciraw The raw PCI Devices API + * @ingroup grp_pdm + * @{ + */ + +typedef struct PDMIPCIRAW *PPDMIPCIRAW; +typedef struct PDMIPCIRAW +{ + /** + * Notify virtual device that interrupt has arrived. + * For this callback to be called, interface have to be + * registered with PDMIPCIRAWUP::pfnRegisterInterruptListener. + * + * @note no level parameter, as we can only support flip-flop. + * + * @param pInterface Pointer to this interface structure. + * @param iGuestIrq Guest interrupt number, passed earlier when registering listener. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnInterruptRequest,(PPDMIPCIRAW pInterface, int32_t iGuestIrq)); +} PDMIPCIRAW; + +typedef struct PDMIPCIRAWUP *PPDMIPCIRAWUP; +typedef struct PDMIPCIRAWUP +{ + /** + * Host PCI MMIO access function. + */ + + /** + * Request driver info about PCI region on host PCI device. + * + * @returns true, if region is present, and out parameters are correct + * @param pInterface Pointer to this interface structure. + * @param iRegion Region number. + * @param pGCPhysRegion Where to store region base address (guest). + * @param pcbRegion Where to store region size. + * + * @param pfFlags If region is MMIO or IO. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnGetRegionInfo, (PPDMIPCIRAWUP pInterface, + uint32_t iRegion, + RTGCPHYS *pGCPhysRegion, + uint64_t *pcbRegion, + uint32_t *pfFlags)); + + /** + * Request driver to map part of host device's MMIO region to the VM process and maybe kernel. + * Shall only be issued within earlier obtained with pfnGetRegionInfo() + * host physical address ranges for the device BARs. Even if failed, device still may function + * using pfnMmio* and pfnPio* operations, just much slower. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param iRegion Number of the region. + * @param StartAddress Host physical address of start. + * @param cbRegion Size of the region. + * @param fFlags Flags, currently lowest significant bit set if R0 mapping requested too + * @param ppvAddressR3 Where to store mapped region address for R3 (can be 0, if cannot map into userland) + * @param ppvAddressR0 Where to store mapped region address for R0 (can be 0, if cannot map into kernel) + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMapRegion, (PPDMIPCIRAWUP pInterface, + uint32_t iRegion, + RTHCPHYS StartAddress, + uint64_t cbRegion, + uint32_t fFlags, + PRTR3PTR ppvAddressR3, + PRTR0PTR ppvAddressR0)); + + /** + * Request driver to unmap part of host device's MMIO region to the VM process. + * Shall only be issued with pointer earlier obtained with pfnMapRegion(). + * + * @returns status code + * @param pInterface Pointer to this interface structure + * @param iRegion Number of the region. + * @param StartAddress Host physical address of start. + * @param cbRegion Size of the region. + * @param pvAddressR3 R3 address of mapped region. + * @param pvAddressR0 R0 address of mapped region. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnUnmapRegion, (PPDMIPCIRAWUP pInterface, + uint32_t iRegion, + RTHCPHYS StartAddress, + uint64_t cbRegion, + RTR3PTR pvAddressR3, + RTR0PTR pvAddressR0)); + + /** + * Request port IO write. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param uPort I/O port address. + * @param uValue Value to write. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPioWrite, (PPDMIPCIRAWUP pInterface, + RTIOPORT uPort, + uint32_t uValue, + unsigned cb)); + + /** + * Request port IO read. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param uPort I/O port address. + * @param puValue Place to store read value. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPioRead, (PPDMIPCIRAWUP pInterface, + RTIOPORT uPort, + uint32_t *puValue, + unsigned cb)); + + + /** + * Request MMIO write. + * + * This callback is only called if driver wants to receive MMIO via pu32Flags + * argument of pfnPciDeviceConstructStart(). + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param Address Guest physical address. + * @param pvValue Address of value to write. + * @param cb Access width. + * + * @todo Why is this @a Address documented as guest physical + * address and given a host ring-0 address type? + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioWrite, (PPDMIPCIRAWUP pInterface, + RTR0PTR Address, + void const *pvValue, + unsigned cb)); + + /** + * Request MMIO read. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param Address Guest physical address. + * @param pvValue Place to store read value. + * @param cb Access width. + * + * @todo Why is this @a Address documented as guest physical + * address and given a host ring-0 address type? + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMmioRead, (PPDMIPCIRAWUP pInterface, + RTR0PTR Address, + void *pvValue, + unsigned cb)); + + /** + * Host PCI config space accessors. + */ + /** + * Request driver to write value to host device's PCI config space. + * Host specific way (PIO or MCFG) is used to perform actual operation. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param offCfgSpace Offset in PCI config space. + * @param pvValue Value to write. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciCfgWrite, (PPDMIPCIRAWUP pInterface, + uint32_t offCfgSpace, + void *pvValue, + unsigned cb)); + /** + * Request driver to read value from host device's PCI config space. + * Host specific way (PIO or MCFG) is used to perform actual operation. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param offCfgSpace Offset in PCI config space. + * @param pvValue Where to store read value. + * @param cb Access width. + * + * @thread EMT thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciCfgRead, (PPDMIPCIRAWUP pInterface, + uint32_t offCfgSpace, + void *pvValue, + unsigned cb)); + + /** + * Request to enable interrupt notifications. Please note that this is purely + * R3 interface, so it's up to implementor to perform necessary machinery + * for communications with host OS kernel driver. Typical implementation will start + * userland thread waiting on shared semaphore (such as using SUPSEMEVENT), + * notified by the kernel interrupt handler, and then will call + * upper port pfnInterruptRequest() based on data provided by the driver. + * This apporach is taken, as calling VBox code from an asyncronous R0 + * interrupt handler when VMM may not be even running doesn't look + * like a good idea. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param uGuestIrq Guest IRQ to be passed to pfnInterruptRequest(). + * + * @thread Any thread, pfnInterruptRequest() will be usually invoked on a dedicated thread. + */ + DECLR3CALLBACKMEMBER(int, pfnEnableInterruptNotifications, (PPDMIPCIRAWUP pInterface, uint8_t uGuestIrq)); + + /** + * Request to disable interrupt notifications. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnDisableInterruptNotifications, (PPDMIPCIRAWUP pInterface)); + + /** @name Notification APIs. + * @{ + */ + + /** + * Notify driver when raw PCI device construction starts. + * + * Have to be the first operation as initializes internal state and opens host + * device driver. + * + * @returns status code + * @param pInterface Pointer to this interface structure. + * @param uHostPciAddress Host PCI address of device attached. + * @param uGuestPciAddress Guest PCI address of device attached. + * @param pszDeviceName Human readable device name. + * @param fDeviceFlags Flags for the host device. + * @param pfFlags Flags for virtual device, from the upper driver. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciDeviceConstructStart, (PPDMIPCIRAWUP pInterface, + uint32_t uHostPciAddress, + uint32_t uGuestPciAddress, + const char *pszDeviceName, + uint32_t fDeviceFlags, + uint32_t *pfFlags)); + + /** + * Notify driver when raw PCI device construction completes, so that it may + * perform further actions depending on success or failure of this operation. + * Standard action is to raise global IHostPciDevicePlugEvent. + * + * @param pInterface Pointer to this interface structure. + * @param rc Result code of the operation. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(void, pfnPciDeviceConstructComplete, (PPDMIPCIRAWUP pInterface, int rc)); + + /** + * Notify driver on finalization of raw PCI device. + * + * @param pInterface Pointer to this interface structure. + * @param fFlags Flags. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciDeviceDestruct, (PPDMIPCIRAWUP pInterface, uint32_t fFlags)); + + /** + * Notify driver on guest power state change. + * + * @param pInterface Pointer to this interface structure. + * @param enmState New power state. + * @param pu64Param State-specific in/out parameter. For now only used during power-on to provide VM caps. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPciDevicePowerStateChange, (PPDMIPCIRAWUP pInterface, + PCIRAWPOWERSTATE enmState, + uint64_t *pu64Param)); + + /** + * Notify driver about runtime error. + * + * @param pInterface Pointer to this interface structure. + * @param fFatal If error is fatal. + * @param pszErrorId Error ID. + * @param pszMessage Error message. + * + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnReportRuntimeError, (PPDMIPCIRAWUP pInterface, + bool fFatal, + const char *pszErrorId, + const char *pszMessage)); + /** @} */ +} PDMIPCIRAWUP; + +/** + * Init R0 PCI module. + */ +PCIRAWR0DECL(int) PciRawR0Init(void); +/** + * Process request (in R0). + */ +PCIRAWR0DECL(int) PciRawR0ProcessReq(PGVM pGVM, PSUPDRVSESSION pSession, PPCIRAWSENDREQ pReq); +/** + * Terminate R0 PCI module. + */ +PCIRAWR0DECL(void) PciRawR0Term(void); + +/** + * Per-VM R0 module init. + */ +PCIRAWR0DECL(int) PciRawR0InitVM(PGVM pGVM); + +/** + * Per-VM R0 module termination routine. + */ +PCIRAWR0DECL(void) PciRawR0TermVM(PGVM pGVM); + +/** + * Flags returned by pfnPciDeviceConstructStart(), to notify device + * how it shall handle device IO traffic. + */ +typedef enum PCIRAWDEVICEFLAGS +{ + /** Intercept port IO (R3 PIO always go to the driver). */ + PCIRAWRFLAG_CAPTURE_PIO = (1 << 0), + /** Intercept MMIO. */ + PCIRAWRFLAG_CAPTURE_MMIO = (1 << 1), + /** Allow bus mastering by physical device (requires IOMMU). */ + PCIRAWRFLAG_ALLOW_BM = (1 << 2), + /** Allow R3 MMIO mapping. */ + PCIRAWRFLAG_ALLOW_R3MAP = (1 << 3), + + /** The usual 32-bit type blow up. */ + PCIRAWRFLAG_32BIT_HACK = 0x7fffffff +} PCIRAWDEVICEFLAGS; + +#define PDMIPCIRAWUP_IID "06daa17f-097b-4ebe-a626-15f467b1de12" +#define PDMIPCIRAW_IID "68c6e4c4-4223-47e0-9134-e3c297992543" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmpci_h */ diff --git a/include/VBox/vmm/pdmpcidev.h b/include/VBox/vmm/pdmpcidev.h new file mode 100644 index 00000000..077c5525 --- /dev/null +++ b/include/VBox/vmm/pdmpcidev.h @@ -0,0 +1,803 @@ +/** @file + * PCI - The PCI Controller And Devices. (DEV) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmpcidev_h +#define VBOX_INCLUDED_vmm_pdmpcidev_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +/** @defgroup grp_pdm_pcidev PDM PCI Device + * @ingroup grp_pdm_device + * @{ + */ + +/** + * Callback function for intercept reading from the PCI configuration space. + * + * @returns VINF_SUCCESS or PDMDevHlpDBGFStop status (maybe others later). + * @retval VINF_PDM_PCI_DO_DEFAULT to do default read (same as calling + * PDMDevHlpPCIConfigRead()). + * + * @param pDevIns Pointer to the device instance the PCI device + * belongs to. + * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance. + * @param uAddress The configuration space register address. [0..4096] + * @param cb The register size. [1,2,4] + * @param pu32Value Where to return the register value. + * + * @remarks Called with the PDM lock held. The device lock is NOT take because + * that is very likely be a lock order violation. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPCICONFIGREAD,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t *pu32Value)); +/** Pointer to a FNPCICONFIGREAD() function. */ +typedef FNPCICONFIGREAD *PFNPCICONFIGREAD; +#if !RT_CLANG_PREREQ(11, 0) /* Clang 11 (at least) has trouble with nothrow and pointers to function pointers. */ +/** Pointer to a PFNPCICONFIGREAD. */ +typedef PFNPCICONFIGREAD *PPFNPCICONFIGREAD; +#endif + +/** + * Callback function for writing to the PCI configuration space. + * + * @returns VINF_SUCCESS or PDMDevHlpDBGFStop status (maybe others later). + * @retval VINF_PDM_PCI_DO_DEFAULT to do default read (same as calling + * PDMDevHlpPCIConfigWrite()). + * + * @param pDevIns Pointer to the device instance the PCI device + * belongs to. + * @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance. + * @param uAddress The configuration space register address. [0..4096] + * @param cb The register size. [1,2,4] + * @param u32Value The value that's being written. The number of bits actually used from + * this value is determined by the cb parameter. + * + * @remarks Called with the PDM lock held. The device lock is NOT take because + * that is very likely be a lock order violation. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPCICONFIGWRITE,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, + uint32_t uAddress, unsigned cb, uint32_t u32Value)); +/** Pointer to a FNPCICONFIGWRITE() function. */ +typedef FNPCICONFIGWRITE *PFNPCICONFIGWRITE; +#if !RT_CLANG_PREREQ(11, 0) /* Clang 11 (at least) has trouble with nothrow and pointers to function pointers. */ +/** Pointer to a PFNPCICONFIGWRITE. */ +typedef PFNPCICONFIGWRITE *PPFNPCICONFIGWRITE; +#endif + +/** + * Callback function for mapping an PCI I/O region. + * + * This is called when a PCI I/O region is mapped, and for new-style devices + * also when unmapped (address set to NIL_RTGCPHYS). For new-style devices, + * this callback is optional as the PCI bus calls IOM to map and unmap the + * regions. + * + * Old style devices have to call IOM to map the region themselves, while + * unmapping is done by the PCI bus like with the new style devices. + * + * @returns VBox status code. + * @retval VINF_PCI_MAPPING_DONE if the caller already did the mapping and the + * PCI bus should not use the handle it got to do the registration + * again. (Only allowed when @a GCPhysAddress is not NIL_RTGCPHYS.) + * + * @param pDevIns Pointer to the device instance the PCI device + * belongs to. + * @param pPciDev Pointer to the PCI device. + * @param iRegion The region number. + * @param GCPhysAddress Physical address of the region. If @a enmType is + * PCI_ADDRESS_SPACE_IO, this is an I/O port, otherwise + * it's a physical address. + * + * NIL_RTGCPHYS indicates that a mapping is about to be + * unmapped and that the device deregister access + * handlers for it and update its internal state to + * reflect this. + * + * @param cb Size of the region in bytes. + * @param enmType One of the PCI_ADDRESS_SPACE_* values. + * + * @remarks Called with the PDM lock held. The device lock is NOT take because + * that is very likely be a lock order violation. + */ +typedef DECLCALLBACKTYPE(int, FNPCIIOREGIONMAP,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + RTGCPHYS GCPhysAddress, RTGCPHYS cb, PCIADDRESSSPACE enmType)); +/** Pointer to a FNPCIIOREGIONMAP() function. */ +typedef FNPCIIOREGIONMAP *PFNPCIIOREGIONMAP; + + +/** + * Sets the size and type for old saved states from within a + * PDMPCIDEV::pfnRegionLoadChangeHookR3 callback. + * + * @returns VBox status code. + * @param pPciDev Pointer to the PCI device. + * @param iRegion The region number. + * @param cbRegion The region size. + * @param enmType Combination of the PCI_ADDRESS_SPACE_* values. + */ +typedef DECLCALLBACKTYPE(int, FNPCIIOREGIONOLDSETTER,(PPDMPCIDEV pPciDev, uint32_t iRegion, RTGCPHYS cbRegion, + PCIADDRESSSPACE enmType)); +/** Pointer to a FNPCIIOREGIONOLDSETTER() function. */ +typedef FNPCIIOREGIONOLDSETTER *PFNPCIIOREGIONOLDSETTER; + +/** + * Swaps two PCI I/O regions from within a PDMPCIDEV::pfnRegionLoadChangeHookR3 + * callback. + * + * @returns VBox status code. + * @param pPciDev Pointer to the PCI device. + * @param iRegion The region number. + * @param iOtherRegion The number of the region swap with. + * @sa @bugref{9359} + */ +typedef DECLCALLBACKTYPE(int, FNPCIIOREGIONSWAP,(PPDMPCIDEV pPciDev, uint32_t iRegion, uint32_t iOtherRegion)); +/** Pointer to a FNPCIIOREGIONSWAP() function. */ +typedef FNPCIIOREGIONSWAP *PFNPCIIOREGIONSWAP; + + +/* + * Hack to include the PDMPCIDEVINT structure at the right place + * to avoid duplications of FNPCIIOREGIONMAP and such. + */ +#ifdef PDMPCIDEV_INCLUDE_PRIVATE +# include "pdmpcidevint.h" +#endif + +/** + * PDM PCI Device structure. + * + * A PCI device belongs to a PDM device. A PDM device may have zero or more PCI + * devices associated with it. The first PCI device that it registers + * automatically becomes the default PCI device and can be used implicitly + * with the device helper APIs. Subsequent PCI devices must be specified + * explicitly to the device helper APIs when used. + */ +typedef struct PDMPCIDEV +{ + /** @name Read only data. + * @{ + */ + /** Magic number (PDMPCIDEV_MAGIC). */ + uint32_t u32Magic; + /** PCI device number [11:3] and function [2:0] on the pci bus. + * @sa VBOX_PCI_DEVFN_MAKE, VBOX_PCI_DEVFN_FUN_MASK, VBOX_PCI_DEVFN_DEV_SHIFT */ + uint32_t uDevFn; + /** Size of the valid config space (we always allocate 4KB). */ + uint16_t cbConfig; + /** Size of the MSI-X state data optionally following the config space. */ + uint16_t cbMsixState; + /** Index into the PDMDEVINS::apPciDev array. */ + uint16_t idxSubDev; + uint16_t u16Padding; + /** Device name. */ + R3PTRTYPE(const char *) pszNameR3; + /** @} */ + + /** + * Callback for dealing with size changes. + * + * This is set by the PCI device when needed. It is only needed if any changes + * in the PCI resources have been made that may be incompatible with saved state + * (i.e. does not reflect configuration, but configuration defaults changed). + * + * The implementation can use PDMDevHlpMMIOExReduce to adjust the resource + * allocation down in size. There is currently no way of growing resources. + * Dropping a resource is automatic. + * + * @returns VBox status code. + * @param pDevIns Pointer to the device instance the PCI device + * belongs to. + * @param pPciDev Pointer to the PCI device. + * @param iRegion The region number or UINT32_MAX if old saved state call. + * @param cbRegion The size being loaded, RTGCPHYS_MAX if old saved state + * call, or 0 for dummy 64-bit top half region. + * @param enmType The type being loaded, -1 if old saved state call, or + * 0xff if dummy 64-bit top half region. + * @param pfnOldSetter Callback for setting size and type for call + * regarding old saved states. NULL otherwise. + * @param pfnSwapRegions Used to swaps two regions. The second one must be a + * higher number than @a iRegion. NULL if old saved + * state. + */ + DECLR3CALLBACKMEMBER(int, pfnRegionLoadChangeHookR3,(PPDMDEVINS pDevIns, PPDMPCIDEV pPciDev, uint32_t iRegion, + uint64_t cbRegion, PCIADDRESSSPACE enmType, + PFNPCIIOREGIONOLDSETTER pfnOldSetter, + PFNPCIIOREGIONSWAP pfnSwapRegion)); + + /** Reserved for future stuff. */ + uint64_t au64Reserved[4 + (R3_ARCH_BITS == 32 ? 1 : 0)]; + + /** Internal data. */ + union + { +#ifdef PDMPCIDEVINT_DECLARED + PDMPCIDEVINT s; +#endif + uint8_t padding[0x180]; + } Int; + + /** PCI config space. + * This is either 256 or 4096 in size. In the latter case it may be + * followed by a MSI-X state area. */ + uint8_t abConfig[4096]; + /** The MSI-X state data. Optional. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint8_t abMsixState[RT_FLEXIBLE_ARRAY]; +} PDMPCIDEV; +#ifdef PDMPCIDEVINT_DECLARED +AssertCompile(RT_SIZEOFMEMB(PDMPCIDEV, Int.s) <= RT_SIZEOFMEMB(PDMPCIDEV, Int.padding)); +#endif +/** Magic number of PDMPCIDEV::u32Magic (Margaret Eleanor Atwood). */ +#define PDMPCIDEV_MAGIC UINT32_C(0x19391118) + +/** Checks that the PCI device structure is valid and belongs to the device + * instance, but does not return. */ +#ifdef VBOX_STRICT +# define PDMPCIDEV_ASSERT_VALID(a_pDevIns, a_pPciDev) \ + do { \ + uintptr_t const offPciDevInTable = (uintptr_t)(a_pPciDev) - (uintptr_t)pDevIns->apPciDevs[0]; \ + uint32_t const cbPciDevTmp = pDevIns->cbPciDev; \ + ASMCompilerBarrier(); \ + AssertMsg( offPciDevInTable < pDevIns->cPciDevs * cbPciDevTmp \ + && cbPciDevTmp >= RT_UOFFSETOF(PDMPCIDEV, abConfig) + 256 \ + && offPciDevInTable % cbPciDevTmp == 0, \ + ("pPciDev=%p apPciDevs[0]=%p offPciDevInTable=%p cPciDevs=%#x cbPciDev=%#x\n", \ + (a_pPciDev), pDevIns->apPciDevs[0], offPciDevInTable, pDevIns->cPciDevs, cbPciDevTmp)); \ + AssertPtr((a_pPciDev)); \ + AssertMsg((a_pPciDev)->u32Magic == PDMPCIDEV_MAGIC, ("%#x\n", (a_pPciDev)->u32Magic)); \ + } while (0) +#else +# define PDMPCIDEV_ASSERT_VALID(a_pDevIns, a_pPciDev) do { } while (0) +#endif + +/** Checks that the PCI device structure is valid, belongs to the device + * instance and that it is registered, but does not return. */ +#ifdef VBOX_STRICT +# define PDMPCIDEV_ASSERT_VALID_AND_REGISTERED(a_pDevIns, a_pPciDev) \ + do { \ + PDMPCIDEV_ASSERT_VALID(a_pDevIns, a_pPciDev); \ + Assert((a_pPciDev)->Int.s.fRegistered); \ + } while (0) +#else +# define PDMPCIDEV_ASSERT_VALID_AND_REGISTERED(a_pDevIns, a_pPciDev) do { } while (0) +#endif + +/** Checks that the PCI device structure is valid and belongs to the device + * instance, returns appropriate status code if not valid. */ +#define PDMPCIDEV_ASSERT_VALID_RET(a_pDevIns, a_pPciDev) \ + do { \ + uintptr_t const offPciDevInTable = (uintptr_t)(a_pPciDev) - (uintptr_t)pDevIns->apPciDevs[0]; \ + uint32_t const cbPciDevTmp = pDevIns->cbPciDev; \ + ASMCompilerBarrier(); \ + AssertMsgReturn( offPciDevInTable < pDevIns->cPciDevs * cbPciDevTmp \ + && cbPciDevTmp >= RT_UOFFSETOF(PDMPCIDEV, abConfig) + 256 \ + && offPciDevInTable % cbPciDevTmp == 0, \ + ("pPciDev=%p apPciDevs[0]=%p offPciDevInTable=%p cPciDevs=%#x cbPciDev=%#x\n", \ + (a_pPciDev), pDevIns->apPciDevs[0], offPciDevInTable, pDevIns->cPciDevs, cbPciDevTmp), \ + VERR_PDM_NOT_PCI_DEVICE); \ + AssertMsgReturn((a_pPciDev)->u32Magic == PDMPCIDEV_MAGIC, ("%#x\n", (a_pPciDev)->u32Magic), VERR_PDM_NOT_PCI_DEVICE); \ + AssertReturn((a_pPciDev)->Int.s.fRegistered, VERR_PDM_NOT_PCI_DEVICE); \ + } while (0) + + + +/** @name PDM PCI config space accessor function. + * @{ + */ + +/** @todo handle extended space access. */ + +DECLINLINE(void) PDMPciDevSetByte(PPDMPCIDEV pPciDev, uint32_t offReg, uint8_t u8Value) +{ + Assert(offReg < sizeof(pPciDev->abConfig)); + pPciDev->abConfig[offReg] = u8Value; +} + +DECLINLINE(uint8_t) PDMPciDevGetByte(PCPDMPCIDEV pPciDev, uint32_t offReg) +{ + Assert(offReg < sizeof(pPciDev->abConfig)); + return pPciDev->abConfig[offReg]; +} + +DECLINLINE(void) PDMPciDevSetWord(PPDMPCIDEV pPciDev, uint32_t offReg, uint16_t u16Value) +{ + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint16_t)); + *(uint16_t*)&pPciDev->abConfig[offReg] = RT_H2LE_U16(u16Value); +} + +DECLINLINE(uint16_t) PDMPciDevGetWord(PCPDMPCIDEV pPciDev, uint32_t offReg) +{ + uint16_t u16Value; + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint16_t)); + u16Value = *(uint16_t*)&pPciDev->abConfig[offReg]; + return RT_H2LE_U16(u16Value); +} + +DECLINLINE(void) PDMPciDevSetDWord(PPDMPCIDEV pPciDev, uint32_t offReg, uint32_t u32Value) +{ + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint32_t)); + *(uint32_t*)&pPciDev->abConfig[offReg] = RT_H2LE_U32(u32Value); +} + +DECLINLINE(uint32_t) PDMPciDevGetDWord(PCPDMPCIDEV pPciDev, uint32_t offReg) +{ + uint32_t u32Value; + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint32_t)); + u32Value = *(uint32_t*)&pPciDev->abConfig[offReg]; + return RT_H2LE_U32(u32Value); +} + +DECLINLINE(void) PDMPciDevSetQWord(PPDMPCIDEV pPciDev, uint32_t offReg, uint64_t u64Value) +{ + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint64_t)); + *(uint64_t*)&pPciDev->abConfig[offReg] = RT_H2LE_U64(u64Value); +} + +DECLINLINE(uint64_t) PDMPciDevGetQWord(PCPDMPCIDEV pPciDev, uint32_t offReg) +{ + uint64_t u64Value; + Assert(offReg <= sizeof(pPciDev->abConfig) - sizeof(uint64_t)); + u64Value = *(uint64_t*)&pPciDev->abConfig[offReg]; + return RT_H2LE_U64(u64Value); +} + +/** + * Sets the vendor id config register. + * @param pPciDev The PCI device. + * @param u16VendorId The vendor id. + */ +DECLINLINE(void) PDMPciDevSetVendorId(PPDMPCIDEV pPciDev, uint16_t u16VendorId) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_VENDOR_ID, u16VendorId); +} + +/** + * Gets the vendor id config register. + * @returns the vendor id. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetVendorId(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_VENDOR_ID); +} + + +/** + * Sets the device id config register. + * @param pPciDev The PCI device. + * @param u16DeviceId The device id. + */ +DECLINLINE(void) PDMPciDevSetDeviceId(PPDMPCIDEV pPciDev, uint16_t u16DeviceId) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_DEVICE_ID, u16DeviceId); +} + +/** + * Gets the device id config register. + * @returns the device id. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetDeviceId(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_DEVICE_ID); +} + +/** + * Sets the command config register. + * + * @param pPciDev The PCI device. + * @param u16Command The command register value. + */ +DECLINLINE(void) PDMPciDevSetCommand(PPDMPCIDEV pPciDev, uint16_t u16Command) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_COMMAND, u16Command); +} + + +/** + * Gets the command config register. + * @returns The command register value. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetCommand(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_COMMAND); +} + +/** + * Checks if the given PCI device is a bus master. + * @returns true if the device is a bus master, false if not. + * @param pPciDev The PCI device. + */ +DECLINLINE(bool) PDMPciDevIsBusmaster(PCPDMPCIDEV pPciDev) +{ + return (PDMPciDevGetCommand(pPciDev) & VBOX_PCI_COMMAND_MASTER) != 0; +} + +/** + * Checks if INTx interrupts disabled in the command config register. + * @returns true if disabled. + * @param pPciDev The PCI device. + */ +DECLINLINE(bool) PDMPciDevIsIntxDisabled(PCPDMPCIDEV pPciDev) +{ + return (PDMPciDevGetCommand(pPciDev) & VBOX_PCI_COMMAND_INTX_DISABLE) != 0; +} + +/** + * Gets the status config register. + * + * @returns status config register. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetStatus(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_STATUS); +} + +/** + * Sets the status config register. + * + * @param pPciDev The PCI device. + * @param u16Status The status register value. + */ +DECLINLINE(void) PDMPciDevSetStatus(PPDMPCIDEV pPciDev, uint16_t u16Status) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_STATUS, u16Status); +} + + +/** + * Sets the revision id config register. + * + * @param pPciDev The PCI device. + * @param u8RevisionId The revision id. + */ +DECLINLINE(void) PDMPciDevSetRevisionId(PPDMPCIDEV pPciDev, uint8_t u8RevisionId) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_REVISION_ID, u8RevisionId); +} + + +/** + * Sets the register level programming class config register. + * + * @param pPciDev The PCI device. + * @param u8ClassProg The new value. + */ +DECLINLINE(void) PDMPciDevSetClassProg(PPDMPCIDEV pPciDev, uint8_t u8ClassProg) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_CLASS_PROG, u8ClassProg); +} + + +/** + * Sets the sub-class (aka device class) config register. + * + * @param pPciDev The PCI device. + * @param u8SubClass The sub-class. + */ +DECLINLINE(void) PDMPciDevSetClassSub(PPDMPCIDEV pPciDev, uint8_t u8SubClass) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_CLASS_SUB, u8SubClass); +} + + +/** + * Sets the base class config register. + * + * @param pPciDev The PCI device. + * @param u8BaseClass The base class. + */ +DECLINLINE(void) PDMPciDevSetClassBase(PPDMPCIDEV pPciDev, uint8_t u8BaseClass) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_CLASS_BASE, u8BaseClass); +} + +/** + * Sets the header type config register. + * + * @param pPciDev The PCI device. + * @param u8HdrType The header type. + */ +DECLINLINE(void) PDMPciDevSetHeaderType(PPDMPCIDEV pPciDev, uint8_t u8HdrType) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_HEADER_TYPE, u8HdrType); +} + +/** + * Gets the header type config register. + * + * @param pPciDev The PCI device. + * @returns u8HdrType The header type. + */ +DECLINLINE(uint8_t) PDMPciDevGetHeaderType(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_HEADER_TYPE); +} + +/** + * Sets the BIST (built-in self-test) config register. + * + * @param pPciDev The PCI device. + * @param u8Bist The BIST value. + */ +DECLINLINE(void) PDMPciDevSetBIST(PPDMPCIDEV pPciDev, uint8_t u8Bist) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_BIST, u8Bist); +} + +/** + * Gets the BIST (built-in self-test) config register. + * + * @param pPciDev The PCI device. + * @returns u8Bist The BIST. + */ +DECLINLINE(uint8_t) PDMPciDevGetBIST(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_BIST); +} + + +/** + * Sets a base address config register. + * + * @param pPciDev The PCI device. + * @param iReg Base address register number (0..5). + * @param fIOSpace Whether it's I/O (true) or memory (false) space. + * @param fPrefetchable Whether the memory is prefetachable. Must be false if fIOSpace == true. + * @param f64Bit Whether the memory can be mapped anywhere in the 64-bit address space. Otherwise restrict to 32-bit. + * @param u32Addr The address value. + */ +DECLINLINE(void) PDMPciDevSetBaseAddress(PPDMPCIDEV pPciDev, uint8_t iReg, bool fIOSpace, bool fPrefetchable, bool f64Bit, + uint32_t u32Addr) +{ + if (fIOSpace) + { + Assert(!(u32Addr & 0x3)); Assert(!fPrefetchable); Assert(!f64Bit); + u32Addr |= RT_BIT_32(0); + } + else + { + Assert(!(u32Addr & 0xf)); + if (fPrefetchable) + u32Addr |= RT_BIT_32(3); + if (f64Bit) + u32Addr |= 0x2 << 1; + } + switch (iReg) + { + case 0: iReg = VBOX_PCI_BASE_ADDRESS_0; break; + case 1: iReg = VBOX_PCI_BASE_ADDRESS_1; break; + case 2: iReg = VBOX_PCI_BASE_ADDRESS_2; break; + case 3: iReg = VBOX_PCI_BASE_ADDRESS_3; break; + case 4: iReg = VBOX_PCI_BASE_ADDRESS_4; break; + case 5: iReg = VBOX_PCI_BASE_ADDRESS_5; break; + default: AssertFailedReturnVoid(); + } + + PDMPciDevSetDWord(pPciDev, iReg, u32Addr); +} + +/** + * Please document me. I don't seem to be getting as much as calculating + * the address of some PCI region. + */ +DECLINLINE(uint32_t) PDMPciDevGetRegionReg(uint32_t iRegion) +{ + return iRegion == VBOX_PCI_ROM_SLOT + ? VBOX_PCI_ROM_ADDRESS : (VBOX_PCI_BASE_ADDRESS_0 + iRegion * 4); +} + +/** + * Sets the sub-system vendor id config register. + * + * @param pPciDev The PCI device. + * @param u16SubSysVendorId The sub-system vendor id. + */ +DECLINLINE(void) PDMPciDevSetSubSystemVendorId(PPDMPCIDEV pPciDev, uint16_t u16SubSysVendorId) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_SUBSYSTEM_VENDOR_ID, u16SubSysVendorId); +} + +/** + * Gets the sub-system vendor id config register. + * @returns the sub-system vendor id. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetSubSystemVendorId(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_SUBSYSTEM_VENDOR_ID); +} + + +/** + * Sets the sub-system id config register. + * + * @param pPciDev The PCI device. + * @param u16SubSystemId The sub-system id. + */ +DECLINLINE(void) PDMPciDevSetSubSystemId(PPDMPCIDEV pPciDev, uint16_t u16SubSystemId) +{ + PDMPciDevSetWord(pPciDev, VBOX_PCI_SUBSYSTEM_ID, u16SubSystemId); +} + +/** + * Gets the sub-system id config register. + * @returns the sub-system id. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint16_t) PDMPciDevGetSubSystemId(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetWord(pPciDev, VBOX_PCI_SUBSYSTEM_ID); +} + +/** + * Sets offset to capability list. + * + * @param pPciDev The PCI device. + * @param u8Offset The offset to capability list. + */ +DECLINLINE(void) PDMPciDevSetCapabilityList(PPDMPCIDEV pPciDev, uint8_t u8Offset) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST, u8Offset); +} + +/** + * Returns offset to capability list. + * + * @returns offset to capability list. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint8_t) PDMPciDevGetCapabilityList(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_CAPABILITY_LIST); +} + +/** + * Sets the interrupt line config register. + * + * @param pPciDev The PCI device. + * @param u8Line The interrupt line. + */ +DECLINLINE(void) PDMPciDevSetInterruptLine(PPDMPCIDEV pPciDev, uint8_t u8Line) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE, u8Line); +} + +/** + * Gets the interrupt line config register. + * + * @returns The interrupt line. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint8_t) PDMPciDevGetInterruptLine(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_INTERRUPT_LINE); +} + +/** + * Sets the interrupt pin config register. + * + * @param pPciDev The PCI device. + * @param u8Pin The interrupt pin. + */ +DECLINLINE(void) PDMPciDevSetInterruptPin(PPDMPCIDEV pPciDev, uint8_t u8Pin) +{ + PDMPciDevSetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN, u8Pin); +} + +/** + * Gets the interrupt pin config register. + * + * @returns The interrupt pin. + * @param pPciDev The PCI device. + */ +DECLINLINE(uint8_t) PDMPciDevGetInterruptPin(PCPDMPCIDEV pPciDev) +{ + return PDMPciDevGetByte(pPciDev, VBOX_PCI_INTERRUPT_PIN); +} + +/** @} */ + +/** @name Aliases for old function names. + * @{ + */ +#if !defined(PDMPCIDEVICE_NO_DEPRECATED) || defined(DOXYGEN_RUNNING) +# define PCIDevSetByte PDMPciDevSetByte +# define PCIDevGetByte PDMPciDevGetByte +# define PCIDevSetWord PDMPciDevSetWord +# define PCIDevGetWord PDMPciDevGetWord +# define PCIDevSetDWord PDMPciDevSetDWord +# define PCIDevGetDWord PDMPciDevGetDWord +# define PCIDevSetQWord PDMPciDevSetQWord +# define PCIDevGetQWord PDMPciDevGetQWord +# define PCIDevSetVendorId PDMPciDevSetVendorId +# define PCIDevGetVendorId PDMPciDevGetVendorId +# define PCIDevSetDeviceId PDMPciDevSetDeviceId +# define PCIDevGetDeviceId PDMPciDevGetDeviceId +# define PCIDevSetCommand PDMPciDevSetCommand +# define PCIDevGetCommand PDMPciDevGetCommand +# define PCIDevIsBusmaster PDMPciDevIsBusmaster +# define PCIDevIsIntxDisabled PDMPciDevIsIntxDisabled +# define PCIDevGetStatus PDMPciDevGetStatus +# define PCIDevSetStatus PDMPciDevSetStatus +# define PCIDevSetRevisionId PDMPciDevSetRevisionId +# define PCIDevSetClassProg PDMPciDevSetClassProg +# define PCIDevSetClassSub PDMPciDevSetClassSub +# define PCIDevSetClassBase PDMPciDevSetClassBase +# define PCIDevSetHeaderType PDMPciDevSetHeaderType +# define PCIDevGetHeaderType PDMPciDevGetHeaderType +# define PCIDevSetBIST PDMPciDevSetBIST +# define PCIDevGetBIST PDMPciDevGetBIST +# define PCIDevSetBaseAddress PDMPciDevSetBaseAddress +# define PCIDevGetRegionReg PDMPciDevGetRegionReg +# define PCIDevSetSubSystemVendorId PDMPciDevSetSubSystemVendorId +# define PCIDevGetSubSystemVendorId PDMPciDevGetSubSystemVendorId +# define PCIDevSetSubSystemId PDMPciDevSetSubSystemId +# define PCIDevGetSubSystemId PDMPciDevGetSubSystemId +# define PCIDevSetCapabilityList PDMPciDevSetCapabilityList +# define PCIDevGetCapabilityList PDMPciDevGetCapabilityList +# define PCIDevSetInterruptLine PDMPciDevSetInterruptLine +# define PCIDevGetInterruptLine PDMPciDevGetInterruptLine +# define PCIDevSetInterruptPin PDMPciDevSetInterruptPin +# define PCIDevGetInterruptPin PDMPciDevGetInterruptPin +#endif +/** @} */ + + +/** @name PDMIICH9BRIDGEPDMPCIDEV_IID - Ugly 3rd party bridge/raw PCI hack. + * + * When querying this IID via IBase::pfnQueryInterface on a ICH9 bridge, you + * will get a pointer to a PDMPCIDEV rather pointer to an interface function + * table as is the custom. This was needed by some unusual 3rd-party raw and/or + * pass-through implementation which need to provide different PCI configuration + * space content for bridges (as long as we don't allow pass-through of bridges + * or custom bridge device implementations). So, HACK ALERT to all of this! + * @{ */ +#define PDMIICH9BRIDGEPDMPCIDEV_IID "785c74b1-8510-4458-9422-56750bf221db" +typedef PPDMPCIDEV PPDMIICH9BRIDGEPDMPCIDEV; +typedef PDMPCIDEV PDMIICH9BRIDGEPDMPCIDEV; +/** @} */ + + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmpcidev_h */ diff --git a/include/VBox/vmm/pdmpcidevint.h b/include/VBox/vmm/pdmpcidevint.h new file mode 100644 index 00000000..b678bf05 --- /dev/null +++ b/include/VBox/vmm/pdmpcidevint.h @@ -0,0 +1,238 @@ +/* $Id: pdmpcidevint.h $ */ +/** @file + * DevPCI - PDM PCI Internal header - Only for hiding bits of PDMPCIDEV. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmpcidevint_h +#define VBOX_INCLUDED_vmm_pdmpcidevint_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +/** @defgroup grp_pdm_pcidev_int The PDM PCI Device Internals + * @ingroup grp_pdm_pcidev + * + * @remarks The PDM PCI device internals are visible to both PDM and the PCI Bus + * implementation, thus it lives among the the public headers despite + * being rather private and internal. + * + * @{ + */ + + +/** + * PCI I/O region. + */ +typedef struct PCIIOREGION +{ + /** Current PCI mapping address, INVALID_PCI_ADDRESS (0xffffffff) means not mapped. */ + uint64_t addr; + /** The region size. Power of 2. */ + uint64_t size; + /** Handle or UINT64_MAX (see PDMPCIDEV_IORGN_F_HANDLE_MASK in fFlags). */ + uint64_t hHandle; + /** PDMPCIDEV_IORGN_F_XXXX. */ + uint32_t fFlags; + /** PCIADDRESSSPACE */ + uint8_t type; + uint8_t abPadding0[3]; + /** Callback called when the region is mapped or unmapped (new style devs). */ + R3PTRTYPE(PFNPCIIOREGIONMAP) pfnMap; +#if R3_ARCH_BITS == 32 + uint32_t u32Padding2; +#endif +} PCIIOREGION; +AssertCompileSize(PCIIOREGION, 5*8); +/** Pointer to a PCI I/O region. */ +typedef PCIIOREGION *PPCIIOREGION; +/** Pointer to a const PCI I/O region. */ +typedef PCIIOREGION const *PCPCIIOREGION; + +/** + * Callback function for reading from the PCI configuration space. + * + * @returns Strict VBox status code. + * @param pDevIns Pointer to the device instance of the PCI bus. + * @param iBus The bus number this device is on. + * @param iDevice The number of the device on the bus. + * @param u32Address The configuration space register address. [0..255] + * @param cb The register size. [1,2,4] + * @param pu32Value Where to return the register value. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPCIBRIDGECONFIGREAD,(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, + uint32_t u32Address, unsigned cb, uint32_t *pu32Value)); +/** Pointer to a FNPCICONFIGREAD() function. */ +typedef FNPCIBRIDGECONFIGREAD *PFNPCIBRIDGECONFIGREAD; +#if !RT_CLANG_PREREQ(11, 0) /* Clang 11 (at least) has trouble with nothrow and pointers to function pointers. */ +/** Pointer to a PFNPCICONFIGREAD. */ +typedef PFNPCIBRIDGECONFIGREAD *PPFNPCIBRIDGECONFIGREAD; +#endif + +/** + * Callback function for writing to the PCI configuration space. + * + * @returns Strict VBox status code. + * @param pDevIns Pointer to the device instance of the PCI bus. + * @param iBus The bus number this device is on. + * @param iDevice The number of the device on the bus. + * @param u32Address The configuration space register address. [0..255] + * @param cb The register size. [1,2,4] + * @param u32Value The value that's being written. The number of bits actually used from + * this value is determined by the cb parameter. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPCIBRIDGECONFIGWRITE,(PPDMDEVINSR3 pDevIns, uint8_t iBus, uint8_t iDevice, + uint32_t u32Address, unsigned cb, uint32_t u32Value)); +/** Pointer to a FNPCICONFIGWRITE() function. */ +typedef FNPCIBRIDGECONFIGWRITE *PFNPCIBRIDGECONFIGWRITE; +#if !RT_CLANG_PREREQ(11, 0) /* Clang 11 (at least) has trouble with nothrow and pointers to function pointers. */ +/** Pointer to a PFNPCICONFIGWRITE. */ +typedef PFNPCIBRIDGECONFIGWRITE *PPFNPCIBRIDGECONFIGWRITE; +#endif + +/* Forward declaration */ +struct DEVPCIBUS; + +enum { + /** Flag whether the device is a pci-to-pci bridge. + * This is set prior to device registration. */ + PCIDEV_FLAG_PCI_TO_PCI_BRIDGE = RT_BIT_32(1), + /** Flag whether the device is a PCI Express device. + * This is set prior to device registration. */ + PCIDEV_FLAG_PCI_EXPRESS_DEVICE = RT_BIT_32(2), + /** Flag whether the device is capable of MSI. + * This one is set by MsiInit(). */ + PCIDEV_FLAG_MSI_CAPABLE = RT_BIT_32(3), + /** Flag whether the device is capable of MSI-X. + * This one is set by MsixInit(). */ + PCIDEV_FLAG_MSIX_CAPABLE = RT_BIT_32(4), + /** Flag if device represents real physical device in passthrough mode. */ + PCIDEV_FLAG_PASSTHROUGH = RT_BIT_32(5), + /** Flag whether the device is capable of MSI using 64-bit address. */ + PCIDEV_FLAG_MSI64_CAPABLE = RT_BIT_32(6) + +}; + + +/** + * PDM PCI Device - Internal data. + * + * @sa PDMPCIDEV + */ +typedef struct PDMPCIDEVINT +{ + /** @name Owned by PDM. + * @remarks The bus may use the device instance pointers. + * @{ + */ + /** Pointer to the PDM device the PCI device belongs to. (R3 ptr) */ + PPDMDEVINSR3 pDevInsR3; + /** The CFGM device configuration index (default, PciDev1..255). + * This also works as the internal sub-device ordinal with MMIOEx. + * @note Same value as idxSubDev, can therefore be removed later. */ + uint8_t idxDevCfg; + /** Set if the it can be reassigned to a different PCI device number. */ + bool fReassignableDevNo; + /** Set if the it can be reassigned to a different PCI function number. */ + bool fReassignableFunNo; + /** Alignment padding - used by ICH9 for region swapping (DevVGA hack). */ + uint8_t bPadding0; + /** Index into the PDM internal bus array (PDM::aPciBuses). */ + uint8_t idxPdmBus; + /** Set if this device has been registered. */ + bool fRegistered; + /** Index into PDMDEVINSR3::apPciDevs (same as PDMPCIDEV::idxSubDev). */ + uint16_t idxSubDev; + /** @} */ + + /** @name Owned by the PCI Bus + * @remarks PDM will not touch anything here (includes not relocating anything). + * @{ + */ + /** Pointer to the PCI bus of the device. (R3 ptr) */ + R3PTRTYPE(struct DEVPCIBUS *) pBusR3; + /** Read config callback. */ + R3PTRTYPE(PFNPCICONFIGREAD) pfnConfigRead; + /** Write config callback. */ + R3PTRTYPE(PFNPCICONFIGWRITE) pfnConfigWrite; + /** Read config callback for PCI bridges to pass requests + * to devices on another bus. */ + R3PTRTYPE(PFNPCIBRIDGECONFIGREAD) pfnBridgeConfigRead; + /** Write config callback for PCI bridges to pass requests + * to devices on another bus. */ + R3PTRTYPE(PFNPCIBRIDGECONFIGWRITE) pfnBridgeConfigWrite; + + /** Flags of this PCI device, see PCIDEV_FLAG_XXX constants. */ + uint32_t fFlags; + /** Current state of the IRQ pin of the device. */ + int32_t uIrqPinState; + + /** Offset of MSI PCI capability in config space, or 0. + * @todo fix non-standard naming. */ + uint8_t u8MsiCapOffset; + /** Size of MSI PCI capability in config space, or 0. + * @todo fix non-standard naming. */ + uint8_t u8MsiCapSize; + /** Offset of MSI-X PCI capability in config space, or 0. + * @todo fix non-standard naming. */ + uint8_t u8MsixCapOffset; + /** Size of MSI-X PCI capability in config space, or 0. + * @todo fix non-standard naming. */ + uint8_t u8MsixCapSize; + /** Size of the MSI-X region. */ + uint16_t cbMsixRegion; + /** Offset to the PBA for MSI-X. */ + uint16_t offMsixPba; + /** Add padding to align aIORegions to an 16 byte boundary. */ + uint8_t abPadding2[HC_ARCH_BITS == 32 ? 12 : 8]; + /** The MMIO handle for the MSI-X MMIO bar. */ + IOMMMIOHANDLE hMmioMsix; + + /** Pointer to bus specific data. (R3 ptr) */ + R3PTRTYPE(const void *) pvPciBusPtrR3; + /** I/O regions. */ + PCIIOREGION aIORegions[VBOX_PCI_NUM_REGIONS]; + /** @} */ +} PDMPCIDEVINT; +AssertCompileMemberAlignment(PDMPCIDEVINT, aIORegions, 8); +AssertCompileSize(PDMPCIDEVINT, HC_ARCH_BITS == 32 ? 0x98 : 0x178); + +/** Indicate that PDMPCIDEV::Int.s can be declared. */ +#define PDMPCIDEVINT_DECLARED + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmpcidevint_h */ + diff --git a/include/VBox/vmm/pdmqueue.h b/include/VBox/vmm/pdmqueue.h new file mode 100644 index 00000000..a932ec28 --- /dev/null +++ b/include/VBox/vmm/pdmqueue.h @@ -0,0 +1,169 @@ +/** @file + * PDM - Pluggable Device Manager, Queues. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmqueue_h +#define VBOX_INCLUDED_vmm_pdmqueue_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_queue The PDM Queues API + * @ingroup grp_pdm + * @{ + */ + +/** Pointer to a PDM queue. */ +typedef struct PDMQUEUE *PPDMQUEUE; + +/** Pointer to a PDM queue item core. */ +typedef union PDMQUEUEITEMCORE *PPDMQUEUEITEMCORE; + +/** + * PDM queue item core. + */ +typedef union PDMQUEUEITEMCORE +{ + /** The next queue item on the pending list (UINT32_MAX for NIL). */ + uint32_t volatile iNext; + /** The next item about to be flushed. */ + R3PTRTYPE(PPDMQUEUEITEMCORE) pNext; + /** Make sure the core is 64-bit wide. */ + uint64_t u64View; +} PDMQUEUEITEMCORE; + + +/** + * Queue consumer callback for devices. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pDevIns The device instance. + * @param pItem The item to consume. Upon return this item will be freed. + * @remarks The device critical section will NOT be entered before calling the + * callback. No locks will be held, but for now it's safe to assume + * that only one EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(bool, FNPDMQUEUEDEV,(PPDMDEVINS pDevIns, PPDMQUEUEITEMCORE pItem)); +/** Pointer to a FNPDMQUEUEDEV(). */ +typedef FNPDMQUEUEDEV *PFNPDMQUEUEDEV; + +/** + * Queue consumer callback for USB devices. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pUsbIns The USB device instance. + * @param pItem The item to consume. Upon return this item will be freed. + * @remarks No locks will be held, but for now it's safe to assume that only one + * EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(bool, FNPDMQUEUEUSB,(PPDMUSBINS pUsbIns, PPDMQUEUEITEMCORE pItem)); +/** Pointer to a FNPDMQUEUEUSB(). */ +typedef FNPDMQUEUEUSB *PFNPDMQUEUEUSB; + +/** + * Queue consumer callback for drivers. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pDrvIns The driver instance. + * @param pItem The item to consume. Upon return this item will be freed. + * @remarks No locks will be held, but for now it's safe to assume that only one + * EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(bool, FNPDMQUEUEDRV,(PPDMDRVINS pDrvIns, PPDMQUEUEITEMCORE pItem)); +/** Pointer to a FNPDMQUEUEDRV(). */ +typedef FNPDMQUEUEDRV *PFNPDMQUEUEDRV; + +/** + * Queue consumer callback for internal component. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pVM The cross context VM structure. + * @param pItem The item to consume. Upon return this item will be freed. + * @remarks No locks will be held, but for now it's safe to assume that only one + * EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(bool, FNPDMQUEUEINT,(PVM pVM, PPDMQUEUEITEMCORE pItem)); +/** Pointer to a FNPDMQUEUEINT(). */ +typedef FNPDMQUEUEINT *PFNPDMQUEUEINT; + +/** + * Queue consumer callback for external component. + * + * @returns Success indicator. + * If false the item will not be removed and the flushing will stop. + * @param pvUser User argument. + * @param pItem The item to consume. Upon return this item will be freed. + * @remarks No locks will be held, but for now it's safe to assume that only one + * EMT will do queue callbacks at any one time. + */ +typedef DECLCALLBACKTYPE(bool, FNPDMQUEUEEXT,(void *pvUser, PPDMQUEUEITEMCORE pItem)); +/** Pointer to a FNPDMQUEUEEXT(). */ +typedef FNPDMQUEUEEXT *PFNPDMQUEUEEXT; + +#ifdef VBOX_IN_VMM +VMMR3_INT_DECL(int) PDMR3QueueCreateDevice(PVM pVM, PPDMDEVINS pDevIns, size_t cbItem, uint32_t cItems, + uint32_t cMilliesInterval, PFNPDMQUEUEDEV pfnCallback, + bool fRZEnabled, const char *pszName, PDMQUEUEHANDLE *phQueue); +VMMR3_INT_DECL(int) PDMR3QueueCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, size_t cbItem, uint32_t cItems, + uint32_t cMilliesInterval, PFNPDMQUEUEDRV pfnCallback, + const char *pszName, PDMQUEUEHANDLE *phQueue); +VMMR3_INT_DECL(int) PDMR3QueueCreateInternal(PVM pVM, size_t cbItem, uint32_t cItems, + uint32_t cMilliesInterval, PFNPDMQUEUEINT pfnCallback, + bool fRZEnabled, const char *pszName, PDMQUEUEHANDLE *phQueue); +VMMR3DECL(int) PDMR3QueueCreateExternal(PVM pVM, size_t cbItem, uint32_t cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEEXT pfnCallback, void *pvUser, const char *pszName, PDMQUEUEHANDLE *phQueue); +VMMR3DECL(int) PDMR3QueueDestroy(PVM pVM, PDMQUEUEHANDLE hQueue, void *pvOwner); +VMMR3_INT_DECL(int) PDMR3QueueDestroyDevice(PVM pVM, PPDMDEVINS pDevIns); +VMMR3_INT_DECL(int) PDMR3QueueDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns); +VMMR3DECL(void) PDMR3QueueFlushAll(PVM pVM); +#endif /* VBOX_IN_VMM */ + +VMMDECL(PPDMQUEUEITEMCORE) PDMQueueAlloc(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner); +VMMDECL(int) PDMQueueInsert(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner, PPDMQUEUEITEMCORE pInsert); +VMMDECL(int) PDMQueueFlushIfNecessary(PVMCC pVM, PDMQUEUEHANDLE hQueue, void *pvOwner); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmqueue_h */ + diff --git a/include/VBox/vmm/pdmserialifs.h b/include/VBox/vmm/pdmserialifs.h new file mode 100644 index 00000000..3917e0e5 --- /dev/null +++ b/include/VBox/vmm/pdmserialifs.h @@ -0,0 +1,249 @@ +/** @file + * PDM - Pluggable Device Manager, Serial port related interfaces. + */ + +/* + * Copyright (C) 2018-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmserialifs_h +#define VBOX_INCLUDED_vmm_pdmserialifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_ifs_serial PDM Serial Port Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +/** @name Bit mask definitions for status line type. + * @{ */ +#define PDMISERIALPORT_STS_LINE_DCD RT_BIT(0) +#define PDMISERIALPORT_STS_LINE_RI RT_BIT(1) +#define PDMISERIALPORT_STS_LINE_DSR RT_BIT(2) +#define PDMISERIALPORT_STS_LINE_CTS RT_BIT(3) +/** @} */ + +/** Pointer to a serial port interface. */ +typedef struct PDMISERIALPORT *PPDMISERIALPORT; +/** + * Serial port interface (down). + */ +typedef struct PDMISERIALPORT +{ + /** + * Notifies the upper device/driver that data is available for reading. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cbAvail The amount of data available to be written. + */ + DECLR3CALLBACKMEMBER(int, pfnDataAvailRdrNotify, (PPDMISERIALPORT pInterface, size_t cbAvail)); + + /** + * Notifies the upper device/driver that all data was sent. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnDataSentNotify, (PPDMISERIALPORT pInterface)); + + /** + * Try to read data from the device/driver above for writing. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the read data. + * @param cbRead How much to read. + * @param pcbRead Where to store the amount of data actually read on success. + */ + DECLR3CALLBACKMEMBER(int, pfnReadWr, (PPDMISERIALPORT pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)); + + /** + * Notify the device/driver when the status lines changed. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fNewStatusLines New state of the status line pins. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnNotifyStsLinesChanged, (PPDMISERIALPORT pInterface, uint32_t fNewStatusLines)); + + /** + * Notify the device/driver that a break condition occurred. + * + * @returns VBox statsus code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnNotifyBrk, (PPDMISERIALPORT pInterface)); + +} PDMISERIALPORT; +/** PDMISERIALPORT interface ID. */ +#define PDMISERIALPORT_IID "44540323-06ca-44c1-8eb2-f5a387704dbd" + + +/** + * Supported parity modes. + */ +typedef enum PDMSERIALPARITY +{ + /** Invalid parity setting. */ + PDMSERIALPARITY_INVALID = 0, + /** No parity. */ + PDMSERIALPARITY_NONE, + /** Even parity. */ + PDMSERIALPARITY_EVEN, + /** Odd parity. */ + PDMSERIALPARITY_ODD, + /** Mark parity. */ + PDMSERIALPARITY_MARK, + /** Space parity. */ + PDMSERIALPARITY_SPACE, + /** 32bit hack. */ + PDMSERIALPARITY_32BIT_HACK = 0x7fffffff +} PDMSERIALPARITY; + + +/** + * Supported number of stop bits. + */ +typedef enum PDMSERIALSTOPBITS +{ + /** Invalid stop bits setting. */ + PDMSERIALSTOPBITS_INVALID = 0, + /** One stop bit is used. */ + PDMSERIALSTOPBITS_ONE, + /** 1.5 stop bits are used. */ + PDMSERIALSTOPBITS_ONEPOINTFIVE, + /** 2 stop bits are used. */ + PDMSERIALSTOPBITS_TWO, + /** 32bit hack. */ + PDMSERIALSTOPBITS_32BIT_HACK = 0x7fffffff +} PDMSERIALSTOPBITS; + + +/** Pointer to a serial interface. */ +typedef struct PDMISERIALCONNECTOR *PPDMISERIALCONNECTOR; +/** + * Serial interface (up). + * Pairs with PDMISERIALPORT. + */ +typedef struct PDMISERIALCONNECTOR +{ + /** + * Notifies the lower layer that data is available for writing. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnDataAvailWrNotify, (PPDMISERIALCONNECTOR pInterface)); + + /** + * Try to read data from the underyling driver. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pvBuf Where to store the read data. + * @param cbRead How much to read. + * @param pcbRead Where to store the amount of data actually read on success. + */ + DECLR3CALLBACKMEMBER(int, pfnReadRdr, (PPDMISERIALCONNECTOR pInterface, void *pvBuf, size_t cbRead, size_t *pcbRead)); + + /** + * Change device parameters. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param uBps Speed of the serial connection. (bits per second) + * @param enmParity Parity method. + * @param cDataBits Number of data bits. + * @param enmStopBits Number of stop bits. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnChgParams, (PPDMISERIALCONNECTOR pInterface, uint32_t uBps, + PDMSERIALPARITY enmParity, unsigned cDataBits, + PDMSERIALSTOPBITS enmStopBits)); + + /** + * Set the state of the modem lines. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fRts Set to true to make the Request to Send line active otherwise to 0. + * @param fDtr Set to true to make the Data Terminal Ready line active otherwise 0. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnChgModemLines, (PPDMISERIALCONNECTOR pInterface, bool fRts, bool fDtr)); + + /** + * Changes the TD line into the requested break condition. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fBrk Set to true to let the device send a break false to put into normal operation. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnChgBrk, (PPDMISERIALCONNECTOR pInterface, bool fBrk)); + + /** + * Queries the current state of the status lines. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfStsLines Where to store the status line states on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryStsLines, (PPDMISERIALCONNECTOR pInterface, uint32_t *pfStsLines)); + + /** + * Flushes the indicated queues. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param fQueueRecv Flag whether to flush the receive queue. + * @param fQueueXmit Flag whether to flush the transmit queue. + */ + DECLR3CALLBACKMEMBER(int, pfnQueuesFlush, (PPDMISERIALCONNECTOR pInterface, bool fQueueRecv, bool fQueueXmit)); + +} PDMISERIALCONNECTOR; +/** PDMIMEDIA interface ID. */ +#define PDMISERIALCONNECTOR_IID "d024f170-c00d-11e8-b568-0800200c9a66" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmserialifs_h */ diff --git a/include/VBox/vmm/pdmsrv.h b/include/VBox/vmm/pdmsrv.h new file mode 100644 index 00000000..e0b3f7ce --- /dev/null +++ b/include/VBox/vmm/pdmsrv.h @@ -0,0 +1,350 @@ +/** @file + * PDM - Pluggable Device Manager, VM Services. + * + * @todo This has not been implemented, consider dropping the concept. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmsrv_h +#define VBOX_INCLUDED_vmm_pdmsrv_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_services The PDM Services API + * @ingroup grp_pdm + * @{ + */ + +/** + * Construct a service instance for a VM. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + * If the registration structure is needed, pSrvIns->pReg points to it. + * @param pCfg Configuration node handle for the service. Use this to obtain the configuration + * of the driver instance. It's also found in pSrvIns->pCfg, but since it's primary + * usage is expected in this function it is passed as a parameter. + */ +typedef DECLCALLBACKTYPE(int, FNPDMSRVCONSTRUCT,(PPDMSRVINS pSrvIns, PCFGMNODE pCfg)); +/** Pointer to a FNPDMSRVCONSTRUCT() function. */ +typedef FNPDMSRVCONSTRUCT *PFNPDMSRVCONSTRUCT; + +/** + * Destruct a driver instance. + * + * Most VM resources are freed by the VM. This callback is provided so that any non-VM + * resources can be freed correctly. + * + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVDESTRUCT,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVDESTRUCT() function. */ +typedef FNPDMSRVDESTRUCT *PFNPDMSRVDESTRUCT; + +/** + * Power On notification. + * + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVPOWERON,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVPOWERON() function. */ +typedef FNPDMSRVPOWERON *PFNPDMSRVPOWERON; + +/** + * Reset notification. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVRESET,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVRESET() function. */ +typedef FNPDMSRVRESET *PFNPDMSRVRESET; + +/** + * Suspend notification. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVSUSPEND,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVSUSPEND() function. */ +typedef FNPDMSRVSUSPEND *PFNPDMSRVSUSPEND; + +/** + * Resume notification. + * + * @returns VBox status. + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVRESUME,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVRESUME() function. */ +typedef FNPDMSRVRESUME *PFNPDMSRVRESUME; + +/** + * Power Off notification. + * + * @param pSrvIns The service instance data. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVPOWEROFF,(PPDMSRVINS pSrvIns)); +/** Pointer to a FNPDMSRVPOWEROFF() function. */ +typedef FNPDMSRVPOWEROFF *PFNPDMSRVPOWEROFF; + +/** + * Detach notification. + * + * This is called when a driver or device is detached from the service + * + * @param pSrvIns The service instance data. + * @param pDevIns The device instance to detach. + * @param pDrvIns The driver instance to detach. + */ +typedef DECLCALLBACKTYPE(void, FNPDMSRVDETACH,(PPDMSRVINS pSrvIns, PPDMDEVINS pDevIns, PPDMDRVINS pDrvIns)); +/** Pointer to a FNPDMSRVDETACH() function. */ +typedef FNPDMSRVDETACH *PFNPDMSRVDETACH; + + + +/** PDM Service Registration Structure, + * This structure is used when registering a driver from + * VBoxServicesRegister() (HC Ring-3). PDM will continue use till + * the VM is terminated. + */ +typedef struct PDMSRVREG +{ + /** Structure version. PDM_SRVREG_VERSION defines the current version. */ + uint32_t u32Version; + /** Driver name. */ + char szServiceName[32]; + /** The description of the driver. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** Flags, combination of the PDM_SRVREG_FLAGS_* \#defines. */ + RTUINT fFlags; + /** Size of the instance data. */ + RTUINT cbInstance; + + /** Construct instance - required. */ + PFNPDMSRVCONSTRUCT pfnConstruct; + /** Destruct instance - optional. */ + PFNPDMSRVDESTRUCT pfnDestruct; + /** Power on notification - optional. */ + PFNPDMSRVPOWERON pfnPowerOn; + /** Reset notification - optional. */ + PFNPDMSRVRESET pfnReset; + /** Suspend notification - optional. */ + PFNPDMSRVSUSPEND pfnSuspend; + /** Resume notification - optional. */ + PFNPDMSRVRESUME pfnResume; + /** Detach notification - optional. */ + PFNPDMSRVDETACH pfnDetach; + /** Power off notification - optional. */ + PFNPDMSRVPOWEROFF pfnPowerOff; + +} PDMSRVREG; +/** Pointer to a PDM Driver Structure. */ +typedef PDMSRVREG *PPDMSRVREG; +/** Const pointer to a PDM Driver Structure. */ +typedef PDMSRVREG const *PCPDMSRVREG; + + + +/** + * PDM Service API. + */ +typedef struct PDMSRVHLP +{ + /** Structure version. PDM_SRVHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pSrvIns Service instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMSRVINS pSrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pSrvIns Service instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertOther,(PPDMSRVINS pSrvIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Creates a timer. + * + * @returns VBox status. + * @param pVM The cross context VM structure. + * @param pSrvIns Service instance. + * @param enmClock The clock to use on this timer. + * @param pfnCallback Callback function. + * @param pszDesc Pointer to description string which must stay around + * until the timer is fully destroyed (i.e. a bit after TMTimerDestroy()). + * @param ppTimer Where to store the timer on success. + */ + DECLR3CALLBACKMEMBER(int, pfnTMTimerCreate,(PPDMSRVINS pSrvIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, const char *pszDesc, PPTMTIMERR3 ppTimer)); + + /** + * Query the virtual timer frequency. + * + * @returns Frequency in Hz. + * @param pSrvIns Service instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMGetVirtualFreq,(PPDMSRVINS pSrvIns)); + + /** + * Query the virtual time. + * + * @returns The current virtual time. + * @param pSrvIns Service instance. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTMGetVirtualTime,(PPDMSRVINS pSrvIns)); + +} PDMSRVHLP; +/** Pointer PDM Service API. */ +typedef PDMSRVHLP *PPDMSRVHLP; +/** Pointer const PDM Service API. */ +typedef const PDMSRVHLP *PCPDMSRVHLP; + +/** Current SRVHLP version number. */ +#define PDM_SRVHLP_VERSION PDM_VERSION_MAKE(0xdfff, 1, 0) + + +/** + * PDM Service Instance. + */ +typedef struct PDMSRVINS +{ + /** Structure version. PDM_SRVINS_VERSION defines the current version. */ + uint32_t u32Version; + + /** Internal data. */ + union + { +#ifdef PDMSRVINSINT_DECLARED + PDMSRVINSINT s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 32 : 32]; + } Internal; + + /** Pointer the PDM Service API. */ + R3PTRTYPE(PCPDMSRVHLP) pHlp; + /** Pointer to driver registration structure. */ + R3PTRTYPE(PCPDMSRVREG) pReg; + /** Configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfg; + /** The base interface of the service. + * The service constructor initializes this. */ + PDMIBASE IBase; + /* padding to make achInstanceData aligned at 16 byte boundary. */ + uint32_t au32Padding[2]; + /** Pointer to driver instance data. */ + R3PTRTYPE(void *) pvInstanceData; + /** Driver instance data. The size of this area is defined + * in the PDMSRVREG::cbInstanceData field. */ + char achInstanceData[4]; +} PDMSRVINS; + +/** Current PDMSRVREG version number. */ +#define PDM_SRVINS_VERSION PDM_VERSION_MAKE(0xdffe, 1, 0) + +/** Converts a pointer to the PDMSRVINS::IBase to a pointer to PDMSRVINS. */ +#define PDMIBASE_2_PDMSRV(pInterface) ( (PPDMSRVINS)((char *)(pInterface) - RT_UOFFSETOF(PDMSRVINS, IBase)) ) + + + +/** Pointer to callbacks provided to the VBoxServiceRegister() call. */ +typedef struct PDMSRVREGCB *PPDMSRVREGCB; + +/** + * Callbacks for VBoxServiceRegister(). + */ +typedef struct PDMSRVREGCB +{ + /** Interface version. + * This is set to PDM_SRVREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a service with the current VM instance. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param pSrvReg Pointer to the device registration record. + * This data must be permanent and readonly. + */ + DECLR3CALLBACKMEMBER(int, pfnRegister,(PPDMSRVREGCB pCallbacks, PCPDMSRVREG pSrvReg)); +} PDMSRVREGCB; + +/** Current version of the PDMSRVREGCB structure. */ +#define PDM_SRVREG_CB_VERSION PDM_VERSION_MAKE(0xdffd, 1, 0) + + +/** + * The VBoxServicesRegister callback function. + * + * PDM will invoke this function after loading a device module and letting + * the module decide which devices to register and how to handle conflicts. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param u32Version VBox version number. + */ +typedef DECLCALLBACKTYPE(int, FNPDMVBOXSERVICESREGISTER,(PPDMSRVREGCB pCallbacks, uint32_t u32Version)); + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmsrv_h */ diff --git a/include/VBox/vmm/pdmstorageifs.h b/include/VBox/vmm/pdmstorageifs.h new file mode 100644 index 00000000..2aeeed99 --- /dev/null +++ b/include/VBox/vmm/pdmstorageifs.h @@ -0,0 +1,1059 @@ +/** @file + * PDM - Pluggable Device Manager, Storage related interfaces. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmstorageifs_h +#define VBOX_INCLUDED_vmm_pdmstorageifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +RT_C_DECLS_BEGIN + +struct PDMISECKEY; +struct PDMISECKEYHLP; + + +/** @defgroup grp_pdm_ifs_storage PDM Storage Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +/** Pointer to a mount interface. */ +typedef struct PDMIMOUNTNOTIFY *PPDMIMOUNTNOTIFY; +/** + * Block interface (up). + * Pair with PDMIMOUNT. + */ +typedef struct PDMIMOUNTNOTIFY +{ + /** + * Called when a media is mounted. + * + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnMountNotify,(PPDMIMOUNTNOTIFY pInterface)); + + /** + * Called when a media is unmounted + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(void, pfnUnmountNotify,(PPDMIMOUNTNOTIFY pInterface)); +} PDMIMOUNTNOTIFY; +/** PDMIMOUNTNOTIFY interface ID. */ +#define PDMIMOUNTNOTIFY_IID "fa143ac9-9fc6-498e-997f-945380a558f9" + + +/** Pointer to mount interface. */ +typedef struct PDMIMOUNT *PPDMIMOUNT; +/** + * Mount interface (down). + * Pair with PDMIMOUNTNOTIFY. + */ +typedef struct PDMIMOUNT +{ + /** + * Unmount the media. + * + * The driver will validate and pass it on. On the rebounce it will decide whether or not to detach it self. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + * @param fForce Force the unmount, even for locked media. + * @param fEject Eject the medium. Only relevant for host drives. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnUnmount,(PPDMIMOUNT pInterface, bool fForce, bool fEject)); + + /** + * Checks if a media is mounted. + * + * @returns true if mounted. + * @returns false if not mounted. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsMounted,(PPDMIMOUNT pInterface)); + + /** + * Locks the media, preventing any unmounting of it. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnLock,(PPDMIMOUNT pInterface)); + + /** + * Unlocks the media, canceling previous calls to pfnLock(). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnUnlock,(PPDMIMOUNT pInterface)); + + /** + * Checks if a media is locked. + * + * @returns true if locked. + * @returns false if not locked. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsLocked,(PPDMIMOUNT pInterface)); +} PDMIMOUNT; +/** PDMIMOUNT interface ID. */ +#define PDMIMOUNT_IID "34fc7a4c-623a-4806-a6bf-5be1be33c99f" + + +/** + * Callback which provides progress information. + * + * @return VBox status code. + * @param pvUser Opaque user data. + * @param uPercentage Completion percentage. + */ +typedef DECLCALLBACKTYPE(int, FNSIMPLEPROGRESS,(void *pvUser, unsigned uPercentage)); +/** Pointer to FNSIMPLEPROGRESS() */ +typedef FNSIMPLEPROGRESS *PFNSIMPLEPROGRESS; + + +/** + * Media type. + */ +typedef enum PDMMEDIATYPE +{ + /** Error (for the query function). */ + PDMMEDIATYPE_ERROR = 1, + /** 360KB 5 1/4" floppy drive. */ + PDMMEDIATYPE_FLOPPY_360, + /** 720KB 3 1/2" floppy drive. */ + PDMMEDIATYPE_FLOPPY_720, + /** 1.2MB 5 1/4" floppy drive. */ + PDMMEDIATYPE_FLOPPY_1_20, + /** 1.44MB 3 1/2" floppy drive. */ + PDMMEDIATYPE_FLOPPY_1_44, + /** 2.88MB 3 1/2" floppy drive. */ + PDMMEDIATYPE_FLOPPY_2_88, + /** Fake drive that can take up to 15.6 MB images. + * C=255, H=2, S=63. */ + PDMMEDIATYPE_FLOPPY_FAKE_15_6, + /** Fake drive that can take up to 63.5 MB images. + * C=255, H=2, S=255. */ + PDMMEDIATYPE_FLOPPY_FAKE_63_5, + /** CDROM drive. */ + PDMMEDIATYPE_CDROM, + /** DVD drive. */ + PDMMEDIATYPE_DVD, + /** Hard disk drive. */ + PDMMEDIATYPE_HARD_DISK +} PDMMEDIATYPE; + +/** Check if the given block type is a floppy. */ +#define PDMMEDIATYPE_IS_FLOPPY(a_enmType) ( (a_enmType) >= PDMMEDIATYPE_FLOPPY_360 && (a_enmType) <= PDMMEDIATYPE_FLOPPY_2_88 ) + +/** + * Raw command data transfer direction. + */ +typedef enum PDMMEDIATXDIR +{ + PDMMEDIATXDIR_NONE = 0, + PDMMEDIATXDIR_FROM_DEVICE, + PDMMEDIATXDIR_TO_DEVICE +} PDMMEDIATXDIR; + +/** + * Media geometry structure. + */ +typedef struct PDMMEDIAGEOMETRY +{ + /** Number of cylinders. */ + uint32_t cCylinders; + /** Number of heads. */ + uint32_t cHeads; + /** Number of sectors. */ + uint32_t cSectors; +} PDMMEDIAGEOMETRY; + +/** Pointer to media geometry structure. */ +typedef PDMMEDIAGEOMETRY *PPDMMEDIAGEOMETRY; +/** Pointer to constant media geometry structure. */ +typedef const PDMMEDIAGEOMETRY *PCPDMMEDIAGEOMETRY; + +/** Pointer to a media port interface. */ +typedef struct PDMIMEDIAPORT *PPDMIMEDIAPORT; +/** + * Media port interface (down). + */ +typedef struct PDMIMEDIAPORT +{ + /** + * Returns the storage controller name, instance and LUN of the attached medium. + * + * @returns VBox status. + * @param pInterface Pointer to this interface. + * @param ppcszController Where to store the name of the storage controller. + * @param piInstance Where to store the instance number of the controller. + * @param piLUN Where to store the LUN of the attached device. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryDeviceLocation, (PPDMIMEDIAPORT pInterface, const char **ppcszController, + uint32_t *piInstance, uint32_t *piLUN)); + + + /** + * Queries the vendor and product ID and revision to report for INQUIRY commands in underlying devices, optional. + * + * @returns VBox status code. + * @param pInterface Pointer to this interface. + * @param ppszVendorId Where to store the pointer to the vendor ID string to report. + * @param ppszProductId Where to store the pointer to the product ID string to report. + * @param ppszRevision Where to store the pointer to the revision string to report. + * + * @note The strings for the inquiry data are stored in the storage controller rather than in the device + * because if device attachments change (virtual CD/DVD drive versus host drive) there is currently no + * way to keep the INQUIRY data in extradata keys without causing trouble when the attachment is changed. + * Also Main currently doesn't has any settings for the attachment to store such information in the settings + * properly. Last reason (but not the most important one) is to stay compatible with older versions + * where the drive emulation was in AHCI but it now uses VSCSI and the settings overwrite should still work. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryScsiInqStrings, (PPDMIMEDIAPORT pInterface, const char **ppszVendorId, + const char **ppszProductId, const char **ppszRevision)); + +} PDMIMEDIAPORT; +/** PDMIMEDIAPORT interface ID. */ +#define PDMIMEDIAPORT_IID "77180ab8-6485-454f-b440-efca322b7bd7" + +/** Pointer to a media interface. */ +typedef struct PDMIMEDIA *PPDMIMEDIA; +/** + * Media interface (up). + * Pairs with PDMIMEDIAPORT. + */ +typedef struct PDMIMEDIA +{ + /** + * Read bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start reading from. The offset must be aligned to a sector boundary. + * @param pvBuf Where to store the read bits. + * @param cbRead Number of bytes to read. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnRead,(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead)); + + /** + * Read bits - version for DevPcBios. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start reading from. The offset must be aligned to a sector boundary. + * @param pvBuf Where to store the read bits. + * @param cbRead Number of bytes to read. Must be aligned to a sector boundary. + * @thread Any thread. + * + * @note: Special version of pfnRead which doesn't try to suspend the VM when the DEKs for encrypted disks + * are missing but just returns an error. + */ + DECLR3CALLBACKMEMBER(int, pfnReadPcBios,(PPDMIMEDIA pInterface, uint64_t off, void *pvBuf, size_t cbRead)); + + /** + * Write bits. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param off Offset to start writing at. The offset must be aligned to a sector boundary. + * @param pvBuf Where to store the write bits. + * @param cbWrite Number of bytes to write. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnWrite,(PPDMIMEDIA pInterface, uint64_t off, const void *pvBuf, size_t cbWrite)); + + /** + * Make sure that the bits written are actually on the storage medium. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnFlush,(PPDMIMEDIA pInterface)); + + /** + * Send a raw command to the underlying device (CDROM). + * This method is optional (i.e. the function pointer may be NULL). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pbCdb The command to process. + * @param cbCdb The length of the command in bytes. + * @param enmTxDir Direction of transfer. + * @param pvBuf Pointer tp the transfer buffer. + * @param pcbBuf Size of the transfer buffer. + * @param pabSense Status of the command (when return value is VERR_DEV_IO_ERROR). + * @param cbSense Size of the sense buffer in bytes. + * @param cTimeoutMillies Command timeout in milliseconds. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSendCmd,(PPDMIMEDIA pInterface, const uint8_t *pbCdb, size_t cbCdb, + PDMMEDIATXDIR enmTxDir, void *pvBuf, uint32_t *pcbBuf, + uint8_t *pabSense, size_t cbSense, uint32_t cTimeoutMillies)); + + /** + * Merge medium contents during a live snapshot deletion. All details + * must have been configured through CFGM or this will fail. + * This method is optional (i.e. the function pointer may be NULL). + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfnProgress Function pointer for progress notification. + * @param pvUser Opaque user data for progress notification. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnMerge,(PPDMIMEDIA pInterface, PFNSIMPLEPROGRESS pfnProgress, void *pvUser)); + + /** + * Sets the secret key retrieval interface to use to get secret keys. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pIfSecKey The secret key interface to use. + * Use NULL to clear the currently set interface and clear all secret + * keys from the user. + * @param pIfSecKeyHlp The secret key helper interface to use. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnSetSecKeyIf,(PPDMIMEDIA pInterface, struct PDMISECKEY *pIfSecKey, + struct PDMISECKEYHLP *pIfSecKeyHlp)); + + /** + * Get the media size in bytes. + * + * @returns Media size in bytes. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint64_t, pfnGetSize,(PPDMIMEDIA pInterface)); + + /** + * Gets the media sector size in bytes. + * + * @returns Media sector size in bytes. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetSectorSize,(PPDMIMEDIA pInterface)); + + /** + * Check if the media is readonly or not. + * + * @returns true if readonly. + * @returns false if read/write. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsReadOnly,(PPDMIMEDIA pInterface)); + + /** + * Returns whether the medium should be marked as rotational or not. + * + * @returns true if non rotating medium. + * @returns false if rotating medium. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsNonRotational,(PPDMIMEDIA pInterface)); + + /** + * Get stored media geometry (physical CHS, PCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnBiosSetPCHSGeometry() yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pPCHSGeometry Pointer to PCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBiosGetPCHSGeometry,(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pPCHSGeometry)); + + /** + * Store the media geometry (physical CHS, PCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pPCHSGeometry Pointer to PCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBiosSetPCHSGeometry,(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pPCHSGeometry)); + + /** + * Get stored media geometry (logical CHS, LCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @returns VERR_PDM_GEOMETRY_NOT_SET if the geometry hasn't been set using pfnBiosSetLCHSGeometry() yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pLCHSGeometry Pointer to LCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBiosGetLCHSGeometry,(PPDMIMEDIA pInterface, PPDMMEDIAGEOMETRY pLCHSGeometry)); + + /** + * Store the media geometry (logical CHS, LCHS) - BIOS property. + * This is an optional feature of a media. + * + * @returns VBox status code. + * @returns VERR_NOT_IMPLEMENTED if the media doesn't support storing the geometry. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pLCHSGeometry Pointer to LCHS geometry (cylinders/heads/sectors). + * @remark This has no influence on the read/write operations. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnBiosSetLCHSGeometry,(PPDMIMEDIA pInterface, PCPDMMEDIAGEOMETRY pLCHSGeometry)); + + /** + * Checks if the device should be visible to the BIOS or not. + * + * @returns true if the device is visible to the BIOS. + * @returns false if the device is not visible to the BIOS. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(bool, pfnBiosIsVisible,(PPDMIMEDIA pInterface)); + + /** + * Gets the media type. + * + * @returns media type. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(PDMMEDIATYPE, pfnGetType,(PPDMIMEDIA pInterface)); + + /** + * Gets the UUID of the media drive. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pUuid Where to store the UUID on success. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnGetUuid,(PPDMIMEDIA pInterface, PRTUUID pUuid)); + + /** + * Discards the given range. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param paRanges Array of ranges to discard. + * @param cRanges Number of entries in the array. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnDiscard,(PPDMIMEDIA pInterface, PCRTRANGE paRanges, unsigned cRanges)); + + /** + * Returns the number of regions for the medium. + * + * @returns Number of regions. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetRegionCount,(PPDMIMEDIA pInterface)); + + /** + * Queries the properties for the given region. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the region index is not known. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param uRegion The region index to query the properties of. + * @param pu64LbaStart Where to store the starting LBA for the region on success. + * @param pcBlocks Where to store the number of blocks for the region on success. + * @param pcbBlock Where to store the size of one block in bytes on success. + * @param penmDataForm WHere to store the data form for the region on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryRegionProperties,(PPDMIMEDIA pInterface, uint32_t uRegion, uint64_t *pu64LbaStart, + uint64_t *pcBlocks, uint64_t *pcbBlock, + PVDREGIONDATAFORM penmDataForm)); + + /** + * Queries the properties for the region covering the given LBA. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the region index is not known. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param u64LbaStart Where to store the starting LBA for the region on success. + * @param puRegion Where to store the region number on success. + * @param pcBlocks Where to store the number of blocks left in this region starting from the given LBA. + * @param pcbBlock Where to store the size of one block in bytes on success. + * @param penmDataForm WHere to store the data form for the region on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryRegionPropertiesForLba,(PPDMIMEDIA pInterface, uint64_t u64LbaStart, + uint32_t *puRegion, uint64_t *pcBlocks, + uint64_t *pcbBlock, PVDREGIONDATAFORM penmDataForm)); + +} PDMIMEDIA; +/** PDMIMEDIA interface ID. */ +#define PDMIMEDIA_IID "8ec68c48-dd20-4430-8386-f0d628a5aca6" + + +/** + * Opaque I/O request handle. + * + * The specific content depends on the driver implementing this interface. + */ +typedef struct PDMMEDIAEXIOREQINT *PDMMEDIAEXIOREQ; +/** Pointer to an I/O request handle. */ +typedef PDMMEDIAEXIOREQ *PPDMMEDIAEXIOREQ; +/** NIL I/O request handle. */ +#define NIL_PDMMEDIAEXIOREQ ((PDMMEDIAEXIOREQ)0) + +/** A I/O request ID. */ +typedef uint64_t PDMMEDIAEXIOREQID; + +/** + * I/O Request Type. + */ +typedef enum PDMMEDIAEXIOREQTYPE +{ + /** Invalid tpe. */ + PDMMEDIAEXIOREQTYPE_INVALID = 0, + /** Flush request. */ + PDMMEDIAEXIOREQTYPE_FLUSH, + /** Write request. */ + PDMMEDIAEXIOREQTYPE_WRITE, + /** Read request. */ + PDMMEDIAEXIOREQTYPE_READ, + /** Discard request. */ + PDMMEDIAEXIOREQTYPE_DISCARD, + /** SCSI command. */ + PDMMEDIAEXIOREQTYPE_SCSI +} PDMMEDIAEXIOREQTYPE; +/** Pointer to a I/O request type. */ +typedef PDMMEDIAEXIOREQTYPE *PPDMMEDIAEXIOREQTYPE; + +/** + * Data direction for raw SCSI commands. + */ +typedef enum PDMMEDIAEXIOREQSCSITXDIR +{ + /** Invalid data direction. */ + PDMMEDIAEXIOREQSCSITXDIR_INVALID = 0, + /** Direction is unknown. */ + PDMMEDIAEXIOREQSCSITXDIR_UNKNOWN, + /** Direction is from device to host. */ + PDMMEDIAEXIOREQSCSITXDIR_FROM_DEVICE, + /** Direction is from host to device. */ + PDMMEDIAEXIOREQSCSITXDIR_TO_DEVICE, + /** No data transfer associated with this request. */ + PDMMEDIAEXIOREQSCSITXDIR_NONE, + /** 32bit hack. */ + PDMMEDIAEXIOREQSCSITXDIR_32BIT_HACK = 0x7fffffff +} PDMMEDIAEXIOREQSCSITXDIR; + +/** + * I/O request state. + */ +typedef enum PDMMEDIAEXIOREQSTATE +{ + /** Invalid state. */ + PDMMEDIAEXIOREQSTATE_INVALID = 0, + /** The request is active and being processed. */ + PDMMEDIAEXIOREQSTATE_ACTIVE, + /** The request is suspended due to an error and no processing will take place. */ + PDMMEDIAEXIOREQSTATE_SUSPENDED, + /** 32bit hack. */ + PDMMEDIAEXIOREQSTATE_32BIT_HACK = 0x7fffffff +} PDMMEDIAEXIOREQSTATE; +/** Pointer to a I/O request state. */ +typedef PDMMEDIAEXIOREQSTATE *PPDMMEDIAEXIOREQSTATE; + +/** @name Supported feature flags + * @{ */ +/** I/O requests will execute asynchronously by default. */ +#define PDMIMEDIAEX_FEATURE_F_ASYNC RT_BIT_32(0) +/** The discard request is supported. */ +#define PDMIMEDIAEX_FEATURE_F_DISCARD RT_BIT_32(1) +/** The send raw SCSI command request is supported. */ +#define PDMIMEDIAEX_FEATURE_F_RAWSCSICMD RT_BIT_32(2) +/** Mask of valid flags. */ +#define PDMIMEDIAEX_FEATURE_F_VALID (PDMIMEDIAEX_FEATURE_F_ASYNC | PDMIMEDIAEX_FEATURE_F_DISCARD | PDMIMEDIAEX_FEATURE_F_RAWSCSICMD) +/** @} */ + +/** @name I/O request specific flags + * @{ */ +/** Default behavior (async I/O).*/ +#define PDMIMEDIAEX_F_DEFAULT (0) +/** The I/O request will be executed synchronously. */ +#define PDMIMEDIAEX_F_SYNC RT_BIT_32(0) +/** Whether to suspend the VM on a recoverable error with + * an appropriate error message (disk full, etc.). + * The request will be retried by the driver implementing the interface + * when the VM resumes the next time. However before suspending the request + * the owner of the request will be notified using the PDMMEDIAEXPORT::pfnIoReqStateChanged. + * The same goes for resuming the request after the VM was resumed. + */ +#define PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR RT_BIT_32(1) + /** Mask of valid flags. */ +#define PDMIMEDIAEX_F_VALID (PDMIMEDIAEX_F_SYNC | PDMIMEDIAEX_F_SUSPEND_ON_RECOVERABLE_ERR) +/** @} */ + +/** Pointer to an extended media notification interface. */ +typedef struct PDMIMEDIAEXPORT *PPDMIMEDIAEXPORT; + +/** + * Asynchronous version of the media interface (up). + * Pair with PDMIMEDIAEXPORT. + */ +typedef struct PDMIMEDIAEXPORT +{ + /** + * Notify completion of a I/O request. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param rcReq IPRT Status code of the completed request. + * VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCompleteNotify, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, int rcReq)); + + /** + * Copy data from the memory buffer of the caller to the callees memory buffer for the given request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOBUF_OVERFLOW if there is not enough room to store the data. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param offDst The destination offset from the start to write the data to. + * @param pSgBuf The S/G buffer to read the data from. + * @param cbCopy How many bytes to copy. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCopyFromBuf, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, uint32_t offDst, PRTSGBUF pSgBuf, + size_t cbCopy)); + + /** + * Copy data to the memory buffer of the caller from the callees memory buffer for the given request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOBUF_UNDERRUN if there is not enough data to copy from the buffer. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param offSrc The offset from the start of the buffer to read the data from. + * @param pSgBuf The S/G buffer to write the data to. + * @param cbCopy How many bytes to copy. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCopyToBuf, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, uint32_t offSrc, PRTSGBUF pSgBuf, + size_t cbCopy)); + + /** + * Queries a pointer to the memory buffer for the request from the drive/device above. + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if this is not supported for this request. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param ppvBuf Where to store the pointer to the guest buffer on success. + * @param pcbBuf Where to store the size of the buffer on success. + * + * @note This is an optional feature of the entity implementing this interface to avoid overhead + * by copying the data between buffers. If NULL it is not supported at all and the caller + * has to resort to PDMIMEDIAEXPORT::pfnIoReqCopyToBuf and PDMIMEDIAEXPORT::pfnIoReqCopyFromBuf. + * The same holds when VERR_NOT_SUPPORTED is returned. + * + * On the upside the caller of this interface might not call this method at all and just + * use the before mentioned methods to copy the data between the buffers. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQueryBuf, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, void **ppvBuf, size_t *pcbBuf)); + + /** + * Queries the specified amount of ranges to discard from the callee for the given I/O request. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param idxRangeStart The range index to start with. + * @param cRanges How man ranges can be stored in the provided array. + * @param paRanges Where to store the ranges on success. + * @param *pcRanges Where to store the number of ranges copied over on success. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQueryDiscardRanges, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, uint32_t idxRangeStart, + uint32_t cRanges, PRTRANGE paRanges, + uint32_t *pcRanges)); + + /** + * Notify the request owner about a state change for the request. + * + * @returns nothing. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request handle. + * @param pvIoReqAlloc The allocator specific memory for this request. + * @param enmState The new state of the request. + */ + DECLR3CALLBACKMEMBER(void, pfnIoReqStateChanged, (PPDMIMEDIAEXPORT pInterface, PDMMEDIAEXIOREQ hIoReq, + void *pvIoReqAlloc, PDMMEDIAEXIOREQSTATE enmState)); + + /** + * Informs the device that the underlying medium was ejected. + * + * @returns nothing. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(void, pfnMediumEjected, (PPDMIMEDIAEXPORT pInterface)); + +} PDMIMEDIAEXPORT; + +/** PDMIMEDIAAEXPORT interface ID. */ +#define PDMIMEDIAEXPORT_IID "0ae2e534-6c28-41d6-9a88-7f88f2cb2ff8" + + +/** Pointer to an extended media interface. */ +typedef struct PDMIMEDIAEX *PPDMIMEDIAEX; + +/** + * Extended version of PDMIMEDIA (down). + * Pair with PDMIMEDIAEXPORT. + */ +typedef struct PDMIMEDIAEX +{ + /** + * Queries the features supported by the entity implementing this interface. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pfFeatures Where to store the supported feature flags on success. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryFeatures, (PPDMIMEDIAEX pInterface, uint32_t *pfFeatures)); + + /** + * Notifies the driver below that the device received a suspend notification. + * + * @returns nothing. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * + * @note this is required because the PDM drivers in the storage area usually get their suspend notification + * only after the device finished suspending. For some cases it is useful for the driver to know + * as early as possible that a suspend is in progress to stop issuing deferred requests or other things. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifySuspend, (PPDMIMEDIAEX pInterface)); + + /** + * Sets the size of the allocator specific memory for a I/O request. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param cbIoReqAlloc The size of the allocator specific memory in bytes. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqAllocSizeSet, (PPDMIMEDIAEX pInterface, size_t cbIoReqAlloc)); + + /** + * Allocates a new I/O request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQID_CONFLICT if the ID belongs to a still active request. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param phIoReq Where to store the handle to the new I/O request on success. + * @param ppvIoReqAlloc Where to store the pointer to the allocator specific memory on success. + * NULL if the memory size was not set or set to 0. + * @param uIoReqId A custom request ID which can be used to cancel the request. + * @param fFlags A combination of PDMIMEDIAEX_F_* flags. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqAlloc, (PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc, + PDMMEDIAEXIOREQID uIoReqId, uint32_t fFlags)); + + /** + * Frees a given I/O request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE if the given request is still active. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to free. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqFree, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)); + + /** + * Queries the residual amount of data not transfered when the request completed. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE has not completed yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request. + * @param pcbResidual Where to store the amount of resdiual data in bytes. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQueryResidual, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbResidual)); + + /** + * Queries the residual amount of data not transfered when the request completed. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_INVALID_STATE has not completed yet. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request. + * @param pcbXfer Where to store the amount of resdiual data in bytes. + * @thread Any thread. + * + * @note For simple read/write requests this returns the amount to read/write as given to the + * PDMIMEDIAEX::pfnIoReqRead or PDMIMEDIAEX::pfnIoReqWrite call. + * For SCSI commands this returns the transfer size as given in the provided CDB. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQueryXferSize, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, size_t *pcbXfer)); + + /** + * Cancels all I/O active requests. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCancelAll, (PPDMIMEDIAEX pInterface)); + + /** + * Cancels a I/O request identified by the ID. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQID_NOT_FOUND if the given ID could not be found in the active request list. + * (The request has either completed already or an invalid ID was given). + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param uIoReqId The I/O request ID + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqCancel, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQID uIoReqId)); + + /** + * Start a reading request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @retval VINF_SUCCESS if the request completed successfully. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the read with. + * @param off Offset to start reading from. Must be aligned to a sector boundary. + * @param cbRead Number of bytes to read. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqRead, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbRead)); + + /** + * Start a writing request. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @retval VINF_SUCCESS if the request completed successfully. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the write with. + * @param off Offset to start reading from. Must be aligned to a sector boundary. + * @param cbWrite Number of bytes to write. Must be aligned to a sector boundary. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqWrite, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, uint64_t off, size_t cbWrite)); + + /** + * Flush everything to disk. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @retval VINF_SUCCESS if the request completed successfully. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the flush with. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqFlush, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq)); + + /** + * Discards the given range. + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @retval VINF_SUCCESS if the request completed successfully. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the discard with. + * @param cRangesMax The maximum number of ranges this request has associated, this must not be accurate + * but can actually be bigger than the amount of ranges actually available. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqDiscard, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, unsigned cRangesMax)); + + /** + * Send a raw command to the underlying device (CDROM). + * + * @returns VBox status code. + * @retval VERR_PDM_MEDIAEX_IOREQ_CANCELED if the request was canceled by a call to + * PDMIMEDIAEX::pfnIoReqCancel. + * @retval VINF_PDM_MEDIAEX_IOREQ_IN_PROGRESS if the request was successfully submitted but is still in progress. + * Completion will be notified through PDMIMEDIAEXPORT::pfnIoReqCompleteNotify with the appropriate status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The I/O request to associate the command with. + * @param uLun The LUN the command is for. + * @param pbCdb The SCSI CDB containing the command. + * @param cbCdb Size of the CDB in bytes. + * @param enmTxDir Direction of transfer. + * @param penmTxDirRet Where to store the transfer direction as parsed from the CDB, optional. + * @param cbBuf Size of the transfer buffer. + * @param pabSense Where to store the optional sense key. + * @param cbSense Size of the sense key buffer. + * @param pcbSenseRet Where to store the amount of sense data written, optional. + * @param pu8ScsiSts Where to store the SCSI status on success. + * @param cTimeoutMillies Command timeout in milliseconds. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqSendScsiCmd,(PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, + uint32_t uLun, const uint8_t *pbCdb, size_t cbCdb, + PDMMEDIAEXIOREQSCSITXDIR enmTxDir, PDMMEDIAEXIOREQSCSITXDIR *penmTxDirRet, + size_t cbBuf, uint8_t *pabSense, size_t cbSense, size_t *pcbSenseRet, + uint8_t *pu8ScsiSts, uint32_t cTimeoutMillies)); + + /** + * Returns the number of active I/O requests. + * + * @returns Number of active I/O requests. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnIoReqGetActiveCount, (PPDMIMEDIAEX pInterface)); + + /** + * Returns the number of suspended requests. + * + * @returns Number of suspended I/O requests. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnIoReqGetSuspendedCount, (PPDMIMEDIAEX pInterface)); + + /** + * Gets the first suspended request handle. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if there is no suspended request waiting. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param phIoReq Where to store the request handle on success. + * @param ppvIoReqAlloc Where to store the pointer to the allocator specific memory on success. + * @thread Any thread. + * + * @note This should only be called when the VM is suspended to make sure the request doesn't suddenly + * changes into the active state again. The only purpose for this method for now is to make saving the state + * possible without breaking saved state versions. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQuerySuspendedStart, (PPDMIMEDIAEX pInterface, PPDMMEDIAEXIOREQ phIoReq, void **ppvIoReqAlloc)); + + /** + * Gets the next suspended request handle. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if there is no suspended request waiting. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param hIoReq The current request handle. + * @param phIoReqNext Where to store the request handle on success. + * @param ppvIoReqAllocNext Where to store the pointer to the allocator specific memory on success. + * @thread Any thread. + * + * @note This should only be called when the VM is suspended to make sure the request doesn't suddenly + * changes into the active state again. The only purpose for this method for now is to make saving the state + * possible without breaking saved state versions. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqQuerySuspendedNext, (PPDMIMEDIAEX pInterface, PDMMEDIAEXIOREQ hIoReq, + PPDMMEDIAEXIOREQ phIoReqNext, void **ppvIoReqAllocNext)); + + /** + * Saves the given I/O request state in the provided saved state unit. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pSSM The SSM handle. + * @param hIoReq The request handle to save. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqSuspendedSave, (PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)); + + /** + * Load a suspended request state from the given saved state unit and link it into the suspended list. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param pSSM The SSM handle to read the state from. + * @param hIoReq The request handle to load the state into. + */ + DECLR3CALLBACKMEMBER(int, pfnIoReqSuspendedLoad, (PPDMIMEDIAEX pInterface, PSSMHANDLE pSSM, PDMMEDIAEXIOREQ hIoReq)); + +} PDMIMEDIAEX; +/** PDMIMEDIAEX interface ID. */ +#define PDMIMEDIAEX_IID "29c9e82b-934e-45c5-bb84-0d871c3cc9dd" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmstorageifs_h */ diff --git a/include/VBox/vmm/pdmtask.h b/include/VBox/vmm/pdmtask.h new file mode 100644 index 00000000..d3b48e99 --- /dev/null +++ b/include/VBox/vmm/pdmtask.h @@ -0,0 +1,162 @@ +/** @file + * PDM - Pluggable Device Manager, Tasks. + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmtask_h +#define VBOX_INCLUDED_vmm_pdmtask_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_task The PDM Tasks API + * @ingroup grp_pdm + * + * A task is a predefined asynchronous procedure call that can be triggered from + * any context. + * + * @{ + */ + +/** PDM task handle. */ +typedef uint64_t PDMTASKHANDLE; +/** NIL PDM task handle. */ +#define NIL_PDMTASKHANDLE UINT64_MAX + + +/** + * Task worker callback for devices. + * + * @param pDevIns The device instance. + * @param pvUser The user parameter. + * @thread Task worker thread. + * @remarks The device critical section will NOT be entered before calling the + * callback. No other locks will be held either. + */ +typedef DECLCALLBACKTYPE(void, FNPDMTASKDEV,(PPDMDEVINS pDevIns, void *pvUser)); +/** Pointer to a FNPDMTASKDEV(). */ +typedef FNPDMTASKDEV *PFNPDMTASKDEV; + +/** + * Task worker callback for drivers. + * + * @param pDrvIns The driver instance. + * @param pvUser The user parameter. + * @thread Task worker thread. + * @remarks No other locks will be held. + */ +typedef DECLCALLBACKTYPE(void, FNPDMTASKDRV,(PPDMDRVINS pDrvIns, void *pvUser)); +/** Pointer to a FNPDMTASKDRV(). */ +typedef FNPDMTASKDRV *PFNPDMTASKDRV; + +/** + * Task worker callback for USB devices. + * + * @param pUsbIns The USB device instance. + * @param pvUser The user parameter. + * @thread Task worker thread. + * @remarks No other locks will be held. + */ +typedef DECLCALLBACKTYPE(void, FNPDMTASKUSB,(PPDMUSBINS pUsbIns, void *pvUser)); +/** Pointer to a FNPDMTASKUSB(). */ +typedef FNPDMTASKUSB *PFNPDMTASKUSB; + +/** + * Task worker callback for internal components. + * + * @param pVM The cross context VM structure. + * @param pvUser The user parameter. + * @thread Task worker thread. + * @remarks No other locks will be held. + */ +typedef DECLCALLBACKTYPE(void, FNPDMTASKINT,(PVM pVM, void *pvUser)); +/** Pointer to a FNPDMTASKINT(). */ +typedef FNPDMTASKINT *PFNPDMTASKINT; + + +/** @name PDMTASK_F_XXX - Task creation flags. + * @{ */ +/** Create a ring-0 triggerable task. */ +#define PDMTASK_F_R0 RT_BIT_32(0) +/** Create a raw-mode triggerable task. */ +#define PDMTASK_F_RC RT_BIT_32(1) +/** Create a ring-0 and raw-mode triggerable task. */ +#define PDMTASK_F_RZ (PDMTASK_F_R0 | PDMTASK_F_RC) +/** Valid flags. */ +#define PDMTASK_F_VALID_MASK UINT32_C(0x00000003) +/** @} */ + +#ifdef VBOX_IN_VMM +/** + * Task owner type. + */ +typedef enum PDMTASKTYPE +{ + /** Invalid zero value. */ + PDMTASKTYPE_INVALID = 0, + /** Device consumer. */ + PDMTASKTYPE_DEV, + /** Driver consumer. */ + PDMTASKTYPE_DRV, + /** USB device consumer. */ + PDMTASKTYPE_USB, + /** Internal consumer. */ + PDMTASKTYPE_INTERNAL, + /** End of valid values. */ + PDMTASKTYPE_END, + /** Typical 32-bit type blowup. */ + PDMTASKTYPE_32BIT_HACK = 0x7fffffff +} PDMTASKTYPE; + +VMMR3_INT_DECL(int) PDMR3TaskCreate(PVM pVM, uint32_t fFlags, const char *pszName, PDMTASKTYPE enmType, void *pvOwner, + PFNRT pfnCallback, void *pvUser, PDMTASKHANDLE *phTask); +VMMR3_INT_DECL(int) PDMR3TaskCreateInternal(PVM pVM, uint32_t fFlags, const char *pszName, + PFNPDMTASKINT pfnCallback, void *pvUser, PDMTASKHANDLE *phTask); +VMMR3_INT_DECL(int) PDMR3TaskDestroyAllByOwner(PVM pVM, PDMTASKTYPE enmType, void *pvOwner); +VMMR3_INT_DECL(int) PDMR3TaskDestroySpecific(PVM pVM, PDMTASKTYPE enmType, void *pvOwner, PDMTASKHANDLE hTask); +VMMR3_INT_DECL(int) PDMR3TaskDestroyInternal(PVM pVM, PDMTASKHANDLE hTask); + +VMM_INT_DECL(int) PDMTaskTrigger(PVMCC pVM, PDMTASKTYPE enmType, RTR3PTR pvOwner, PDMTASKHANDLE hTask); +VMM_INT_DECL(int) PDMTaskTriggerInternal(PVMCC pVM, PDMTASKHANDLE hTask); +#endif /* VBOX_IN_VMM */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmtask_h */ + diff --git a/include/VBox/vmm/pdmthread.h b/include/VBox/vmm/pdmthread.h new file mode 100644 index 00000000..1163f163 --- /dev/null +++ b/include/VBox/vmm/pdmthread.h @@ -0,0 +1,311 @@ +/** @file + * PDM - Pluggable Device Manager, Threads. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmthread_h +#define VBOX_INCLUDED_vmm_pdmthread_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#ifdef IN_RING3 +# include +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_thread The PDM Threads API + * @ingroup grp_pdm + * @{ + */ + +/** + * The thread state + */ +typedef enum PDMTHREADSTATE +{ + /** The usual invalid 0 entry. */ + PDMTHREADSTATE_INVALID = 0, + /** The thread is initializing. + * Prev state: none + * Next state: suspended, terminating (error) */ + PDMTHREADSTATE_INITIALIZING, + /** The thread has been asked to suspend. + * Prev state: running + * Next state: suspended */ + PDMTHREADSTATE_SUSPENDING, + /** The thread is supended. + * Prev state: suspending, initializing + * Next state: resuming, terminated. */ + PDMTHREADSTATE_SUSPENDED, + /** The thread is active. + * Prev state: suspended + * Next state: running, terminating. */ + PDMTHREADSTATE_RESUMING, + /** The thread is active. + * Prev state: resuming + * Next state: suspending, terminating. */ + PDMTHREADSTATE_RUNNING, + /** The thread has been asked to terminate. + * Prev state: initializing, suspended, resuming, running + * Next state: terminated. */ + PDMTHREADSTATE_TERMINATING, + /** The thread is terminating / has terminated. + * Prev state: terminating + * Next state: none */ + PDMTHREADSTATE_TERMINATED, + /** The usual 32-bit hack. */ + PDMTHREADSTATE_32BIT_HACK = 0x7fffffff +} PDMTHREADSTATE; + +/** A pointer to a PDM thread. */ +typedef R3PTRTYPE(struct PDMTHREAD *) PPDMTHREAD; +/** A pointer to a pointer to a PDM thread. */ +typedef PPDMTHREAD *PPPDMTHREAD; + +/** + * PDM thread, device variation. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADDEV,(PPDMDEVINS pDevIns, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADDEV(). */ +typedef FNPDMTHREADDEV *PFNPDMTHREADDEV; + +/** + * PDM thread, USB device variation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADUSB,(PPDMUSBINS pUsbIns, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADUSB(). */ +typedef FNPDMTHREADUSB *PFNPDMTHREADUSB; + +/** + * PDM thread, driver variation. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADDRV,(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADDRV(). */ +typedef FNPDMTHREADDRV *PFNPDMTHREADDRV; + +/** + * PDM thread, driver variation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADINT,(PVM pVM, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADINT(). */ +typedef FNPDMTHREADINT *PFNPDMTHREADINT; + +/** + * PDM thread, driver variation. + * + * @returns VBox status code. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADEXT(PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADEXT(). */ +typedef FNPDMTHREADEXT *PFNPDMTHREADEXT; + + + +/** + * PDM thread wakeup call, device variation. + * + * @returns VBox status code. + * @param pDevIns The device instance. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADWAKEUPDEV,(PPDMDEVINS pDevIns, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADDEV(). */ +typedef FNPDMTHREADWAKEUPDEV *PFNPDMTHREADWAKEUPDEV; + +/** + * PDM thread wakeup call, device variation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADWAKEUPUSB,(PPDMUSBINS pUsbIns, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADUSB(). */ +typedef FNPDMTHREADWAKEUPUSB *PFNPDMTHREADWAKEUPUSB; + +/** + * PDM thread wakeup call, driver variation. + * + * @returns VBox status code. + * @param pDrvIns The driver instance. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADWAKEUPDRV,(PPDMDRVINS pDrvIns, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADDRV(). */ +typedef FNPDMTHREADWAKEUPDRV *PFNPDMTHREADWAKEUPDRV; + +/** + * PDM thread wakeup call, internal variation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pThread The PDM thread data. + */ +typedef DECLCALLBACKTYPE(int, FNPDMTHREADWAKEUPINT,(PVM pVM, PPDMTHREAD pThread)); +/** Pointer to a FNPDMTHREADWAKEUPINT(). */ +typedef FNPDMTHREADWAKEUPINT *PFNPDMTHREADWAKEUPINT; + +/** + * PDM thread wakeup call, external variation. + * + * @returns VBox status code. + * @param pThread The PDM thread data. + */ +typedef int FNPDMTHREADWAKEUPEXT(PPDMTHREAD pThread); +/** Pointer to a FNPDMTHREADEXT(). */ +typedef FNPDMTHREADWAKEUPEXT *PFNPDMTHREADWAKEUPEXT; + + +/** + * PDM Thread instance data. + */ +typedef struct PDMTHREAD +{ + /** PDMTHREAD_VERSION. */ + uint32_t u32Version; + /** The thread state. */ + PDMTHREADSTATE volatile enmState; + /** The thread handle. */ + RTTHREAD Thread; + /** The user parameter. */ + R3PTRTYPE(void *) pvUser; + /** Data specific to the kind of thread. + * This should really be in PDMTHREADINT, but is placed here because of the + * function pointer typedefs. So, don't touch these, please. + */ + union + { + /** PDMTHREADTYPE_DEVICE data. */ + struct + { + /** The device instance. */ + PPDMDEVINSR3 pDevIns; + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADDEV) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPDEV) pfnWakeUp; + } Dev; + + /** PDMTHREADTYPE_USB data. */ + struct + { + /** The device instance. */ + PPDMUSBINS pUsbIns; + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADUSB) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPUSB) pfnWakeUp; + } Usb; + + /** PDMTHREADTYPE_DRIVER data. */ + struct + { + /** The driver instance. */ + R3PTRTYPE(PPDMDRVINS) pDrvIns; + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADDRV) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPDRV) pfnWakeUp; + } Drv; + + /** PDMTHREADTYPE_INTERNAL data. */ + struct + { + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADINT) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPINT) pfnWakeUp; + } Int; + + /** PDMTHREADTYPE_EXTERNAL data. */ + struct + { + /** The thread function. */ + R3PTRTYPE(PFNPDMTHREADEXT) pfnThread; + /** Thread. */ + R3PTRTYPE(PFNPDMTHREADWAKEUPEXT) pfnWakeUp; + } Ext; + } u; + + /** Internal data. */ + union + { +#ifdef PDMTHREADINT_DECLARED + PDMTHREADINT s; +#endif + uint8_t padding[64]; + } Internal; +} PDMTHREAD; + +/** PDMTHREAD::u32Version value. */ +#define PDMTHREAD_VERSION PDM_VERSION_MAKE(0xefff, 1, 0) + +#ifdef IN_RING3 +VMMR3DECL(int) PDMR3ThreadCreate(PVM pVM, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADINT pfnThread, + PFNPDMTHREADWAKEUPINT pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName); +VMMR3DECL(int) PDMR3ThreadCreateExternal(PVM pVM, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADEXT pfnThread, + PFNPDMTHREADWAKEUPEXT pfnWakeUp, size_t cbStack, RTTHREADTYPE enmType, const char *pszName); +VMMR3DECL(int) PDMR3ThreadDestroy(PPDMTHREAD pThread, int *pRcThread); +VMMR3DECL(int) PDMR3ThreadIAmSuspending(PPDMTHREAD pThread); +VMMR3DECL(int) PDMR3ThreadIAmRunning(PPDMTHREAD pThread); +VMMR3DECL(int) PDMR3ThreadSleep(PPDMTHREAD pThread, RTMSINTERVAL cMillies); +VMMR3DECL(int) PDMR3ThreadSuspend(PPDMTHREAD pThread); +VMMR3DECL(int) PDMR3ThreadResume(PPDMTHREAD pThread); +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmthread_h */ diff --git a/include/VBox/vmm/pdmtpmifs.h b/include/VBox/vmm/pdmtpmifs.h new file mode 100644 index 00000000..22a15839 --- /dev/null +++ b/include/VBox/vmm/pdmtpmifs.h @@ -0,0 +1,163 @@ +/** @file + * PDM - Pluggable Device Manager, TPM related interfaces. + */ + +/* + * Copyright (C) 2021-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmtpmifs_h +#define VBOX_INCLUDED_vmm_pdmtpmifs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_ifs_tpm PDM TPM Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + + +/** Pointer to a TPM port interface. */ +typedef struct PDMITPMPORT *PPDMITPMPORT; +/** + * TPM port interface (down). + */ +typedef struct PDMITPMPORT +{ + /** + * @todo + */ + DECLR3CALLBACKMEMBER(int, pfnDummy, (PPDMITPMPORT pInterface)); + +} PDMITPMPORT; +/** PDMITPMPORT interface ID. */ +#define PDMITPMPORT_IID "1e57710f-f820-47ec-afa6-2713195f8f94" + + +/** + * TPM version enumeration. + */ +typedef enum TPMVERSION +{ + /** Invalid TPM version, don't use. */ + TPMVERSION_INVALID = 0, + /** TPM works according to version 1.2 of the specification. */ + TPMVERSION_1_2, + /** TPM works according to version 2.0 of the specification. */ + TPMVERSION_2_0, + /** TPM version is unknown. */ + TPMVERSION_UNKNOWN +} TPMVERSION; + + +/** Pointer to a TPM interface. */ +typedef struct PDMITPMCONNECTOR *PPDMITPMCONNECTOR; +/** + * TPM interface (up). + * Pairs with PDMITPMPORT. + */ +typedef struct PDMITPMCONNECTOR +{ + /** + * Returns the version of the TPM implemented by the driver below. + * + * @returns The TPM version. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(TPMVERSION, pfnGetVersion, (PPDMITPMCONNECTOR pInterface)); + + /** + * Returns the maximum supported locality of the driver below. + * + * @returns The maximum supported locality (0-4). + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetLocalityMax, (PPDMITPMCONNECTOR pInterface)); + + /** + * Returns the command/response buffer size of the driver below. + * + * @returns Buffer size in bytes. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetBufferSize, (PPDMITPMCONNECTOR pInterface)); + + /** + * Returns the status of the established flag. + * + * @returns Status of the established flag. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(bool, pfnGetEstablishedFlag, (PPDMITPMCONNECTOR pInterface)); + + /** + * Resets the TPM established flag. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param bLoc The locality issuing this request. + */ + DECLR3CALLBACKMEMBER(int, pfnResetEstablishedFlag, (PPDMITPMCONNECTOR pInterface, uint8_t bLoc)); + + /** + * Executes the given command. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + * @param bLoc The locality the command is issued from. + * @param pvCmd Pointer to the command data. + * @param cbCmd Size of the command in bytes. + * @param pvResp Where to store the response data. + * @param cbResp Size of the response buffer in bytes. + */ + DECLR3CALLBACKMEMBER(int, pfnCmdExec, (PPDMITPMCONNECTOR pInterface, uint8_t bLoc, const void *pvCmd, size_t cbCmd, void *pvResp, size_t cbResp)); + + /** + * Cancels the currently executed command. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface structure containing the called function pointer. + */ + DECLR3CALLBACKMEMBER(int, pfnCmdCancel, (PPDMITPMCONNECTOR pInterface)); + +} PDMITPMCONNECTOR; +/** PDMITPMCONNECTOR interface ID. */ +#define PDMITPMCONNECTOR_IID "30afefd8-c11f-4e2a-a746-424e3d99fa86" + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmtpmifs_h */ diff --git a/include/VBox/vmm/pdmusb.h b/include/VBox/vmm/pdmusb.h new file mode 100644 index 00000000..c27c33a7 --- /dev/null +++ b/include/VBox/vmm/pdmusb.h @@ -0,0 +1,1502 @@ +/** @file + * PDM - Pluggable Device Manager, USB Devices. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmusb_h +#define VBOX_INCLUDED_vmm_pdmusb_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pdm_usbdev The USB Devices API + * @ingroup grp_pdm + * @{ + */ + + +/** + * A string entry for the USB descriptor cache. + */ +typedef struct PDMUSBDESCCACHESTRING +{ + /** The string index. */ + uint8_t idx; + /** The UTF-8 representation of the string. */ + const char *psz; +} PDMUSBDESCCACHESTRING; +/** Pointer to a const string entry. */ +typedef PDMUSBDESCCACHESTRING const *PCPDMUSBDESCCACHESTRING; + + +/** + * A language entry for the USB descriptor cache. + */ +typedef struct PDMUSBDESCCACHELANG +{ + /** The language ID for the strings in this block. */ + uint16_t idLang; + /** The number of strings in the array. */ + uint16_t cStrings; + /** Pointer to an array of associated strings. + * This must be sorted in ascending order by string index as a binary lookup + * will be performed. */ + PCPDMUSBDESCCACHESTRING paStrings; +} PDMUSBDESCCACHELANG; +/** Pointer to a const language entry. */ +typedef PDMUSBDESCCACHELANG const *PCPDMUSBDESCCACHELANG; + + +/** + * USB descriptor cache. + * + * This structure is owned by the USB device but provided to the PDM/VUSB layer + * thru the PDMUSBREG::pfnGetDescriptorCache method. PDM/VUSB will use the + * information here to map addresses to endpoints, perform SET_CONFIGURATION + * requests, and optionally perform GET_DESCRIPTOR requests (see flag). + * + * Currently, only device and configuration descriptors are cached. + */ +typedef struct PDMUSBDESCCACHE +{ + /** USB device descriptor */ + PCVUSBDESCDEVICE pDevice; + /** USB Descriptor arrays (pDev->bNumConfigurations) */ + PCVUSBDESCCONFIGEX paConfigs; + /** Language IDs and their associated strings. + * This must be sorted in ascending order by language ID as a binary lookup + * will be used. */ + PCPDMUSBDESCCACHELANG paLanguages; + /** The number of entries in the array pointed to by paLanguages. */ + uint16_t cLanguages; + /** Use the cached descriptors for GET_DESCRIPTOR requests. */ + bool fUseCachedDescriptors; + /** Use the cached string descriptors. */ + bool fUseCachedStringsDescriptors; +} PDMUSBDESCCACHE; +/** Pointer to an USB descriptor cache. */ +typedef PDMUSBDESCCACHE *PPDMUSBDESCCACHE; +/** Pointer to a const USB descriptor cache. */ +typedef const PDMUSBDESCCACHE *PCPDMUSBDESCCACHE; + + +/** PDM Device Flags. + * @{ */ +/** A high-speed capable USB 2.0 device (also required to support full-speed). */ +#define PDM_USBREG_HIGHSPEED_CAPABLE RT_BIT(0) +/** Indicates that the device implements the saved state handlers. */ +#define PDM_USBREG_SAVED_STATE_SUPPORTED RT_BIT(1) +/** A SuperSpeed USB 3.0 device. */ +#define PDM_USBREG_SUPERSPEED_CAPABLE RT_BIT(2) +/** @} */ + +/** PDM USB Device Registration Structure, + * + * This structure is used when registering a device from VBoxUsbRegister() in HC Ring-3. + * The PDM will make use of this structure until the VM is destroyed. + */ +typedef struct PDMUSBREG +{ + /** Structure version. PDM_DEVREG_VERSION defines the current version. */ + uint32_t u32Version; + /** Device name. */ + char szName[32]; + /** The description of the device. The UTF-8 string pointed to shall, like this structure, + * remain unchanged from registration till VM destruction. */ + const char *pszDescription; + + /** Flags, combination of the PDM_USBREG_FLAGS_* \#defines. */ + RTUINT fFlags; + /** Maximum number of instances (per VM). */ + RTUINT cMaxInstances; + /** Size of the instance data. */ + RTUINT cbInstance; + + + /** + * Construct an USB device instance for a VM. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * If the registration structure is needed, it will be + * accessible thru pUsbDev->pReg. + * @param iInstance Instance number. Use this to figure out which registers + * and such to use. The instance number is also found in + * pUsbDev->iInstance, but since it's likely to be + * frequently used PDM passes it as parameter. + * @param pCfg Configuration node handle for the device. Use this to + * obtain the configuration of the device instance. It is + * also found in pUsbDev->pCfg, but since it is primary + * usage will in this function it is passed as a parameter. + * @param pCfgGlobal Handle to the global device configuration. Also found + * in pUsbDev->pCfgGlobal. + * @remarks This callback is required. + */ + DECLR3CALLBACKMEMBER(int, pfnConstruct,(PPDMUSBINS pUsbIns, int iInstance, PCFGMNODE pCfg, PCFGMNODE pCfgGlobal)); + + /** + * Destruct an USB device instance. + * + * Most VM resources are freed by the VM. This callback is provided so that any non-VM + * resources can be freed correctly. + * + * This method will be called regardless of the pfnConstruct result to avoid + * complicated failure paths. + * + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnDestruct,(PPDMUSBINS pUsbIns)); + + + /** + * Init complete notification. + * + * This can be done to do communication with other devices and other + * initialization which requires everything to be in place. + * + * @returns VBOX status code. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + * @remarks Not called when hotplugged. + */ + DECLR3CALLBACKMEMBER(int, pfnVMInitComplete,(PPDMUSBINS pUsbIns)); + + /** + * VM Power On notification. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnVMPowerOn,(PPDMUSBINS pUsbIns)); + + /** + * VM Reset notification. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnVMReset,(PPDMUSBINS pUsbIns)); + + /** + * VM Suspend notification. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnVMSuspend,(PPDMUSBINS pUsbIns)); + + /** + * VM Resume notification. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnVMResume,(PPDMUSBINS pUsbIns)); + + /** + * VM Power Off notification. + * + * This is only called when the VMR3PowerOff call is made on a running VM. This + * means that there is no notification if the VM was suspended before being + * powered of. There will also be no callback when hot plugging devices. + * + * @param pUsbIns The USB device instance data. + */ + DECLR3CALLBACKMEMBER(void, pfnVMPowerOff,(PPDMUSBINS pUsbIns)); + + /** + * Called after the constructor when attaching a device at run time. + * + * This can be used to do tasks normally assigned to pfnInitComplete and/or pfnVMPowerOn. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnHotPlugged,(PPDMUSBINS pUsbIns)); + + /** + * Called before the destructor when a device is unplugged at run time. + * + * This can be used to do tasks normally assigned to pfnVMSuspend and/or pfnVMPowerOff. + * + * @returns VBox status. + * @param pUsbIns The USB device instance data. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnHotUnplugged,(PPDMUSBINS pUsbIns)); + /** + * Driver Attach command. + * + * This is called to let the USB device attach to a driver for a specified LUN + * at runtime. This is not called during VM construction, the device constructor + * have to attach to all the available drivers. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance data. + * @param iLUN The logical unit which is being detached. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverAttach,(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)); + + /** + * Driver Detach notification. + * + * This is called when a driver is detaching itself from a LUN of the device. + * The device should adjust it's state to reflect this. + * + * @param pUsbIns The USB device instance data. + * @param iLUN The logical unit which is being detached. + * @param fFlags Flags, combination of the PDM_TACH_FLAGS_* \#defines. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(void, pfnDriverDetach,(PPDMUSBINS pUsbIns, unsigned iLUN, uint32_t fFlags)); + + /** + * Query the base interface of a logical unit. + * + * @returns VBOX status code. + * @param pUsbIns The USB device instance data. + * @param iLUN The logicial unit to query. + * @param ppBase Where to store the pointer to the base interface of the LUN. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnQueryInterface,(PPDMUSBINS pUsbIns, unsigned iLUN, PPDMIBASE *ppBase)); + + /** + * Requests the USB device to reset. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param fResetOnLinux A hint to the usb proxy. + * Don't use this unless you're the linux proxy device. + * @thread Any thread. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnUsbReset,(PPDMUSBINS pUsbIns, bool fResetOnLinux)); + + /** + * Query device and configuration descriptors for the caching and servicing + * relevant GET_DESCRIPTOR requests. + * + * @returns Pointer to the descriptor cache (read-only). + * @param pUsbIns The USB device instance. + * @remarks Mandatory. + */ + DECLR3CALLBACKMEMBER(PCPDMUSBDESCCACHE, pfnUsbGetDescriptorCache,(PPDMUSBINS pUsbIns)); + + /** + * SET_CONFIGURATION request. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param bConfigurationValue The bConfigurationValue of the new configuration. + * @param pvOldCfgDesc Internal - for the device proxy. + * @param pvOldIfState Internal - for the device proxy. + * @param pvNewCfgDesc Internal - for the device proxy. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnUsbSetConfiguration,(PPDMUSBINS pUsbIns, uint8_t bConfigurationValue, + const void *pvOldCfgDesc, const void *pvOldIfState, const void *pvNewCfgDesc)); + + /** + * SET_INTERFACE request. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param bInterfaceNumber The interface number. + * @param bAlternateSetting The alternate setting. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnUsbSetInterface,(PPDMUSBINS pUsbIns, uint8_t bInterfaceNumber, uint8_t bAlternateSetting)); + + /** + * Clears the halted state of an endpoint. (Optional) + * + * This called when VUSB sees a CLEAR_FEATURE(ENDPOINT_HALT) on request + * on the zero pipe. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param uEndpoint The endpoint to clear. + * @remarks Optional. + */ + DECLR3CALLBACKMEMBER(int, pfnUsbClearHaltedEndpoint,(PPDMUSBINS pUsbIns, unsigned uEndpoint)); + + /** + * Allocates an URB. + * + * This can be used to make use of shared user/kernel mode buffers. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param cbData The size of the data buffer. + * @param cTds The number of TDs. + * @param enmType The type of URB. + * @param ppUrb Where to store the allocated URB. + * @remarks Optional. + * @remarks Not implemented yet. + */ + DECLR3CALLBACKMEMBER(int, pfnUrbNew,(PPDMUSBINS pUsbIns, size_t cbData, size_t cTds, VUSBXFERTYPE enmType, PVUSBURB *ppUrb)); + + /** + * Queues an URB for processing. + * + * @returns VBox status code. + * @retval VINF_SUCCESS on success. + * @retval VERR_VUSB_DEVICE_NOT_ATTACHED if the device has been disconnected. + * @retval VERR_VUSB_FAILED_TO_QUEUE_URB as a general failure kind of thing. + * @retval TBD - document new stuff! + * + * @param pUsbIns The USB device instance. + * @param pUrb The URB to process. + * @remarks Mandatory. + */ + DECLR3CALLBACKMEMBER(int, pfnUrbQueue,(PPDMUSBINS pUsbIns, PVUSBURB pUrb)); + + /** + * Cancels an URB. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pUrb The URB to cancel. + * @remarks Mandatory. + */ + DECLR3CALLBACKMEMBER(int, pfnUrbCancel,(PPDMUSBINS pUsbIns, PVUSBURB pUrb)); + + /** + * Reaps an URB. + * + * @returns A ripe URB, NULL if none. + * @param pUsbIns The USB device instance. + * @param cMillies How log to wait for an URB to become ripe. + * @remarks Mandatory. + */ + DECLR3CALLBACKMEMBER(PVUSBURB, pfnUrbReap,(PPDMUSBINS pUsbIns, RTMSINTERVAL cMillies)); + + /** + * Wakes a thread waiting in pfnUrbReap. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnWakeup,(PPDMUSBINS pUsbIns)); + + /** Just some init precaution. Must be set to PDM_USBREG_VERSION. */ + uint32_t u32TheEnd; +} PDMUSBREG; +/** Pointer to a PDM USB Device Structure. */ +typedef PDMUSBREG *PPDMUSBREG; +/** Const pointer to a PDM USB Device Structure. */ +typedef PDMUSBREG const *PCPDMUSBREG; + +/** Current USBREG version number. */ +#define PDM_USBREG_VERSION PDM_VERSION_MAKE(0xeeff, 2, 0) + +/** PDM USB Device Flags. + * @{ */ +/* none yet */ +/** @} */ + + +#ifdef IN_RING3 + +/** + * PDM USB Device API. + */ +typedef struct PDMUSBHLP +{ + /** Structure version. PDM_USBHLP_VERSION defines the current version. */ + uint32_t u32Version; + + /** + * Attaches a driver (chain) to the USB device. + * + * The first call for a LUN this will serve as a registration of the LUN. The pBaseInterface and + * the pszDesc string will be registered with that LUN and kept around for PDMR3QueryUSBDeviceLun(). + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param iLun The logical unit to attach. + * @param pBaseInterface Pointer to the base interface for that LUN. (device side / down) + * @param ppBaseInterface Where to store the pointer to the base interface. (driver side / up) + * @param pszDesc Pointer to a string describing the LUN. This string must remain valid + * for the live of the device instance. + */ + DECLR3CALLBACKMEMBER(int, pfnDriverAttach,(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface, PPDMIBASE *ppBaseInterface, const char *pszDesc)); + + /** + * Assert that the current thread is the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pUsbIns The USB device instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertEMT,(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Assert that the current thread is NOT the emulation thread. + * + * @returns True if correct. + * @returns False if wrong. + * @param pUsbIns The USB device instance. + * @param pszFile Filename of the assertion location. + * @param iLine Linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + */ + DECLR3CALLBACKMEMBER(bool, pfnAssertOther,(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction)); + + /** + * Stops the VM and enters the debugger to look at the guest state. + * + * Use the PDMUsbDBGFStop() inline function with the RT_SRC_POS macro instead of + * invoking this function directly. + * + * @returns VBox status code which must be passed up to the VMM. + * @param pUsbIns The USB device instance. + * @param pszFile Filename of the assertion location. + * @param iLine The linenumber of the assertion location. + * @param pszFunction Function of the assertion location. + * @param pszFormat Message. (optional) + * @param va Message parameters. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFStopV,(PPDMUSBINS pUsbIns, const char *pszFile, unsigned iLine, const char *pszFunction, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0)); + + /** + * Register a info handler with DBGF, argv style. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pszName The identifier of the info. + * @param pszDesc The description of the info and any arguments the handler may take. + * @param pfnHandler The handler function to be called to display the info. + */ + DECLR3CALLBACKMEMBER(int, pfnDBGFInfoRegisterArgv,(PPDMUSBINS pUsbIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVUSB pfnHandler)); + + /** + * Allocate memory which is associated with current VM instance + * and automatically freed on it's destruction. + * + * @returns Pointer to allocated memory. The memory is *NOT* zero-ed. + * @param pUsbIns The USB device instance. + * @param cb Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(void *, pfnMMHeapAlloc,(PPDMUSBINS pUsbIns, size_t cb)); + + /** + * Allocate memory which is associated with current VM instance + * and automatically freed on it's destruction. The memory is ZEROed. + * + * @returns Pointer to allocated memory. The memory is *NOT* zero-ed. + * @param pUsbIns The USB device instance. + * @param cb Number of bytes to allocate. + */ + DECLR3CALLBACKMEMBER(void *, pfnMMHeapAllocZ,(PPDMUSBINS pUsbIns, size_t cb)); + + /** + * Free memory allocated with pfnMMHeapAlloc() and pfnMMHeapAllocZ(). + * + * @param pUsbIns The USB device instance. + * @param pv Pointer to the memory to free. + */ + DECLR3CALLBACKMEMBER(void, pfnMMHeapFree,(PPDMUSBINS pUsbIns, void *pv)); + + /** + * Create a queue. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param cbItem Size a queue item. + * @param cItems Number of items in the queue. + * @param cMilliesInterval Number of milliseconds between polling the queue. + * If 0 then the emulation thread will be notified whenever an item arrives. + * @param pfnCallback The consumer function. + * @param pszName The queue base name. The instance number will be + * appended automatically. + * @param ppQueue Where to store the queue handle on success. + * @thread The emulation thread. + */ + DECLR3CALLBACKMEMBER(int, pfnPDMQueueCreate,(PPDMUSBINS pUsbIns, RTUINT cbItem, RTUINT cItems, uint32_t cMilliesInterval, + PFNPDMQUEUEUSB pfnCallback, const char *pszName, PPDMQUEUE *ppQueue)); + + /** + * Register a save state data unit. + * + * @returns VBox status. + * @param pUsbIns The USB device instance. + * @param uVersion Data layout version number. + * @param cbGuess The approximate amount of data in the unit. + * Only for progress indicators. + * + * @param pfnLivePrep Prepare live save callback, optional. + * @param pfnLiveExec Execute live save callback, optional. + * @param pfnLiveVote Vote live save callback, optional. + * + * @param pfnSavePrep Prepare save callback, optional. + * @param pfnSaveExec Execute save callback, optional. + * @param pfnSaveDone Done save callback, optional. + * + * @param pfnLoadPrep Prepare load callback, optional. + * @param pfnLoadExec Execute load callback, optional. + * @param pfnLoadDone Done load callback, optional. + */ + DECLR3CALLBACKMEMBER(int, pfnSSMRegister,(PPDMUSBINS pUsbIns, uint32_t uVersion, size_t cbGuess, + PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote, + PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone, + PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE pfnLoadDone)); + + /** @name Exported SSM Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnSSMPutStruct,(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStructEx,(PSSMHANDLE pSSM, const void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutBool,(PSSMHANDLE pSSM, bool fBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU8,(PSSMHANDLE pSSM, uint8_t u8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS8,(PSSMHANDLE pSSM, int8_t i8)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU16,(PSSMHANDLE pSSM, uint16_t u16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS16,(PSSMHANDLE pSSM, int16_t i16)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU32,(PSSMHANDLE pSSM, uint32_t u32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS32,(PSSMHANDLE pSSM, int32_t i32)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU64,(PSSMHANDLE pSSM, uint64_t u64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS64,(PSSMHANDLE pSSM, int64_t i64)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutU128,(PSSMHANDLE pSSM, uint128_t u128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutS128,(PSSMHANDLE pSSM, int128_t i128)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutUInt,(PSSMHANDLE pSSM, RTUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSInt,(PSSMHANDLE pSSM, RTINT i)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUInt,(PSSMHANDLE pSSM, RTGCUINT u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntReg,(PSSMHANDLE pSSM, RTGCUINTREG u)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys32,(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys64,(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPhys,(PSSMHANDLE pSSM, RTGCPHYS GCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCPtr,(PSSMHANDLE pSSM, RTGCPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutGCUIntPtr,(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutRCPtr,(PSSMHANDLE pSSM, RTRCPTR RCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutIOPort,(PSSMHANDLE pSSM, RTIOPORT IOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutSel,(PSSMHANDLE pSSM, RTSEL Sel)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutMem,(PSSMHANDLE pSSM, const void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMPutStrZ,(PSSMHANDLE pSSM, const char *psz)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStruct,(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStructEx,(PSSMHANDLE pSSM, void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBool,(PSSMHANDLE pSSM, bool *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetBoolV,(PSSMHANDLE pSSM, bool volatile *pfBool)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8,(PSSMHANDLE pSSM, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU8V,(PSSMHANDLE pSSM, uint8_t volatile *pu8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8,(PSSMHANDLE pSSM, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS8V,(PSSMHANDLE pSSM, int8_t volatile *pi8)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16,(PSSMHANDLE pSSM, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU16V,(PSSMHANDLE pSSM, uint16_t volatile *pu16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16,(PSSMHANDLE pSSM, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS16V,(PSSMHANDLE pSSM, int16_t volatile *pi16)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32,(PSSMHANDLE pSSM, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU32V,(PSSMHANDLE pSSM, uint32_t volatile *pu32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32,(PSSMHANDLE pSSM, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS32V,(PSSMHANDLE pSSM, int32_t volatile *pi32)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64,(PSSMHANDLE pSSM, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU64V,(PSSMHANDLE pSSM, uint64_t volatile *pu64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64,(PSSMHANDLE pSSM, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS64V,(PSSMHANDLE pSSM, int64_t volatile *pi64)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128,(PSSMHANDLE pSSM, uint128_t *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetU128V,(PSSMHANDLE pSSM, uint128_t volatile *pu128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128,(PSSMHANDLE pSSM, int128_t *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetS128V,(PSSMHANDLE pSSM, int128_t volatile *pi128)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32,(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys32V,(PSSMHANDLE pSSM, RTGCPHYS32 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64,(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys64V,(PSSMHANDLE pSSM, RTGCPHYS64 volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhys,(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPhysV,(PSSMHANDLE pSSM, RTGCPHYS volatile *pGCPhys)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetUInt,(PSSMHANDLE pSSM, PRTUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSInt,(PSSMHANDLE pSSM, PRTINT pi)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUInt,(PSSMHANDLE pSSM, PRTGCUINT pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntReg,(PSSMHANDLE pSSM, PRTGCUINTREG pu)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCPtr,(PSSMHANDLE pSSM, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetGCUIntPtr,(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetRCPtr,(PSSMHANDLE pSSM, PRTRCPTR pRCPtr)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetIOPort,(PSSMHANDLE pSSM, PRTIOPORT pIOPort)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetSel,(PSSMHANDLE pSSM, PRTSEL pSel)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetMem,(PSSMHANDLE pSSM, void *pv, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZ,(PSSMHANDLE pSSM, char *psz, size_t cbMax)); + DECLR3CALLBACKMEMBER(int, pfnSSMGetStrZEx,(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkip,(PSSMHANDLE pSSM, size_t cb)); + DECLR3CALLBACKMEMBER(int, pfnSSMSkipToEndOfUnit,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadError,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetLoadErrorV,(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgError,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6)); + DECLR3CALLBACKMEMBER(int, pfnSSMSetCfgErrorV,(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0)); + DECLR3CALLBACKMEMBER(int, pfnSSMHandleGetStatus,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(SSMAFTER, pfnSSMHandleGetAfter,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(bool, pfnSSMHandleIsLiveSave,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleMaxDowntime,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleHostBits,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleRevision,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(uint32_t, pfnSSMHandleVersion,(PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(const char *, pfnSSMHandleHostOSAndArch,(PSSMHANDLE pSSM)); + /** @} */ + + /** @name Exported CFGM Functions. + * @{ */ + DECLR3CALLBACKMEMBER(bool, pfnCFGMExists,( PCFGMNODE pNode, const char *pszName)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryType,( PCFGMNODE pNode, const char *pszName, PCFGMVALUETYPE penmType)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySize,( PCFGMNODE pNode, const char *pszName, size_t *pcb)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryInteger,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryIntegerDef,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryString,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringDef,( PCFGMNODE pNode, const char *pszName, char *pszString, size_t cchString, const char *pszDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBytes,( PCFGMNODE pNode, const char *pszName, void *pvData, size_t cbData)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU64Def,( PCFGMNODE pNode, const char *pszName, uint64_t *pu64, uint64_t u64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64,( PCFGMNODE pNode, const char *pszName, int64_t *pi64)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS64Def,( PCFGMNODE pNode, const char *pszName, int64_t *pi64, int64_t i64Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU32Def,( PCFGMNODE pNode, const char *pszName, uint32_t *pu32, uint32_t u32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32,( PCFGMNODE pNode, const char *pszName, int32_t *pi32)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS32Def,( PCFGMNODE pNode, const char *pszName, int32_t *pi32, int32_t i32Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU16Def,( PCFGMNODE pNode, const char *pszName, uint16_t *pu16, uint16_t u16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16,( PCFGMNODE pNode, const char *pszName, int16_t *pi16)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS16Def,( PCFGMNODE pNode, const char *pszName, int16_t *pi16, int16_t i16Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryU8Def,( PCFGMNODE pNode, const char *pszName, uint8_t *pu8, uint8_t u8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8,( PCFGMNODE pNode, const char *pszName, int8_t *pi8)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryS8Def,( PCFGMNODE pNode, const char *pszName, int8_t *pi8, int8_t i8Def)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBool,( PCFGMNODE pNode, const char *pszName, bool *pf)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryBoolDef,( PCFGMNODE pNode, const char *pszName, bool *pf, bool fDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPort,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryPortDef,( PCFGMNODE pNode, const char *pszName, PRTIOPORT pPort, RTIOPORT PortDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUInt,( PCFGMNODE pNode, const char *pszName, unsigned int *pu)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryUIntDef,( PCFGMNODE pNode, const char *pszName, unsigned int *pu, unsigned int uDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySInt,( PCFGMNODE pNode, const char *pszName, signed int *pi)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQuerySIntDef,( PCFGMNODE pNode, const char *pszName, signed int *pi, signed int iDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtr,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrDef,( PCFGMNODE pNode, const char *pszName, PRTGCPTR pGCPtr, RTGCPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrU,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrUDef,( PCFGMNODE pNode, const char *pszName, PRTGCUINTPTR pGCPtr, RTGCUINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrS,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryGCPtrSDef,( PCFGMNODE pNode, const char *pszName, PRTGCINTPTR pGCPtr, RTGCINTPTR GCPtrDef)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAlloc,( PCFGMNODE pNode, const char *pszName, char **ppszString)); + DECLR3CALLBACKMEMBER(int, pfnCFGMQueryStringAllocDef,(PCFGMNODE pNode, const char *pszName, char **ppszString, const char *pszDef)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetParent,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChild,(PCFGMNODE pNode, const char *pszPath)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildF,(PCFGMNODE pNode, const char *pszPathFormat, ...) RT_IPRT_FORMAT_ATTR(2, 3)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetChildFV,(PCFGMNODE pNode, const char *pszPathFormat, va_list Args) RT_IPRT_FORMAT_ATTR(3, 0)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetFirstChild,(PCFGMNODE pNode)); + DECLR3CALLBACKMEMBER(PCFGMNODE, pfnCFGMGetNextChild,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetName,(PCFGMNODE pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetNameLen,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreChildrenValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetFirstValue,(PCFGMNODE pCur)); + DECLR3CALLBACKMEMBER(PCFGMLEAF, pfnCFGMGetNextValue,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(int, pfnCFGMGetValueName,(PCFGMLEAF pCur, char *pszName, size_t cchName)); + DECLR3CALLBACKMEMBER(size_t, pfnCFGMGetValueNameLen,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(CFGMVALUETYPE, pfnCFGMGetValueType,(PCFGMLEAF pCur)); + DECLR3CALLBACKMEMBER(bool, pfnCFGMAreValuesValid,(PCFGMNODE pNode, const char *pszzValid)); + DECLR3CALLBACKMEMBER(int, pfnCFGMValidateConfig,(PCFGMNODE pNode, const char *pszNode, + const char *pszValidValues, const char *pszValidNodes, + const char *pszWho, uint32_t uInstance)); + /** @} */ + + /** + * Register a STAM sample. + * + * Use the PDMUsbHlpSTAMRegister wrapper. + * + * @returns VBox status. + * @param pUsbIns The USB device instance. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param enmVisibility Visibility type specifying whether unused statistics should be visible or not. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + * @param pszName The sample name format string. + * @param va Arguments to the format string. + */ + DECLR3CALLBACKMEMBER(void, pfnSTAMRegisterV,(PPDMUSBINS pUsbIns, void *pvSample, STAMTYPE enmType, + STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, const char *pszDesc, + const char *pszName, va_list va) RT_IPRT_FORMAT_ATTR(7, 0)); + + /** + * Creates a timer. + * + * @returns VBox status. + * @param pUsbIns The USB device instance. + * @param enmClock The clock to use on this timer. + * @param pfnCallback Callback function. + * @param pvUser User argument for the callback. + * @param fFlags Flags, see TMTIMER_FLAGS_*. + * @param pszDesc Pointer to description string which must stay around + * until the timer is fully destroyed (i.e. a bit after TMTimerDestroy()). + * @param phTimer Where to store the timer handle on success. + */ + DECLR3CALLBACKMEMBER(int, pfnTimerCreate,(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer)); + + /** @name Timer handle method wrappers + * @{ */ + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromMicro,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromMilli,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerFromNano,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGet,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGetFreq,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(uint64_t, pfnTimerGetNano,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(bool, pfnTimerIsActive,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(bool, pfnTimerIsLockOwner,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(int, pfnTimerLockClock,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + /** Takes the clock lock then enters the specified critical section. */ + DECLR3CALLBACKMEMBER(int, pfnTimerLockClock2,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSet,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t uExpire)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetFrequencyHint,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint32_t uHz)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetMicro,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetMillies,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetNano,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetRelative,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now)); + DECLR3CALLBACKMEMBER(int, pfnTimerStop,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(void, pfnTimerUnlockClock,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + DECLR3CALLBACKMEMBER(void, pfnTimerUnlockClock2,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSetCritSect,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect)); + DECLR3CALLBACKMEMBER(int, pfnTimerSave,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnTimerLoad,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM)); + DECLR3CALLBACKMEMBER(int, pfnTimerDestroy,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer)); + /** @sa TMR3TimerSkip */ + DECLR3CALLBACKMEMBER(int, pfnTimerSkipLoad,(PSSMHANDLE pSSM, bool *pfActive)); + /** @} */ + + /** + * Set the VM error message + * + * @returns rc. + * @param pUsbIns The USB device instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetErrorV,(PPDMUSBINS pUsbIns, int rc, RT_SRC_POS_DECL, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0)); + + /** + * Set the VM runtime error message + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param fFlags The action flags. See VMSETRTERR_FLAGS_*. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ + DECLR3CALLBACKMEMBER(int, pfnVMSetRuntimeErrorV,(PPDMUSBINS pUsbIns, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(4, 0)); + + /** + * Gets the VM state. + * + * @returns VM state. + * @param pUsbIns The USB device instance. + * @thread Any thread (just keep in mind that it's volatile info). + */ + DECLR3CALLBACKMEMBER(VMSTATE, pfnVMState, (PPDMUSBINS pUsbIns)); + + /** + * Creates a PDM thread. + * + * This differs from the RTThreadCreate() API in that PDM takes care of suspending, + * resuming, and destroying the thread as the VM state changes. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param ppThread Where to store the thread 'handle'. + * @param pvUser The user argument to the thread function. + * @param pfnThread The thread function. + * @param pfnWakeup The wakup callback. This is called on the EMT + * thread when a state change is pending. + * @param cbStack See RTThreadCreate. + * @param enmType See RTThreadCreate. + * @param pszName See RTThreadCreate. + */ + DECLR3CALLBACKMEMBER(int, pfnThreadCreate,(PPDMUSBINS pUsbIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADUSB pfnThread, + PFNPDMTHREADWAKEUPUSB pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName)); + + /** @name Exported PDM Thread Functions + * @{ */ + DECLR3CALLBACKMEMBER(int, pfnThreadDestroy,(PPDMTHREAD pThread, int *pRcThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmSuspending,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadIAmRunning,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadSleep,(PPDMTHREAD pThread, RTMSINTERVAL cMillies)); + DECLR3CALLBACKMEMBER(int, pfnThreadSuspend,(PPDMTHREAD pThread)); + DECLR3CALLBACKMEMBER(int, pfnThreadResume,(PPDMTHREAD pThread)); + /** @} */ + + /** + * Set up asynchronous handling of a suspend, reset or power off notification. + * + * This shall only be called when getting the notification. It must be called + * for each one. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance. + * @param pfnAsyncNotify The callback. + * @thread EMT(0) + */ + DECLR3CALLBACKMEMBER(int, pfnSetAsyncNotification, (PPDMUSBINS pUSbIns, PFNPDMUSBASYNCNOTIFY pfnAsyncNotify)); + + /** + * Notify EMT(0) that the device has completed the asynchronous notification + * handling. + * + * This can be called at any time, spurious calls will simply be ignored. + * + * @param pUsbIns The USB device instance. + * @thread Any + */ + DECLR3CALLBACKMEMBER(void, pfnAsyncNotificationCompleted, (PPDMUSBINS pUsbIns)); + + /** + * Gets the reason for the most recent VM suspend. + * + * @returns The suspend reason. VMSUSPENDREASON_INVALID is returned if no + * suspend has been made or if the pUsbIns is invalid. + * @param pUsbIns The driver instance. + */ + DECLR3CALLBACKMEMBER(VMSUSPENDREASON, pfnVMGetSuspendReason,(PPDMUSBINS pUsbIns)); + + /** + * Gets the reason for the most recent VM resume. + * + * @returns The resume reason. VMRESUMEREASON_INVALID is returned if no + * resume has been made or if the pUsbIns is invalid. + * @param pUsbIns The driver instance. + */ + DECLR3CALLBACKMEMBER(VMRESUMEREASON, pfnVMGetResumeReason,(PPDMUSBINS pUsbIns)); + + /** + * Queries a generic object from the VMM user. + * + * @returns Pointer to the object if found, NULL if not. + * @param pUsbIns The USB device instance. + * @param pUuid The UUID of what's being queried. The UUIDs and + * the usage conventions are defined by the user. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryGenericUserObject,(PPDMUSBINS pUsbIns, PCRTUUID pUuid)); + + /** @name Space reserved for minor interface changes. + * @{ */ + DECLR3CALLBACKMEMBER(void, pfnReserved0,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved1,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved2,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved3,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved4,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved5,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved6,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved7,(PPDMUSBINS pUsbIns)); + DECLR3CALLBACKMEMBER(void, pfnReserved8,(PPDMUSBINS pUsbIns)); + /** @} */ + + /** Just a safety precaution. */ + uint32_t u32TheEnd; +} PDMUSBHLP; +/** Pointer PDM USB Device API. */ +typedef PDMUSBHLP *PPDMUSBHLP; +/** Pointer const PDM USB Device API. */ +typedef const PDMUSBHLP *PCPDMUSBHLP; + +/** Current USBHLP version number. */ +#define PDM_USBHLP_VERSION PDM_VERSION_MAKE(0xeefe, 7, 0) + +#endif /* IN_RING3 */ + +/** + * PDM USB Device Instance. + */ +typedef struct PDMUSBINS +{ + /** Structure version. PDM_USBINS_VERSION defines the current version. */ + uint32_t u32Version; + /** USB device instance number. */ + uint32_t iInstance; + /** The base interface of the device. + * The device constructor initializes this if it has any device level + * interfaces to export. To obtain this interface call PDMR3QueryUSBDevice(). */ + PDMIBASE IBase; +#if HC_ARCH_BITS == 32 + uint32_t u32Alignment; /**< Alignment padding. */ +#endif + + /** Internal data. */ + union + { +#ifdef PDMUSBINSINT_DECLARED + PDMUSBINSINT s; +#endif + uint8_t padding[HC_ARCH_BITS == 32 ? 96 : 128]; + } Internal; + + /** Pointer the PDM USB Device API. */ + R3PTRTYPE(PCPDMUSBHLP) pHlpR3; + /** Pointer to the USB device registration structure. */ + R3PTRTYPE(PCPDMUSBREG) pReg; + /** Configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfg; + /** The (device) global configuration handle. */ + R3PTRTYPE(PCFGMNODE) pCfgGlobal; + /** Pointer to device instance data. */ + R3PTRTYPE(void *) pvInstanceDataR3; + /** Pointer to the VUSB Device structure. + * Internal to VUSB, don't touch. + * @todo Moved this to PDMUSBINSINT. */ + R3PTRTYPE(void *) pvVUsbDev2; + /** Device name for using when logging. + * The constructor sets this and the destructor frees it. */ + R3PTRTYPE(char *) pszName; + /** Tracing indicator. */ + uint32_t fTracing; + /** The tracing ID of this device. */ + uint32_t idTracing; + /** The port/device speed. HCs and emulated devices need to know. */ + VUSBSPEED enmSpeed; + + /** Padding to make achInstanceData aligned at 32 byte boundary. */ + uint32_t au32Padding[HC_ARCH_BITS == 32 ? 2 : 3]; + + /** Device instance data. The size of this area is defined + * in the PDMUSBREG::cbInstanceData field. */ + char achInstanceData[8]; +} PDMUSBINS; + +/** Current USBINS version number. */ +#define PDM_USBINS_VERSION PDM_VERSION_MAKE(0xeefd, 3, 0) + +/** + * Checks the structure versions of the USB device instance and USB device + * helpers, returning if they are incompatible. + * + * This shall be the first statement of the constructor! + * + * @param pUsbIns The USB device instance pointer. + */ +#define PDMUSB_CHECK_VERSIONS_RETURN(pUsbIns) \ + do \ + { \ + PPDMUSBINS pUsbInsTypeCheck = (pUsbIns); NOREF(pUsbInsTypeCheck); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->u32Version, PDM_USBINS_VERSION), \ + ("DevIns=%#x mine=%#x\n", (pUsbIns)->u32Version, PDM_USBINS_VERSION), \ + VERR_PDM_USBINS_VERSION_MISMATCH); \ + AssertLogRelMsgReturn(PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->pHlpR3->u32Version, PDM_USBHLP_VERSION), \ + ("DevHlp=%#x mine=%#x\n", (pUsbIns)->pHlpR3->u32Version, PDM_USBHLP_VERSION), \ + VERR_PDM_USBHLPR3_VERSION_MISMATCH); \ + } while (0) + +/** + * Quietly checks the structure versions of the USB device instance and + * USB device helpers, returning if they are incompatible. + * + * This shall be invoked as the first statement in the destructor! + * + * @param pUsbIns The USB device instance pointer. + */ +#define PDMUSB_CHECK_VERSIONS_RETURN_VOID(pUsbIns) \ + do \ + { \ + PPDMUSBINS pUsbInsTypeCheck = (pUsbIns); NOREF(pUsbInsTypeCheck); \ + if (RT_LIKELY(PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->u32Version, PDM_USBINS_VERSION) )) \ + { /* likely */ } else return; \ + if (RT_LIKELY(PDM_VERSION_ARE_COMPATIBLE((pUsbIns)->pHlpR3->u32Version, PDM_USBHLP_VERSION) )) \ + { /* likely */ } else return; \ + } while (0) + + +/** Converts a pointer to the PDMUSBINS::IBase to a pointer to PDMUSBINS. */ +#define PDMIBASE_2_PDMUSB(pInterface) ( (PPDMUSBINS)((char *)(pInterface) - RT_UOFFSETOF(PDMUSBINS, IBase)) ) + + +/** @def PDMUSB_ASSERT_EMT + * Assert that the current thread is the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMUSB_ASSERT_EMT(pUsbIns) pUsbIns->pHlpR3->pfnAssertEMT(pUsbIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMUSB_ASSERT_EMT(pUsbIns) do { } while (0) +#endif + +/** @def PDMUSB_ASSERT_OTHER + * Assert that the current thread is NOT the emulation thread. + */ +#ifdef VBOX_STRICT +# define PDMUSB_ASSERT_OTHER(pUsbIns) pUsbIns->pHlpR3->pfnAssertOther(pUsbIns, __FILE__, __LINE__, __FUNCTION__) +#else +# define PDMUSB_ASSERT_OTHER(pUsbIns) do { } while (0) +#endif + +/** @def PDMUSB_SET_ERROR + * Set the VM error. See PDMUsbHlpVMSetError() for printf like message + * formatting. + */ +#define PDMUSB_SET_ERROR(pUsbIns, rc, pszError) \ + PDMUsbHlpVMSetError(pUsbIns, rc, RT_SRC_POS, "%s", pszError) + +/** @def PDMUSB_SET_RUNTIME_ERROR + * Set the VM runtime error. See PDMUsbHlpVMSetRuntimeError() for printf like + * message formatting. + */ +#define PDMUSB_SET_RUNTIME_ERROR(pUsbIns, fFlags, pszErrorId, pszError) \ + PDMUsbHlpVMSetRuntimeError(pUsbIns, fFlags, pszErrorId, "%s", pszError) + + +#ifdef IN_RING3 + +/** + * @copydoc PDMUSBHLP::pfnDriverAttach + */ +DECLINLINE(int) PDMUsbHlpDriverAttach(PPDMUSBINS pUsbIns, RTUINT iLun, PPDMIBASE pBaseInterface, PPDMIBASE *ppBaseInterface, const char *pszDesc) +{ + return pUsbIns->pHlpR3->pfnDriverAttach(pUsbIns, iLun, pBaseInterface, ppBaseInterface, pszDesc); +} + +/** + * VBOX_STRICT wrapper for pHlpR3->pfnDBGFStopV. + * + * @returns VBox status code which must be passed up to the VMM. + * @param pUsbIns Device instance. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Message. (optional) + * @param ... Message parameters. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(5, 6) PDMUsbDBGFStop(PPDMUSBINS pUsbIns, RT_SRC_POS_DECL, const char *pszFormat, ...) +{ +#ifdef VBOX_STRICT + int rc; + va_list va; + va_start(va, pszFormat); + rc = pUsbIns->pHlpR3->pfnDBGFStopV(pUsbIns, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + return rc; +#else + NOREF(pUsbIns); + NOREF(pszFile); + NOREF(iLine); + NOREF(pszFunction); + NOREF(pszFormat); + return VINF_SUCCESS; +#endif +} + +/** + * @copydoc PDMUSBHLP::pfnVMState + */ +DECLINLINE(VMSTATE) PDMUsbHlpVMState(PPDMUSBINS pUsbIns) +{ + return pUsbIns->pHlpR3->pfnVMState(pUsbIns); +} + +/** + * @copydoc PDMUSBHLP::pfnThreadCreate + */ +DECLINLINE(int) PDMUsbHlpThreadCreate(PPDMUSBINS pUsbIns, PPPDMTHREAD ppThread, void *pvUser, PFNPDMTHREADUSB pfnThread, + PFNPDMTHREADWAKEUPUSB pfnWakeup, size_t cbStack, RTTHREADTYPE enmType, const char *pszName) +{ + return pUsbIns->pHlpR3->pfnThreadCreate(pUsbIns, ppThread, pvUser, pfnThread, pfnWakeup, cbStack, enmType, pszName); +} + + +/** + * @copydoc PDMUSBHLP::pfnSetAsyncNotification + */ +DECLINLINE(int) PDMUsbHlpSetAsyncNotification(PPDMUSBINS pUsbIns, PFNPDMUSBASYNCNOTIFY pfnAsyncNotify) +{ + return pUsbIns->pHlpR3->pfnSetAsyncNotification(pUsbIns, pfnAsyncNotify); +} + +/** + * @copydoc PDMUSBHLP::pfnAsyncNotificationCompleted + */ +DECLINLINE(void) PDMUsbHlpAsyncNotificationCompleted(PPDMUSBINS pUsbIns) +{ + pUsbIns->pHlpR3->pfnAsyncNotificationCompleted(pUsbIns); +} + +/** + * Set the VM error message + * + * @returns rc. + * @param pUsbIns The USB device instance. + * @param rc VBox status code. + * @param SRC_POS Use RT_SRC_POS. + * @param pszFormat Error message format string. + * @param ... Error message arguments. + */ +DECLINLINE(int) RT_IPRT_FORMAT_ATTR(6, 7) PDMUsbHlpVMSetError(PPDMUSBINS pUsbIns, int rc, RT_SRC_POS_DECL, + const char *pszFormat, ...) +{ + va_list va; + va_start(va, pszFormat); + rc = pUsbIns->pHlpR3->pfnVMSetErrorV(pUsbIns, rc, RT_SRC_POS_ARGS, pszFormat, va); + va_end(va); + return rc; +} + +/** + * @copydoc PDMUSBHLP::pfnMMHeapAlloc + */ +DECLINLINE(void *) PDMUsbHlpMMHeapAlloc(PPDMUSBINS pUsbIns, size_t cb) +{ + return pUsbIns->pHlpR3->pfnMMHeapAlloc(pUsbIns, cb); +} + +/** + * @copydoc PDMUSBHLP::pfnMMHeapAllocZ + */ +DECLINLINE(void *) PDMUsbHlpMMHeapAllocZ(PPDMUSBINS pUsbIns, size_t cb) +{ + return pUsbIns->pHlpR3->pfnMMHeapAllocZ(pUsbIns, cb); +} + +/** + * Frees memory allocated by PDMUsbHlpMMHeapAlloc or PDMUsbHlpMMHeapAllocZ. + * + * @param pUsbIns The USB device instance. + * @param pv The memory to free. NULL is fine. + */ +DECLINLINE(void) PDMUsbHlpMMHeapFree(PPDMUSBINS pUsbIns, void *pv) +{ + pUsbIns->pHlpR3->pfnMMHeapFree(pUsbIns, pv); +} + +/** + * @copydoc PDMUSBHLP::pfnDBGFInfoRegisterArgv + */ +DECLINLINE(int) PDMUsbHlpDBGFInfoRegisterArgv(PPDMUSBINS pUsbIns, const char *pszName, const char *pszDesc, PFNDBGFINFOARGVUSB pfnHandler) +{ + return pUsbIns->pHlpR3->pfnDBGFInfoRegisterArgv(pUsbIns, pszName, pszDesc, pfnHandler); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerCreate + */ +DECLINLINE(int) PDMUsbHlpTimerCreate(PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, void *pvUser, + uint32_t fFlags, const char *pszDesc, PTMTIMERHANDLE phTimer) +{ + return pUsbIns->pHlpR3->pfnTimerCreate(pUsbIns, enmClock, pfnCallback, pvUser, fFlags, pszDesc, phTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerFromMicro + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerFromMicro(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicroSecs) +{ + return pUsbIns->pHlpR3->pfnTimerFromMicro(pUsbIns, hTimer, cMicroSecs); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerFromMilli + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerFromMilli(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliSecs) +{ + return pUsbIns->pHlpR3->pfnTimerFromMilli(pUsbIns, hTimer, cMilliSecs); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerFromNano + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerFromNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanoSecs) +{ + return pUsbIns->pHlpR3->pfnTimerFromNano(pUsbIns, hTimer, cNanoSecs); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerGet + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerGet(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerGet(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerGetFreq + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerGetFreq(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerGetFreq(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerGetNano + */ +DECLINLINE(uint64_t) PDMUsbHlpTimerGetNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerGetNano(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerIsActive + */ +DECLINLINE(bool) PDMUsbHlpTimerIsActive(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerIsActive(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerIsLockOwner + */ +DECLINLINE(bool) PDMUsbHlpTimerIsLockOwner(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerIsLockOwner(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerLockClock + */ +DECLINLINE(int) PDMUsbHlpTimerLockClock(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerLockClock(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerLockClock2 + */ +DECLINLINE(int) PDMUsbHlpTimerLockClock2(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + return pUsbIns->pHlpR3->pfnTimerLockClock2(pUsbIns, hTimer, pCritSect); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSet + */ +DECLINLINE(int) PDMUsbHlpTimerSet(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t uExpire) +{ + return pUsbIns->pHlpR3->pfnTimerSet(pUsbIns, hTimer, uExpire); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetFrequencyHint + */ +DECLINLINE(int) PDMUsbHlpTimerSetFrequencyHint(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint32_t uHz) +{ + return pUsbIns->pHlpR3->pfnTimerSetFrequencyHint(pUsbIns, hTimer, uHz); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetMicro + */ +DECLINLINE(int) PDMUsbHlpTimerSetMicro(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext) +{ + return pUsbIns->pHlpR3->pfnTimerSetMicro(pUsbIns, hTimer, cMicrosToNext); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetMillies + */ +DECLINLINE(int) PDMUsbHlpTimerSetMillies(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cMilliesToNext) +{ + return pUsbIns->pHlpR3->pfnTimerSetMillies(pUsbIns, hTimer, cMilliesToNext); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetNano + */ +DECLINLINE(int) PDMUsbHlpTimerSetNano(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cNanosToNext) +{ + return pUsbIns->pHlpR3->pfnTimerSetNano(pUsbIns, hTimer, cNanosToNext); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetRelative + */ +DECLINLINE(int) PDMUsbHlpTimerSetRelative(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now) +{ + return pUsbIns->pHlpR3->pfnTimerSetRelative(pUsbIns, hTimer, cTicksToNext, pu64Now); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerStop + */ +DECLINLINE(int) PDMUsbHlpTimerStop(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerStop(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerUnlockClock + */ +DECLINLINE(void) PDMUsbHlpTimerUnlockClock(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + pUsbIns->pHlpR3->pfnTimerUnlockClock(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerUnlockClock2 + */ +DECLINLINE(void) PDMUsbHlpTimerUnlockClock2(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + pUsbIns->pHlpR3->pfnTimerUnlockClock2(pUsbIns, hTimer, pCritSect); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSetCritSect + */ +DECLINLINE(int) PDMUsbHlpTimerSetCritSect(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect) +{ + return pUsbIns->pHlpR3->pfnTimerSetCritSect(pUsbIns, hTimer, pCritSect); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerSave + */ +DECLINLINE(int) PDMUsbHlpTimerSave(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM) +{ + return pUsbIns->pHlpR3->pfnTimerSave(pUsbIns, hTimer, pSSM); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerLoad + */ +DECLINLINE(int) PDMUsbHlpTimerLoad(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM) +{ + return pUsbIns->pHlpR3->pfnTimerLoad(pUsbIns, hTimer, pSSM); +} + +/** + * @copydoc PDMUSBHLP::pfnTimerDestroy + */ +DECLINLINE(int) PDMUsbHlpTimerDestroy(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer) +{ + return pUsbIns->pHlpR3->pfnTimerDestroy(pUsbIns, hTimer); +} + +/** + * @copydoc PDMUSBHLP::pfnSSMRegister + */ +DECLINLINE(int) PDMUsbHlpSSMRegister(PPDMUSBINS pUsbIns, uint32_t uVersion, size_t cbGuess, + PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote, + PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone, + PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE pfnLoadDone) +{ + return pUsbIns->pHlpR3->pfnSSMRegister(pUsbIns, uVersion, cbGuess, + pfnLivePrep, pfnLiveExec, pfnLiveVote, + pfnSavePrep, pfnSaveExec, pfnSaveDone, + pfnLoadPrep, pfnLoadExec, pfnLoadDone); +} + +/** + * @copydoc PDMUSBHLP::pfnQueryGenericUserObject + */ +DECLINLINE(void *) PDMUsbHlpQueryGenericUserObject(PPDMUSBINS pUsbIns, PCRTUUID pUuid) +{ + return pUsbIns->pHlpR3->pfnQueryGenericUserObject(pUsbIns, pUuid); +} + +#endif /* IN_RING3 */ + + + +/** Pointer to callbacks provided to the VBoxUsbRegister() call. */ +typedef const struct PDMUSBREGCB *PCPDMUSBREGCB; + +/** + * Callbacks for VBoxUSBDeviceRegister(). + */ +typedef struct PDMUSBREGCB +{ + /** Interface version. + * This is set to PDM_USBREG_CB_VERSION. */ + uint32_t u32Version; + + /** + * Registers a device with the current VM instance. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param pReg Pointer to the USB device registration record. + * This data must be permanent and readonly. + */ + DECLR3CALLBACKMEMBER(int, pfnRegister,(PCPDMUSBREGCB pCallbacks, PCPDMUSBREG pReg)); +} PDMUSBREGCB; + +/** Current version of the PDMUSBREGCB structure. */ +#define PDM_USBREG_CB_VERSION PDM_VERSION_MAKE(0xeefc, 1, 0) + + +/** + * The VBoxUsbRegister callback function. + * + * PDM will invoke this function after loading a USB device module and letting + * the module decide which devices to register and how to handle conflicts. + * + * @returns VBox status code. + * @param pCallbacks Pointer to the callback table. + * @param u32Version VBox version number. + */ +typedef DECLCALLBACKTYPE(int, FNPDMVBOXUSBREGISTER,(PCPDMUSBREGCB pCallbacks, uint32_t u32Version)); + +VMMR3DECL(int) PDMR3UsbCreateEmulatedDevice(PUVM pUVM, const char *pszDeviceName, PCFGMNODE pDeviceNode, PCRTUUID pUuid, + const char *pszCaptureFilename); +VMMR3DECL(int) PDMR3UsbCreateProxyDevice(PUVM pUVM, PCRTUUID pUuid, const char *pszBackend, const char *pszAddress, PCFGMNODE pSubTree, + VUSBSPEED enmSpeed, uint32_t fMaskedIfs, const char *pszCaptureFilename); +VMMR3DECL(int) PDMR3UsbDetachDevice(PUVM pUVM, PCRTUUID pUuid); +VMMR3DECL(bool) PDMR3UsbHasHub(PUVM pUVM); +VMMR3DECL(int) PDMR3UsbDriverAttach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, uint32_t fFlags, + PPPDMIBASE ppBase); +VMMR3DECL(int) PDMR3UsbDriverDetach(PUVM pUVM, const char *pszDevice, unsigned iDevIns, unsigned iLun, + const char *pszDriver, unsigned iOccurrence, uint32_t fFlags); +VMMR3DECL(int) PDMR3UsbQueryLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, PPDMIBASE *ppBase); +VMMR3DECL(int) PDMR3UsbQueryDriverOnLun(PUVM pUVM, const char *pszDevice, unsigned iInstance, unsigned iLun, + const char *pszDriver, PPPDMIBASE ppBase); + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_pdmusb_h */ diff --git a/include/VBox/vmm/pdmwebcaminfs.h b/include/VBox/vmm/pdmwebcaminfs.h new file mode 100644 index 00000000..3c1fe35f --- /dev/null +++ b/include/VBox/vmm/pdmwebcaminfs.h @@ -0,0 +1,156 @@ +/* $Id: pdmwebcaminfs.h $ */ +/** @file + * webcaminfs - interfaces between dev and driver. + */ + +/* + * Copyright (C) 2011-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pdmwebcaminfs_h +#define VBOX_INCLUDED_vmm_pdmwebcaminfs_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include + +struct VRDEVIDEOINDEVICEDESC; +struct VRDEVIDEOINPAYLOADHDR; +struct VRDEVIDEOINCTRLHDR; + + +/** @defgroup grp_pdm_ifs_webcam PDM Web Camera Interfaces + * @ingroup grp_pdm_interfaces + * @{ + */ + +/** Pointer to the web camera driver (up) interface. */ +typedef struct PDMIWEBCAMDRV *PPDMIWEBCAMDRV; +/** + * Web camera interface driver provided by the driver to the device, + * i.e. facing upwards. + */ +typedef struct PDMIWEBCAMDRV +{ + /** + * The PDM device is ready to get webcam notifications. + * + * @param pInterface Pointer to the interface. + * @param fReady Whether the device is ready. + */ + DECLR3CALLBACKMEMBER(void, pfnReady,(PPDMIWEBCAMDRV pInterface, bool fReady)); + + /** + * Send a control request to the webcam. + * + * Async response will be returned by pfnWebcamUpControl callback. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface. + * @param pvUser The callers context. + * @param idDevice Unique id for the reported webcam assigned by the driver. + * @param pCtrl The control data. + * @param cbCtrl The size of the control data. + */ + DECLR3CALLBACKMEMBER(int, pfnControl,(PPDMIWEBCAMDRV pInterface, void *pvUser, uint64_t idDevice, + struct VRDEVIDEOINCTRLHDR const *pCtrl, uint32_t cbCtrl)); +} PDMIWEBCAMDRV; +/** Interface ID for PDMIWEBCAMDRV. */ +#define PDMIWEBCAMDRV_IID "0d29b9a1-f4cd-4719-a564-38d5634ba9f8" + + +/** Pointer to the web camera driver/device (down) interface. */ +typedef struct PDMIWEBCAMDEV *PPDMIWEBCAMDEV; +/** + * Web camera interface provided by the device(/driver) interface, + * i.e. facing downwards. + */ +typedef struct PDMIWEBCAMDEV +{ + /** + * A webcam is available. + * + * @returns VBox status code. + * @param pInterface Pointer to the interface. + * @param idDevice Unique id for the reported webcam assigned by the driver. + * @param pDeviceDesc The device description. + * @param cbDeviceDesc The size of the device description. + * @param uVersion The remote video input protocol version. + * @param fCapabilities The remote video input protocol capabilities. + */ + DECLR3CALLBACKMEMBER(int, pfnAttached,(PPDMIWEBCAMDEV pInterface, uint64_t idDevice, + struct VRDEVIDEOINDEVICEDESC const *pDeviceDesc, uint32_t cbDeviceDesc, + uint32_t uVersion, uint32_t fCapabilities)); + + /** + * The webcam is not available anymore. + * + * @param pInterface Pointer to the interface. + * @param idDevice Unique id for the reported webcam assigned by the + * driver. + */ + DECLR3CALLBACKMEMBER(void, pfnDetached,(PPDMIWEBCAMDEV pInterface, uint64_t idDevice)); + + /** + * There is a control response or a control change for the webcam. + * + * @param pInterface Pointer to the interface. + * @param fResponse True if this is a response for a previous pfnWebcamDownControl call. + * @param pvUser The pvUser parameter of the pfnWebcamDownControl call. Undefined if fResponse == false. + * @param idDevice Unique id for the reported webcam assigned by the + * driver. + * @param pCtrl The control data (defined in VRDE). + * @param cbCtrl The size of the control data. + */ + DECLR3CALLBACKMEMBER(void, pfnControl,(PPDMIWEBCAMDEV pInterface, bool fResponse, void *pvUser, + uint64_t idDevice, struct VRDEVIDEOINCTRLHDR const *pCtrl, uint32_t cbCtrl)); + + /** + * A new frame. + * + * @param pInterface Pointer to the interface. + * @param idDevice Unique id for the reported webcam assigned by the driver. + * @param pHeader Payload header (defined in VRDE). + * @param cbHeader Size of the payload header. + * @param pvFrame Frame (image) data. + * @param cbFrame Size of the image data. + */ + DECLR3CALLBACKMEMBER(void, pfnFrame,(PPDMIWEBCAMDEV pInterface, uint64_t idDevice, + struct VRDEVIDEOINPAYLOADHDR const *pHeader, uint32_t cbHeader, + const void *pvFrame, uint32_t cbFrame)); +} PDMIWEBCAMDEV; +/** Interface ID for PDMIWEBCAMDEV. */ +#define PDMIWEBCAMDEV_IID "6ac03e3c-f56c-4a35-80af-c13ce47a9dd7" + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_pdmwebcaminfs_h */ + diff --git a/include/VBox/vmm/pgm.h b/include/VBox/vmm/pgm.h new file mode 100644 index 00000000..133ad827 --- /dev/null +++ b/include/VBox/vmm/pgm.h @@ -0,0 +1,1129 @@ +/** @file + * PGM - Page Monitor / Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_pgm_h +#define VBOX_INCLUDED_vmm_pgm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include /* for PGMMREGISTERSHAREDMODULEREQ */ +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_pgm The Page Monitor / Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * FNPGMRELOCATE callback mode. + */ +typedef enum PGMRELOCATECALL +{ + /** The callback is for checking if the suggested address is suitable. */ + PGMRELOCATECALL_SUGGEST = 1, + /** The callback is for executing the relocation. */ + PGMRELOCATECALL_RELOCATE +} PGMRELOCATECALL; + + +/** + * Callback function which will be called when PGM is trying to find + * a new location for the mapping. + * + * The callback is called in two modes, 1) the check mode and 2) the relocate mode. + * In 1) the callback should say if it objects to a suggested new location. If it + * accepts the new location, it is called again for doing it's relocation. + * + * + * @returns true if the location is ok. + * @returns false if another location should be found. + * @param pVM The cross context VM structure. + * @param GCPtrOld The old virtual address. + * @param GCPtrNew The new virtual address. + * @param enmMode Used to indicate the callback mode. + * @param pvUser User argument. + * @remark The return value is no a failure indicator, it's an acceptance + * indicator. Relocation can not fail! + */ +typedef DECLCALLBACKTYPE(bool, FNPGMRELOCATE,(PVM pVM, RTGCPTR GCPtrOld, RTGCPTR GCPtrNew, PGMRELOCATECALL enmMode, void *pvUser)); +/** Pointer to a relocation callback function. */ +typedef FNPGMRELOCATE *PFNPGMRELOCATE; + + +/** + * Memory access origin. + */ +typedef enum PGMACCESSORIGIN +{ + /** Invalid zero value. */ + PGMACCESSORIGIN_INVALID = 0, + /** IEM is access memory. */ + PGMACCESSORIGIN_IEM, + /** HM is access memory. */ + PGMACCESSORIGIN_HM, + /** Some device is access memory. */ + PGMACCESSORIGIN_DEVICE, + /** Someone debugging is access memory. */ + PGMACCESSORIGIN_DEBUGGER, + /** SELM is access memory. */ + PGMACCESSORIGIN_SELM, + /** FTM is access memory. */ + PGMACCESSORIGIN_FTM, + /** REM is access memory. */ + PGMACCESSORIGIN_REM, + /** IOM is access memory. */ + PGMACCESSORIGIN_IOM, + /** End of valid values. */ + PGMACCESSORIGIN_END, + /** Type size hack. */ + PGMACCESSORIGIN_32BIT_HACK = 0x7fffffff +} PGMACCESSORIGIN; + + +/** + * Physical page access handler kind. + */ +typedef enum PGMPHYSHANDLERKIND +{ + /** Invalid zero value. */ + PGMPHYSHANDLERKIND_INVALID = 0, + /** MMIO range. Pages are not present, all access is done in interpreter or recompiler. */ + PGMPHYSHANDLERKIND_MMIO, + /** Handler all write access to a physical page range. */ + PGMPHYSHANDLERKIND_WRITE, + /** Handler all access to a physical page range. */ + PGMPHYSHANDLERKIND_ALL, + /** End of the valid values. */ + PGMPHYSHANDLERKIND_END, + /** Type size hack. */ + PGMPHYSHANDLERKIND_32BIT_HACK = 0x7fffffff +} PGMPHYSHANDLERKIND; + +/** + * Guest Access type + */ +typedef enum PGMACCESSTYPE +{ + /** Read access. */ + PGMACCESSTYPE_READ = 1, + /** Write access. */ + PGMACCESSTYPE_WRITE +} PGMACCESSTYPE; + + +/** @def PGM_ALL_CB_DECL + * Macro for declaring a handler callback for all contexts. The handler + * callback is static in ring-3, and exported in RC and R0. + * @sa PGM_ALL_CB2_DECL. + */ +#if defined(IN_RC) || defined(IN_RING0) +# ifdef __cplusplus +# define PGM_ALL_CB_DECL(type) extern "C" DECLCALLBACK(DECLEXPORT(type)) +# else +# define PGM_ALL_CB_DECL(type) DECLCALLBACK(DECLEXPORT(type)) +# endif +#else +# define PGM_ALL_CB_DECL(type) static DECLCALLBACK(type) +#endif + +/** @def PGM_ALL_CB2_DECL + * Macro for declaring a handler callback for all contexts. The handler + * callback is hidden in ring-3, and exported in RC and R0. + * @sa PGM_ALL_CB2_DECL. + */ +#if defined(IN_RC) || defined(IN_RING0) +# ifdef __cplusplus +# define PGM_ALL_CB2_DECL(type) extern "C" DECLCALLBACK(DECLEXPORT(type)) +# else +# define PGM_ALL_CB2_DECL(type) DECLCALLBACK(DECLEXPORT(type)) +# endif +#else +# define PGM_ALL_CB2_DECL(type) DECL_HIDDEN_CALLBACK(type) +#endif + +/** @def PGM_ALL_CB2_PROTO + * Macro for declaring a handler callback for all contexts. The handler + * callback is hidden in ring-3, and exported in RC and R0. + * @param fnType The callback function type. + * @sa PGM_ALL_CB2_DECL. + */ +#if defined(IN_RC) || defined(IN_RING0) +# ifdef __cplusplus +# define PGM_ALL_CB2_PROTO(fnType) extern "C" DECLEXPORT(fnType) +# else +# define PGM_ALL_CB2_PROTO(fnType) DECLEXPORT(fnType) +# endif +#else +# define PGM_ALL_CB2_PROTO(fnType) DECLHIDDEN(fnType) +#endif + + +/** + * \#PF Handler callback for physical access handler ranges in RC and R0. + * + * @returns Strict VBox status code (appropriate for ring-0 and raw-mode). + * @param pVM The cross context VM structure. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param uErrorCode CPU Error code. + * @param pCtx Pointer to the register context for the CPU. + * @param pvFault The fault address (cr2). + * @param GCPhysFault The GC physical address corresponding to pvFault. + * @param uUser User argument (not a pointer). + * @thread EMT(pVCpu) + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPGMRZPHYSPFHANDLER,(PVMCC pVM, PVMCPUCC pVCpu, RTGCUINT uErrorCode, PCPUMCTX pCtx, + RTGCPTR pvFault, RTGCPHYS GCPhysFault, uint64_t uUser)); +/** Pointer to PGM access callback. */ +typedef FNPGMRZPHYSPFHANDLER *PFNPGMRZPHYSPFHANDLER; + + +/** + * Access handler callback for physical access handler ranges. + * + * The handler can not raise any faults, it's mainly for monitoring write access + * to certain pages (like MMIO). + * + * @returns Strict VBox status code in ring-0 and raw-mode context, in ring-3 + * the only supported informational status code is + * VINF_PGM_HANDLER_DO_DEFAULT. + * @retval VINF_SUCCESS if the handler have carried out the operation. + * @retval VINF_PGM_HANDLER_DO_DEFAULT if the caller should carry out the + * access operation. + * @retval VINF_EM_XXX in ring-0 and raw-mode context. + * + * @param pVM The cross context VM structure. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param GCPhys The physical address the guest is writing to. + * @param pvPhys The HC mapping of that address. + * @param pvBuf What the guest is reading/writing. + * @param cbBuf How much it's reading/writing. + * @param enmAccessType The access type. + * @param enmOrigin The origin of this call. + * @param uUser User argument (not a pointer). + * @thread EMT(pVCpu) + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNPGMPHYSHANDLER,(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, void *pvPhys, + void *pvBuf, size_t cbBuf, PGMACCESSTYPE enmAccessType, + PGMACCESSORIGIN enmOrigin, uint64_t uUser)); +/** Pointer to PGM access callback. */ +typedef FNPGMPHYSHANDLER *PFNPGMPHYSHANDLER; + + +/** + * Paging mode. + * + * @note Part of saved state. Change with extreme care. + */ +typedef enum PGMMODE +{ + /** The usual invalid value. */ + PGMMODE_INVALID = 0, + /** Real mode. */ + PGMMODE_REAL, + /** Protected mode, no paging. */ + PGMMODE_PROTECTED, + /** 32-bit paging. */ + PGMMODE_32_BIT, + /** PAE paging. */ + PGMMODE_PAE, + /** PAE paging with NX enabled. */ + PGMMODE_PAE_NX, + /** 64-bit AMD paging (long mode). */ + PGMMODE_AMD64, + /** 64-bit AMD paging (long mode) with NX enabled. */ + PGMMODE_AMD64_NX, + /** 32-bit nested paging mode (shadow only; guest physical to host physical). */ + PGMMODE_NESTED_32BIT, + /** PAE nested paging mode (shadow only; guest physical to host physical). */ + PGMMODE_NESTED_PAE, + /** AMD64 nested paging mode (shadow only; guest physical to host physical). */ + PGMMODE_NESTED_AMD64, + /** Extended paging (Intel) mode. */ + PGMMODE_EPT, + /** Special mode used by NEM to indicate no shadow paging necessary. */ + PGMMODE_NONE, + /** The max number of modes */ + PGMMODE_MAX, + /** 32bit hackishness. */ + PGMMODE_32BIT_HACK = 0x7fffffff +} PGMMODE; + +/** + * Second level address translation (SLAT) mode. + */ +typedef enum PGMSLAT +{ + /** The usual invalid value. */ + PGMSLAT_INVALID = 0, + /** No second level translation. */ + PGMSLAT_DIRECT, + /** Intel Extended Page Tables (EPT). */ + PGMSLAT_EPT, + /** AMD-V Nested Paging 32-bit. */ + PGMSLAT_32BIT, + /** AMD-V Nested Paging PAE. */ + PGMSLAT_PAE, + /** AMD-V Nested Paging 64-bit. */ + PGMSLAT_AMD64, + /** 32bit hackishness. */ + PGMSLAT_32BIT_HACK = 0x7fffffff +} PGMSLAT; + + +/** @name PGMPTWALK::fFailed flags. + * These flags indicate the type of a page-walk failure. + * @{ + */ +typedef uint32_t PGMWALKFAIL; +/** Regular page fault (MBZ since guest Walk code don't set these explicitly). */ +#define PGM_WALKFAIL_PAGE_FAULT UINT32_C(0) +/** EPT violation - Intel. */ +#define PGM_WALKFAIL_EPT_VIOLATION RT_BIT_32(0) +/** EPT violation, convertible to \#VE exception - Intel. */ +#define PGM_WALKFAIL_EPT_VIOLATION_CONVERTIBLE RT_BIT_32(1) +/** EPT misconfiguration - Intel. */ +#define PGM_WALKFAIL_EPT_MISCONFIG RT_BIT_32(2) + +/** Mask of all EPT induced page-walk failures - Intel. */ +#define PGM_WALKFAIL_EPT ( PGM_WALKFAIL_EPT_VIOLATION \ + | PGM_WALKFAIL_EPT_VIOLATION_CONVERTIBLE \ + | PGM_WALKFAIL_EPT_MISCONFIG) +/** @} */ + + +/** @name PGMPTATTRS - PGM page-table attributes. + * + * This is VirtualBox's combined page table attributes. It combines regular page + * table and Intel EPT attributes. It's 64-bit in size so there's ample room for + * bits added in the future to EPT or regular page tables (for e.g. Protection Key). + * + * The following bits map 1:1 (shifted by PGM_PTATTRS_EPT_SHIFT) to the Intel EPT + * attributes as these are unique to EPT and fit within 64-bits despite the shift: + * - EPT_R : Read access. + * - EPT_W : Write access. + * - EPT_X_SUPER : Execute or execute for supervisor-mode linear addr access. + * - EPT_MEMTYPE : EPT memory type. + * - EPT_IGNORE_PAT: Ignore PAT memory type. + * - EPT_X_USER : Execute access for user-mode linear addresses. + * + * For regular page tables, the R bit is always 1 (same as P bit). + * For Intel EPT, the EPT_R and EPT_W bits are copied to R and W bits respectively. + * + * The following EPT attributes are mapped to the following positions because they + * exist in the regular page tables at these positions OR are exclusive to EPT and + * have been mapped to arbitrarily chosen positions: + * - EPT_A : Accessed (EPT bit 8 maps to bit 5). + * - EPT_D : Dirty (EPT bit 9 maps to bit 6). + * - EPT_SUPER_SHW_STACK : Supervisor Shadow Stack (EPT bit 60 maps to bit 24). + * - EPT_SUPPRESS_VE_XCPT: Suppress \#VE exception (EPT bit 63 maps to bit 25). + * + * Bits 12, 11:9 and 43 are deliberately kept unused (correspond to bit PS and bits + * 11:9 in the regular page-table structures and to bit 11 in the EPT structures + * respectively) as bit 12 is the page-size bit and bits 11:9 are reserved for + * use by software and we may want to use/preserve them in the future. + * + * @{ */ +typedef uint64_t PGMPTATTRS; +/** Pointer to a PGMPTATTRS type. */ +typedef PGMPTATTRS *PPGMPTATTRS; + +/** Read bit (always 1 for regular PT, copy of EPT_R for EPT). */ +#define PGM_PTATTRS_R_SHIFT 0 +#define PGM_PTATTRS_R_MASK RT_BIT_64(PGM_PTATTRS_R_SHIFT) +/** Write access bit (aka read/write bit for regular PT). */ +#define PGM_PTATTRS_W_SHIFT 1 +#define PGM_PTATTRS_W_MASK RT_BIT_64(PGM_PTATTRS_W_SHIFT) +/** User-mode access bit. */ +#define PGM_PTATTRS_US_SHIFT 2 +#define PGM_PTATTRS_US_MASK RT_BIT_64(PGM_PTATTRS_US_SHIFT) +/** Write through cache bit. */ +#define PGM_PTATTRS_PWT_SHIFT 3 +#define PGM_PTATTRS_PWT_MASK RT_BIT_64(PGM_PTATTRS_PWT_SHIFT) +/** Cache disabled bit. */ +#define PGM_PTATTRS_PCD_SHIFT 4 +#define PGM_PTATTRS_PCD_MASK RT_BIT_64(PGM_PTATTRS_PCD_SHIFT) +/** Accessed bit. */ +#define PGM_PTATTRS_A_SHIFT 5 +#define PGM_PTATTRS_A_MASK RT_BIT_64(PGM_PTATTRS_A_SHIFT) +/** Dirty bit. */ +#define PGM_PTATTRS_D_SHIFT 6 +#define PGM_PTATTRS_D_MASK RT_BIT_64(PGM_PTATTRS_D_SHIFT) +/** The PAT bit. */ +#define PGM_PTATTRS_PAT_SHIFT 7 +#define PGM_PTATTRS_PAT_MASK RT_BIT_64(PGM_PTATTRS_PAT_SHIFT) +/** The global bit. */ +#define PGM_PTATTRS_G_SHIFT 8 +#define PGM_PTATTRS_G_MASK RT_BIT_64(PGM_PTATTRS_G_SHIFT) +/** Reserved (bits 12:9) unused. */ +#define PGM_PTATTRS_RSVD_12_9_SHIFT 9 +#define PGM_PTATTRS_RSVD_12_9_MASK UINT64_C(0x0000000000001e00) +/** Read access bit - EPT only. */ +#define PGM_PTATTRS_EPT_R_SHIFT 13 +#define PGM_PTATTRS_EPT_R_MASK RT_BIT_64(PGM_PTATTRS_EPT_R_SHIFT) +/** Write access bit - EPT only. */ +#define PGM_PTATTRS_EPT_W_SHIFT 14 +#define PGM_PTATTRS_EPT_W_MASK RT_BIT_64(PGM_PTATTRS_EPT_W_SHIFT) +/** Execute or execute access for supervisor-mode linear addresses - EPT only. */ +#define PGM_PTATTRS_EPT_X_SUPER_SHIFT 15 +#define PGM_PTATTRS_EPT_X_SUPER_MASK RT_BIT_64(PGM_PTATTRS_EPT_X_SUPER_SHIFT) +/** EPT memory type - EPT only. */ +#define PGM_PTATTRS_EPT_MEMTYPE_SHIFT 16 +#define PGM_PTATTRS_EPT_MEMTYPE_MASK UINT64_C(0x0000000000070000) +/** Ignore PAT memory type - EPT only. */ +#define PGM_PTATTRS_EPT_IGNORE_PAT_SHIFT 19 +#define PGM_PTATTRS_EPT_IGNORE_PAT_MASK RT_BIT_64(PGM_PTATTRS_EPT_IGNORE_PAT_SHIFT) +/** Leaf paging entry (big or regular) - EPT only. */ +#define PGM_PTATTRS_EPT_LEAF_SHIFT 20 +#define PGM_PTATTRS_EPT_LEAF_MASK RT_BIT_64(PGM_PTATTRS_EPT_LEAF_SHIFT) +/** Accessed bit - EPT only. */ +#define PGM_PTATTRS_EPT_A_SHIFT 21 +#define PGM_PTATTRS_EPT_A_MASK RT_BIT_64(PGM_PTATTRS_EPT_A_SHIFT) +/** Dirty bit - EPT only. */ +#define PGM_PTATTRS_EPT_D_SHIFT 22 +#define PGM_PTATTRS_EPT_D_MASK RT_BIT_64(PGM_PTATTRS_EPT_D_SHIFT) +/** Execute access for user-mode linear addresses - EPT only. */ +#define PGM_PTATTRS_EPT_X_USER_SHIFT 23 +#define PGM_PTATTRS_EPT_X_USER_MASK RT_BIT_64(PGM_PTATTRS_EPT_X_USER_SHIFT) +/** Reserved (bits 29:24) - unused. */ +#define PGM_PTATTRS_RSVD_29_24_SHIFT 24 +#define PGM_PTATTRS_RSVD_29_24_MASK UINT64_C(0x000000003f000000) +/** Verify Guest Paging - EPT only. */ +#define PGM_PTATTRS_EPT_VGP_SHIFT 30 +#define PGM_PTATTRS_EPT_VGP_MASK RT_BIT_64(PGM_PTATTRS_EPT_VGP_SHIFT) +/** Paging-write - EPT only. */ +#define PGM_PTATTRS_EPT_PW_SHIFT 31 +#define PGM_PTATTRS_EPT_PW_MASK RT_BIT_64(PGM_PTATTRS_EPT_PW_SHIFT) +/** Reserved (bit 32) - unused. */ +#define PGM_PTATTRS_RSVD_32_SHIFT 32 +#define PGM_PTATTRS_RSVD_32_MASK UINT64_C(0x0000000100000000) +/** Supervisor shadow stack - EPT only. */ +#define PGM_PTATTRS_EPT_SSS_SHIFT 33 +#define PGM_PTATTRS_EPT_SSS_MASK RT_BIT_64(PGM_PTATTRS_EPT_SSS_SHIFT) +/** Sub-page write permission - EPT only. */ +#define PGM_PTATTRS_EPT_SPP_SHIFT 34 +#define PGM_PTATTRS_EPT_SPP_MASK RT_BIT_64(PGM_PTATTRS_EPT_SPP_SHIFT) +/** Reserved (bit 35) - unused. */ +#define PGM_PTATTRS_RSVD_35_SHIFT 35 +#define PGM_PTATTRS_RSVD_35_MASK UINT64_C(0x0000000800000000) +/** Suppress \#VE exception - EPT only. */ +#define PGM_PTATTRS_EPT_SVE_SHIFT 36 +#define PGM_PTATTRS_EPT_SVE_MASK RT_BIT_64(PGM_PTATTRS_EPT_SVE_SHIFT) +/** Reserved (bits 62:37) - unused. */ +#define PGM_PTATTRS_RSVD_62_37_SHIFT 37 +#define PGM_PTATTRS_RSVD_62_37_MASK UINT64_C(0x7fffffe000000000) +/** No-execute bit. */ +#define PGM_PTATTRS_NX_SHIFT 63 +#define PGM_PTATTRS_NX_MASK RT_BIT_64(PGM_PTATTRS_NX_SHIFT) + +RT_BF_ASSERT_COMPILE_CHECKS(PGM_PTATTRS_, UINT64_C(0), UINT64_MAX, + (R, W, US, PWT, PCD, A, D, PAT, G, RSVD_12_9, EPT_R, EPT_W, EPT_X_SUPER, EPT_MEMTYPE, EPT_IGNORE_PAT, + EPT_LEAF, EPT_A, EPT_D, EPT_X_USER, RSVD_29_24, EPT_VGP, EPT_PW, RSVD_32, EPT_SSS, EPT_SPP, + RSVD_35, EPT_SVE, RSVD_62_37, NX)); + +/** The bit position where the EPT specific attributes begin. */ +#define PGM_PTATTRS_EPT_SHIFT PGM_PTATTRS_EPT_R_SHIFT +/** The mask of EPT bits (bits 36:ATTR_SHIFT). In the future we might choose to + * use higher unused bits for something else, in that case adjust this mask. */ +#define PGM_PTATTRS_EPT_MASK UINT64_C(0x0000001fffffe000) + +/** The mask of all PGM page attribute bits for regular page-tables. */ +#define PGM_PTATTRS_PT_VALID_MASK ( PGM_PTATTRS_R_MASK \ + | PGM_PTATTRS_W_MASK \ + | PGM_PTATTRS_US_MASK \ + | PGM_PTATTRS_PWT_MASK \ + | PGM_PTATTRS_PCD_MASK \ + | PGM_PTATTRS_A_MASK \ + | PGM_PTATTRS_D_MASK \ + | PGM_PTATTRS_PAT_MASK \ + | PGM_PTATTRS_G_MASK \ + | PGM_PTATTRS_NX_MASK) + +/** The mask of all PGM page attribute bits for EPT. */ +#define PGM_PTATTRS_EPT_VALID_MASK ( PGM_PTATTRS_EPT_R_MASK \ + | PGM_PTATTRS_EPT_W_MASK \ + | PGM_PTATTRS_EPT_X_SUPER_MASK \ + | PGM_PTATTRS_EPT_MEMTYPE_MASK \ + | PGM_PTATTRS_EPT_IGNORE_PAT_MASK \ + | PGM_PTATTRS_EPT_LEAF_MASK \ + | PGM_PTATTRS_EPT_A_MASK \ + | PGM_PTATTRS_EPT_D_MASK \ + | PGM_PTATTRS_EPT_X_USER_MASK \ + | PGM_PTATTRS_EPT_VGP_MASK \ + | PGM_PTATTRS_EPT_PW_MASK \ + | PGM_PTATTRS_EPT_SSS_MASK \ + | PGM_PTATTRS_EPT_SPP_MASK \ + | PGM_PTATTRS_EPT_SVE_MASK) + +/* The mask of all PGM page attribute bits (combined). */ +#define PGM_PTATTRS_VALID_MASK (PGM_PTATTRS_PT_VALID_MASK | PGM_PTATTRS_EPT_VALID_MASK) + +/* Verify bits match the regular PT bits. */ +AssertCompile(PGM_PTATTRS_W_SHIFT == X86_PTE_BIT_RW); +AssertCompile(PGM_PTATTRS_US_SHIFT == X86_PTE_BIT_US); +AssertCompile(PGM_PTATTRS_PWT_SHIFT == X86_PTE_BIT_PWT); +AssertCompile(PGM_PTATTRS_PCD_SHIFT == X86_PTE_BIT_PCD); +AssertCompile(PGM_PTATTRS_A_SHIFT == X86_PTE_BIT_A); +AssertCompile(PGM_PTATTRS_D_SHIFT == X86_PTE_BIT_D); +AssertCompile(PGM_PTATTRS_PAT_SHIFT == X86_PTE_BIT_PAT); +AssertCompile(PGM_PTATTRS_G_SHIFT == X86_PTE_BIT_G); +AssertCompile(PGM_PTATTRS_W_MASK == X86_PTE_RW); +AssertCompile(PGM_PTATTRS_US_MASK == X86_PTE_US); +AssertCompile(PGM_PTATTRS_PWT_MASK == X86_PTE_PWT); +AssertCompile(PGM_PTATTRS_PCD_MASK == X86_PTE_PCD); +AssertCompile(PGM_PTATTRS_A_MASK == X86_PTE_A); +AssertCompile(PGM_PTATTRS_D_MASK == X86_PTE_D); +AssertCompile(PGM_PTATTRS_PAT_MASK == X86_PTE_PAT); +AssertCompile(PGM_PTATTRS_G_MASK == X86_PTE_G); +AssertCompile(PGM_PTATTRS_NX_MASK == X86_PTE_PAE_NX); + +/* Verify those EPT bits that must map 1:1 (after shifting). */ +AssertCompile(PGM_PTATTRS_EPT_R_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_READ); +AssertCompile(PGM_PTATTRS_EPT_W_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_WRITE); +AssertCompile(PGM_PTATTRS_EPT_X_SUPER_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_EXECUTE); +AssertCompile(PGM_PTATTRS_EPT_IGNORE_PAT_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_IGNORE_PAT); +AssertCompile(PGM_PTATTRS_EPT_X_USER_SHIFT - PGM_PTATTRS_EPT_SHIFT == EPT_E_BIT_USER_EXECUTE); +/** @} */ + + +/** + * Page table walk information. + * + * This provides extensive information regarding page faults (or EPT + * violations/misconfigurations) while traversing page tables. + */ +typedef struct PGMPTWALK +{ + /** The linear address that is being resolved (input). */ + RTGCPTR GCPtr; + + /** The second-level physical address (input/output). + * @remarks only valid if fIsSlat is set. */ + RTGCPHYS GCPhysNested; + + /** The physical address that is the result of the walk (output). */ + RTGCPHYS GCPhys; + + /** Set if the walk succeeded. */ + bool fSucceeded; + /** Whether this is a second-level address translation. */ + bool fIsSlat; + /** Whether the linear address (GCPtr) caused the second-level + * address translation. */ + bool fIsLinearAddrValid; + /** The level problem arrised at. + * PTE is level 1, PDE is level 2, PDPE is level 3, PML4 is level 4, CR3 is + * level 8. This is 0 on success. */ + uint8_t uLevel; + /** Set if the page isn't present. */ + bool fNotPresent; + /** Encountered a bad physical address. */ + bool fBadPhysAddr; + /** Set if there was reserved bit violations. */ + bool fRsvdError; + /** Set if it involves a big page (2/4 MB). */ + bool fBigPage; + /** Set if it involves a gigantic page (1 GB). */ + bool fGigantPage; + bool afPadding[3]; + /** Page-walk failure type, PGM_WALKFAIL_XXX. */ + PGMWALKFAIL fFailed; + + /** The effective page-table attributes, PGM_PTATTRS_XXX. */ + PGMPTATTRS fEffective; +} PGMPTWALK; +/** Pointer to page walk information. */ +typedef PGMPTWALK *PPGMPTWALK; +/** Pointer to const page walk information. */ +typedef PGMPTWALK const *PCPGMPTWALK; + + +/** Macro for checking if the guest is using paging. + * @param enmMode PGMMODE_*. + * @remark ASSUMES certain order of the PGMMODE_* values. + */ +#define PGMMODE_WITH_PAGING(enmMode) ((enmMode) >= PGMMODE_32_BIT) + +/** Macro for checking if it's one of the long mode modes. + * @param enmMode PGMMODE_*. + */ +#define PGMMODE_IS_LONG_MODE(enmMode) ((enmMode) == PGMMODE_AMD64_NX || (enmMode) == PGMMODE_AMD64) + +/** Macro for checking if it's one of the AMD64 nested modes. + * @param enmMode PGMMODE_*. + */ +#define PGMMODE_IS_NESTED(enmMode) ( (enmMode) == PGMMODE_NESTED_32BIT \ + || (enmMode) == PGMMODE_NESTED_PAE \ + || (enmMode) == PGMMODE_NESTED_AMD64) + +/** Macro for checking if it's one of the PAE modes. + * @param enmMode PGMMODE_*. + */ +#define PGMMODE_IS_PAE(enmMode) ( (enmMode) == PGMMODE_PAE \ + || (enmMode) == PGMMODE_PAE_NX) + +/** + * Is the ROM mapped (true) or is the shadow RAM mapped (false). + * + * @returns boolean. + * @param enmProt The PGMROMPROT value, must be valid. + */ +#define PGMROMPROT_IS_ROM(enmProt) \ + ( (enmProt) == PGMROMPROT_READ_ROM_WRITE_IGNORE \ + || (enmProt) == PGMROMPROT_READ_ROM_WRITE_RAM ) + + +VMMDECL(bool) PGMIsLockOwner(PVMCC pVM); + +VMMDECL(int) PGMRegisterStringFormatTypes(void); +VMMDECL(void) PGMDeregisterStringFormatTypes(void); +VMMDECL(RTHCPHYS) PGMGetHyperCR3(PVMCPU pVCpu); +VMMDECL(int) PGMTrap0eHandler(PVMCPUCC pVCpu, RTGCUINT uErr, PCPUMCTX pCtx, RTGCPTR pvFault); +VMMDECL(int) PGMPrefetchPage(PVMCPUCC pVCpu, RTGCPTR GCPtrPage); +VMMDECL(VBOXSTRICTRC) PGMInterpretInstruction(PVMCPUCC pVCpu, RTGCPTR pvFault); +VMMDECL(int) PGMShwGetPage(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint64_t *pfFlags, PRTHCPHYS pHCPhys); +VMMDECL(int) PGMShwMakePageReadonly(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint32_t fFlags); +VMMDECL(int) PGMShwMakePageWritable(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint32_t fFlags); +VMMDECL(int) PGMShwMakePageNotPresent(PVMCPUCC pVCpu, RTGCPTR GCPtr, uint32_t fFlags); +/** @name Flags for PGMShwMakePageReadonly, PGMShwMakePageWritable and + * PGMShwMakePageNotPresent + * @{ */ +/** The call is from an access handler for dealing with the a faulting write + * operation. The virtual address is within the same page. */ +#define PGM_MK_PG_IS_WRITE_FAULT RT_BIT(0) +/** The page is an MMIO2. */ +#define PGM_MK_PG_IS_MMIO2 RT_BIT(1) +/** @}*/ +VMMDECL(int) PGMGstGetPage(PVMCPUCC pVCpu, RTGCPTR GCPtr, PPGMPTWALK pWalk); +VMMDECL(int) PGMGstModifyPage(PVMCPUCC pVCpu, RTGCPTR GCPtr, size_t cb, uint64_t fFlags, uint64_t fMask); +VMM_INT_DECL(bool) PGMGstArePaePdpesValid(PVMCPUCC pVCpu, PCX86PDPE paPaePdpes); +VMM_INT_DECL(int) PGMGstMapPaePdpes(PVMCPUCC pVCpu, PCX86PDPE paPaePdpes); +VMM_INT_DECL(int) PGMGstMapPaePdpesAtCr3(PVMCPUCC pVCpu, uint64_t cr3); + +VMMDECL(int) PGMInvalidatePage(PVMCPUCC pVCpu, RTGCPTR GCPtrPage); +VMMDECL(int) PGMFlushTLB(PVMCPUCC pVCpu, uint64_t cr3, bool fGlobal); +VMMDECL(int) PGMSyncCR3(PVMCPUCC pVCpu, uint64_t cr0, uint64_t cr3, uint64_t cr4, bool fGlobal); +VMMDECL(int) PGMUpdateCR3(PVMCPUCC pVCpu, uint64_t cr3); +VMMDECL(int) PGMChangeMode(PVMCPUCC pVCpu, uint64_t cr0, uint64_t cr4, uint64_t efer, bool fForce); +VMM_INT_DECL(int) PGMHCChangeMode(PVMCC pVM, PVMCPUCC pVCpu, PGMMODE enmGuestMode, bool fForce); +VMMDECL(void) PGMCr0WpEnabled(PVMCPUCC pVCpu); +VMMDECL(PGMMODE) PGMGetGuestMode(PVMCPU pVCpu); +VMMDECL(PGMMODE) PGMGetShadowMode(PVMCPU pVCpu); +VMMDECL(PGMMODE) PGMGetHostMode(PVM pVM); +VMMDECL(const char *) PGMGetModeName(PGMMODE enmMode); +#ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT +VMM_INT_DECL(const char *) PGMGetSlatModeName(PGMSLAT enmSlatMode); +#endif +VMM_INT_DECL(RTGCPHYS) PGMGetGuestCR3Phys(PVMCPU pVCpu); +VMM_INT_DECL(void) PGMNotifyNxeChanged(PVMCPU pVCpu, bool fNxe); +VMMDECL(bool) PGMHasDirtyPages(PVM pVM); +VMM_INT_DECL(void) PGMSetGuestEptPtr(PVMCPUCC pVCpu, uint64_t uEptPtr); + +/** PGM physical access handler type registration handle (heap offset, valid + * cross contexts without needing fixing up). Callbacks and handler type is + * associated with this and it is shared by all handler registrations. */ +typedef uint64_t PGMPHYSHANDLERTYPE; +/** Pointer to a PGM physical handler type registration handle. */ +typedef PGMPHYSHANDLERTYPE *PPGMPHYSHANDLERTYPE; +/** NIL value for PGM physical access handler type handle. */ +#define NIL_PGMPHYSHANDLERTYPE UINT64_MAX +VMMDECL(int) PGMHandlerPhysicalRegister(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast, PGMPHYSHANDLERTYPE hType, + uint64_t uUser, R3PTRTYPE(const char *) pszDesc); +VMMDECL(int) PGMHandlerPhysicalModify(PVMCC pVM, RTGCPHYS GCPhysCurrent, RTGCPHYS GCPhys, RTGCPHYS GCPhysLast); +VMMDECL(int) PGMHandlerPhysicalDeregister(PVMCC pVM, RTGCPHYS GCPhys); +VMMDECL(int) PGMHandlerPhysicalChangeUserArg(PVMCC pVM, RTGCPHYS GCPhys, uint64_t uUser); +VMMDECL(int) PGMHandlerPhysicalSplit(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysSplit); +VMMDECL(int) PGMHandlerPhysicalJoin(PVMCC pVM, RTGCPHYS GCPhys1, RTGCPHYS GCPhys2); +VMMDECL(int) PGMHandlerPhysicalPageTempOff(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage); +VMMDECL(int) PGMHandlerPhysicalPageAliasMmio2(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage, + PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS offMMio2PageRemap); +VMMDECL(int) PGMHandlerPhysicalPageAliasHC(PVMCC pVM, RTGCPHYS GCPhys, RTGCPHYS GCPhysPage, RTHCPHYS HCPhysPageRemap); +VMMDECL(int) PGMHandlerPhysicalReset(PVMCC pVM, RTGCPHYS GCPhys); +VMMDECL(bool) PGMHandlerPhysicalIsRegistered(PVMCC pVM, RTGCPHYS GCPhys); + +/** @name PGMPHYSHANDLER_F_XXX - flags for PGMR3HandlerPhysicalTypeRegister and PGMR0HandlerPhysicalTypeRegister + * @{ */ +/** Whether to hold the PGM lock while calling the handler or not. + * Mainly an optimization for PGM callers. */ +#define PGMPHYSHANDLER_F_KEEP_PGM_LOCK RT_BIT_32(0) +/** The uUser value is a ring-0 device instance index that needs translating + * into a PDMDEVINS pointer before calling the handler. This is a hack to make + * it possible to use access handlers in devices. */ +#define PGMPHYSHANDLER_F_R0_DEVINS_IDX RT_BIT_32(1) +/** Don't apply the access handler to VT-x and AMD-V. Only works with full pages. + * This is a trick for the VT-x APIC access page in nested VT-x setups. */ +#define PGMPHYSHANDLER_F_NOT_IN_HM RT_BIT_32(2) +/** Mask of valid bits. */ +#define PGMPHYSHANDLER_F_VALID_MASK UINT32_C(7) +/** @} */ + + +/** + * Page type. + * + * @remarks This enum has to fit in a 3-bit field (see PGMPAGE::u3Type). + * @remarks This is used in the saved state, so changes to it requires bumping + * the saved state version. + * @todo So, convert to \#defines! + */ +typedef enum PGMPAGETYPE +{ + /** The usual invalid zero entry. */ + PGMPAGETYPE_INVALID = 0, + /** RAM page. (RWX) */ + PGMPAGETYPE_RAM, + /** MMIO2 page. (RWX) */ + PGMPAGETYPE_MMIO2, + /** MMIO2 page aliased over an MMIO page. (RWX) + * See PGMHandlerPhysicalPageAlias(). */ + PGMPAGETYPE_MMIO2_ALIAS_MMIO, + /** Special page aliased over an MMIO page. (RWX) + * See PGMHandlerPhysicalPageAliasHC(), but this is generally only used for + * VT-x's APIC access page at the moment. Treated as MMIO by everyone except + * the shadow paging code. */ + PGMPAGETYPE_SPECIAL_ALIAS_MMIO, + /** Shadowed ROM. (RWX) */ + PGMPAGETYPE_ROM_SHADOW, + /** ROM page. (R-X) */ + PGMPAGETYPE_ROM, + /** MMIO page. (---) */ + PGMPAGETYPE_MMIO, + /** End of valid entries. */ + PGMPAGETYPE_END +} PGMPAGETYPE; +AssertCompile(PGMPAGETYPE_END == 8); + +/** @name PGM page type predicates. + * @{ */ +#define PGMPAGETYPE_IS_READABLE(a_enmType) ( (a_enmType) <= PGMPAGETYPE_ROM ) +#define PGMPAGETYPE_IS_WRITEABLE(a_enmType) ( (a_enmType) <= PGMPAGETYPE_ROM_SHADOW ) +#define PGMPAGETYPE_IS_RWX(a_enmType) ( (a_enmType) <= PGMPAGETYPE_ROM_SHADOW ) +#define PGMPAGETYPE_IS_ROX(a_enmType) ( (a_enmType) == PGMPAGETYPE_ROM ) +#define PGMPAGETYPE_IS_NP(a_enmType) ( (a_enmType) == PGMPAGETYPE_MMIO ) +/** @} */ + + +VMM_INT_DECL(PGMPAGETYPE) PGMPhysGetPageType(PVMCC pVM, RTGCPHYS GCPhys); + +VMM_INT_DECL(int) PGMPhysGCPhys2HCPhys(PVMCC pVM, RTGCPHYS GCPhys, PRTHCPHYS pHCPhys); +VMM_INT_DECL(int) PGMPhysGCPtr2HCPhys(PVMCPUCC pVCpu, RTGCPTR GCPtr, PRTHCPHYS pHCPhys); +VMM_INT_DECL(int) PGMPhysGCPhys2CCPtr(PVMCC pVM, RTGCPHYS GCPhys, void **ppv, PPGMPAGEMAPLOCK pLock); +VMM_INT_DECL(int) PGMPhysGCPhys2CCPtrReadOnly(PVMCC pVM, RTGCPHYS GCPhys, void const **ppv, PPGMPAGEMAPLOCK pLock); +VMM_INT_DECL(int) PGMPhysGCPtr2CCPtr(PVMCPU pVCpu, RTGCPTR GCPtr, void **ppv, PPGMPAGEMAPLOCK pLock); +VMM_INT_DECL(int) PGMPhysGCPtr2CCPtrReadOnly(PVMCPUCC pVCpu, RTGCPTR GCPtr, void const **ppv, PPGMPAGEMAPLOCK pLock); + +VMMDECL(bool) PGMPhysIsA20Enabled(PVMCPU pVCpu); +VMMDECL(bool) PGMPhysIsGCPhysValid(PVMCC pVM, RTGCPHYS GCPhys); +VMMDECL(bool) PGMPhysIsGCPhysNormal(PVMCC pVM, RTGCPHYS GCPhys); +VMMDECL(int) PGMPhysGCPtr2GCPhys(PVMCPUCC pVCpu, RTGCPTR GCPtr, PRTGCPHYS pGCPhys); +VMMDECL(void) PGMPhysReleasePageMappingLock(PVMCC pVM, PPGMPAGEMAPLOCK pLock); +VMMDECL(void) PGMPhysBulkReleasePageMappingLocks(PVMCC pVM, uint32_t cPages, PPGMPAGEMAPLOCK paLock); + +/** @def PGM_PHYS_RW_IS_SUCCESS + * Check whether a PGMPhysRead, PGMPhysWrite, PGMPhysReadGCPtr or + * PGMPhysWriteGCPtr call completed the given task. + * + * @returns true if completed, false if not. + * @param a_rcStrict The status code. + * @sa IOM_SUCCESS + */ +#ifdef IN_RING3 +# define PGM_PHYS_RW_IS_SUCCESS(a_rcStrict) \ + ( (a_rcStrict) == VINF_SUCCESS \ + || (a_rcStrict) == VINF_EM_DBG_STOP \ + || (a_rcStrict) == VINF_EM_DBG_EVENT \ + || (a_rcStrict) == VINF_EM_DBG_BREAKPOINT \ + ) +#elif defined(IN_RING0) +# define PGM_PHYS_RW_IS_SUCCESS(a_rcStrict) \ + ( (a_rcStrict) == VINF_SUCCESS \ + || (a_rcStrict) == VINF_IOM_R3_MMIO_COMMIT_WRITE \ + || (a_rcStrict) == VINF_EM_OFF \ + || (a_rcStrict) == VINF_EM_SUSPEND \ + || (a_rcStrict) == VINF_EM_RESET \ + || (a_rcStrict) == VINF_EM_HALT \ + || (a_rcStrict) == VINF_EM_DBG_STOP \ + || (a_rcStrict) == VINF_EM_DBG_EVENT \ + || (a_rcStrict) == VINF_EM_DBG_BREAKPOINT \ + ) +#elif defined(IN_RC) +# define PGM_PHYS_RW_IS_SUCCESS(a_rcStrict) \ + ( (a_rcStrict) == VINF_SUCCESS \ + || (a_rcStrict) == VINF_IOM_R3_MMIO_COMMIT_WRITE \ + || (a_rcStrict) == VINF_EM_OFF \ + || (a_rcStrict) == VINF_EM_SUSPEND \ + || (a_rcStrict) == VINF_EM_RESET \ + || (a_rcStrict) == VINF_EM_HALT \ + || (a_rcStrict) == VINF_SELM_SYNC_GDT \ + || (a_rcStrict) == VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT \ + || (a_rcStrict) == VINF_EM_DBG_STOP \ + || (a_rcStrict) == VINF_EM_DBG_EVENT \ + || (a_rcStrict) == VINF_EM_DBG_BREAKPOINT \ + ) +#endif +/** @def PGM_PHYS_RW_DO_UPDATE_STRICT_RC + * Updates the return code with a new result. + * + * Both status codes must be successes according to PGM_PHYS_RW_IS_SUCCESS. + * + * @param a_rcStrict The current return code, to be updated. + * @param a_rcStrict2 The new return code to merge in. + */ +#ifdef IN_RING3 +# define PGM_PHYS_RW_DO_UPDATE_STRICT_RC(a_rcStrict, a_rcStrict2) \ + do { \ + Assert(rcStrict == VINF_SUCCESS); \ + Assert(rcStrict2 == VINF_SUCCESS); \ + } while (0) +#elif defined(IN_RING0) +# define PGM_PHYS_RW_DO_UPDATE_STRICT_RC(a_rcStrict, a_rcStrict2) \ + do { \ + Assert(PGM_PHYS_RW_IS_SUCCESS(rcStrict)); \ + Assert(PGM_PHYS_RW_IS_SUCCESS(rcStrict2)); \ + AssertCompile(VINF_IOM_R3_MMIO_COMMIT_WRITE > VINF_EM_LAST); \ + if ((a_rcStrict2) == VINF_SUCCESS || (a_rcStrict) == (a_rcStrict2)) \ + { /* likely */ } \ + else if ( (a_rcStrict) == VINF_SUCCESS \ + || (a_rcStrict) > (a_rcStrict2)) \ + (a_rcStrict) = (a_rcStrict2); \ + } while (0) +#elif defined(IN_RC) +# define PGM_PHYS_RW_DO_UPDATE_STRICT_RC(a_rcStrict, a_rcStrict2) \ + do { \ + Assert(PGM_PHYS_RW_IS_SUCCESS(rcStrict)); \ + Assert(PGM_PHYS_RW_IS_SUCCESS(rcStrict2)); \ + AssertCompile(VINF_SELM_SYNC_GDT > VINF_EM_LAST); \ + AssertCompile(VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT > VINF_EM_LAST); \ + AssertCompile(VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT < VINF_SELM_SYNC_GDT); \ + AssertCompile(VINF_IOM_R3_MMIO_COMMIT_WRITE > VINF_EM_LAST); \ + AssertCompile(VINF_IOM_R3_MMIO_COMMIT_WRITE > VINF_SELM_SYNC_GDT); \ + AssertCompile(VINF_IOM_R3_MMIO_COMMIT_WRITE > VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT); \ + if ((a_rcStrict2) == VINF_SUCCESS || (a_rcStrict) == (a_rcStrict2)) \ + { /* likely */ } \ + else if ((a_rcStrict) == VINF_SUCCESS) \ + (a_rcStrict) = (a_rcStrict2); \ + else if ( ( (a_rcStrict) > (a_rcStrict2) \ + && ( (a_rcStrict2) <= VINF_EM_RESET \ + || (a_rcStrict) != VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT) ) \ + || ( (a_rcStrict2) == VINF_EM_RAW_EMULATE_INSTR_GDT_FAULT \ + && (a_rcStrict) > VINF_EM_RESET) ) \ + (a_rcStrict) = (a_rcStrict2); \ + } while (0) +#endif + +VMMDECL(VBOXSTRICTRC) PGMPhysRead(PVMCC pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, PGMACCESSORIGIN enmOrigin); +VMMDECL(VBOXSTRICTRC) PGMPhysWrite(PVMCC pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, PGMACCESSORIGIN enmOrigin); +VMMDECL(VBOXSTRICTRC) PGMPhysReadGCPtr(PVMCPUCC pVCpu, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, PGMACCESSORIGIN enmOrigin); +VMMDECL(VBOXSTRICTRC) PGMPhysWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb, PGMACCESSORIGIN enmOrigin); + +VMMDECL(int) PGMPhysSimpleReadGCPhys(PVMCC pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleWriteGCPhys(PVMCC pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleReadGCPtr(PVMCPUCC pVCpu, void *pvDst, RTGCPTR GCPtrSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb); +VMMDECL(int) PGMPhysSimpleDirtyWriteGCPtr(PVMCPUCC pVCpu, RTGCPTR GCPtrDst, const void *pvSrc, size_t cb); + +VMM_INT_DECL(int) PGMPhysIemGCPhys2Ptr(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers, void **ppv, PPGMPAGEMAPLOCK pLock); +VMM_INT_DECL(int) PGMPhysIemQueryAccess(PVMCC pVM, RTGCPHYS GCPhys, bool fWritable, bool fByPassHandlers); +VMM_INT_DECL(int) PGMPhysIemGCPhys2PtrNoLock(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, uint64_t const volatile *puTlbPhysRev, +#if defined(IN_RC) + R3PTRTYPE(uint8_t *) *ppb, +#else + R3R0PTRTYPE(uint8_t *) *ppb, +#endif + uint64_t *pfTlb); +/** @name Flags returned by PGMPhysIemGCPhys2PtrNoLock + * @{ */ +#define PGMIEMGCPHYS2PTR_F_NO_WRITE RT_BIT_32(3) /**< Not writable (IEMTLBE_F_PG_NO_WRITE). */ +#define PGMIEMGCPHYS2PTR_F_NO_READ RT_BIT_32(4) /**< Not readable (IEMTLBE_F_PG_NO_READ). */ +#define PGMIEMGCPHYS2PTR_F_NO_MAPPINGR3 RT_BIT_32(7) /**< No ring-3 mapping (IEMTLBE_F_NO_MAPPINGR3). */ +#define PGMIEMGCPHYS2PTR_F_UNASSIGNED RT_BIT_32(8) /**< Unassgined memory (IEMTLBE_F_PG_UNASSIGNED). */ +/** @} */ + +/** Information returned by PGMPhysNemQueryPageInfo. */ +typedef struct PGMPHYSNEMPAGEINFO +{ + /** The host physical address of the page, NIL_HCPHYS if invalid page. */ + RTHCPHYS HCPhys; + /** The NEM access mode for the page, NEM_PAGE_PROT_XXX */ + uint32_t fNemProt : 8; + /** The NEM state associated with the PAGE. */ + uint32_t u2NemState : 2; + /** The NEM state associated with the PAGE before pgmPhysPageMakeWritable was called. */ + uint32_t u2OldNemState : 2; + /** Set if the page has handler. */ + uint32_t fHasHandlers : 1; + /** Set if is the zero page backing it. */ + uint32_t fZeroPage : 1; + /** Set if the page has handler. */ + PGMPAGETYPE enmType; +} PGMPHYSNEMPAGEINFO; +/** Pointer to page information for NEM. */ +typedef PGMPHYSNEMPAGEINFO *PPGMPHYSNEMPAGEINFO; +/** + * Callback for checking that the page is in sync while under the PGM lock. + * + * NEM passes this callback to PGMPhysNemQueryPageInfo to check that the page is + * in-sync between PGM and the native hypervisor API in an atomic fashion. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pVCpu The cross context per virtual CPU structure. Optional, + * see PGMPhysNemQueryPageInfo. + * @param GCPhys The guest physical address (not A20 masked). + * @param pInfo The page info structure. This function updates the + * u2NemState memory and the caller will update the PGMPAGE + * copy accordingly. + * @param pvUser Callback user argument. + */ +typedef DECLCALLBACKTYPE(int, FNPGMPHYSNEMCHECKPAGE,(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, PPGMPHYSNEMPAGEINFO pInfo, void *pvUser)); +/** Pointer to a FNPGMPHYSNEMCHECKPAGE function. */ +typedef FNPGMPHYSNEMCHECKPAGE *PFNPGMPHYSNEMCHECKPAGE; + +VMM_INT_DECL(int) PGMPhysNemPageInfoChecker(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, bool fMakeWritable, + PPGMPHYSNEMPAGEINFO pInfo, PFNPGMPHYSNEMCHECKPAGE pfnChecker, void *pvUser); + +/** + * Callback for use with PGMPhysNemEnumPagesByState. + * @returns VBox status code. + * Failure status will stop enumeration immediately and return. + * @param pVM The cross context VM structure. + * @param pVCpu The cross context per virtual CPU structure. Optional, + * see PGMPhysNemEnumPagesByState. + * @param GCPhys The guest physical address (not A20 masked). + * @param pu2NemState Pointer to variable with the NEM state. This can be + * update. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNPGMPHYSNEMENUMCALLBACK,(PVMCC pVM, PVMCPUCC pVCpu, RTGCPHYS GCPhys, + uint8_t *pu2NemState, void *pvUser)); +/** Pointer to a FNPGMPHYSNEMENUMCALLBACK function. */ +typedef FNPGMPHYSNEMENUMCALLBACK *PFNPGMPHYSNEMENUMCALLBACK; +VMM_INT_DECL(int) PGMPhysNemEnumPagesByState(PVMCC pVM, PVMCPUCC VCpu, uint8_t uMinState, + PFNPGMPHYSNEMENUMCALLBACK pfnCallback, void *pvUser); + + +#ifdef VBOX_STRICT +VMMDECL(unsigned) PGMAssertHandlerAndFlagsInSync(PVMCC pVM); +VMMDECL(unsigned) PGMAssertNoMappingConflicts(PVM pVM); +VMMDECL(unsigned) PGMAssertCR3(PVMCC pVM, PVMCPUCC pVCpu, uint64_t cr3, uint64_t cr4); +#endif /* VBOX_STRICT */ + +VMMDECL(int) PGMSetLargePageUsage(PVMCC pVM, bool fUseLargePages); + +/** + * Query large page usage state + * + * @returns 0 - disabled, 1 - enabled + * @param pVM The cross context VM structure. + */ +#define PGMIsUsingLargePages(pVM) ((pVM)->pgm.s.fUseLargePages) + + +#ifdef IN_RING0 +/** @defgroup grp_pgm_r0 The PGM Host Context Ring-0 API + * @{ + */ +VMMR0_INT_DECL(int) PGMR0InitPerVMData(PGVM pGVM, RTR0MEMOBJ hMemObj); +VMMR0_INT_DECL(int) PGMR0InitVM(PGVM pGVM); +VMMR0_INT_DECL(void) PGMR0DoneInitVM(PGVM pGVM); +VMMR0_INT_DECL(void) PGMR0CleanupVM(PGVM pGVM); +VMMR0_INT_DECL(int) PGMR0PhysAllocateHandyPages(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) PGMR0PhysFlushHandyPages(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(int) PGMR0PhysAllocateLargePage(PGVM pGVM, VMCPUID idCpu, RTGCPHYS GCPhys); +VMMR0_INT_DECL(int) PGMR0PhysMMIO2MapKernel(PGVM pGVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, + size_t offSub, size_t cbSub, void **ppvMapping); +VMMR0_INT_DECL(int) PGMR0PhysSetupIoMmu(PGVM pGVM); +VMMR0_INT_DECL(int) PGMR0PhysHandlerInitReqHandler(PGVM pGVM, uint32_t cEntries); +VMMR0_INT_DECL(int) PGMR0HandlerPhysicalTypeSetUpContext(PGVM pGVM, PGMPHYSHANDLERKIND enmKind, uint32_t fFlags, + PFNPGMPHYSHANDLER pfnHandler, PFNPGMRZPHYSPFHANDLER pfnPfHandler, + const char *pszDesc, PGMPHYSHANDLERTYPE hType); + +VMMR0DECL(int) PGMR0SharedModuleCheck(PVMCC pVM, PGVM pGVM, VMCPUID idCpu, PGMMSHAREDMODULE pModule, + PCRTGCPTR64 paRegionsGCPtrs); +VMMR0DECL(int) PGMR0Trap0eHandlerNestedPaging(PGVM pGVM, PGVMCPU pGVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr, + PCPUMCTX pCtx, RTGCPHYS pvFault); +VMMR0DECL(VBOXSTRICTRC) PGMR0Trap0eHandlerNPMisconfig(PGVM pGVM, PGVMCPU pGVCpu, PGMMODE enmShwPagingMode, + PCPUMCTX pCtx, RTGCPHYS GCPhysFault, uint32_t uErr); +VMMR0_INT_DECL(int) PGMR0PoolGrow(PGVM pGVM, VMCPUID idCpu); + +# ifdef VBOX_WITH_NESTED_HWVIRT_VMX_EPT +VMMR0DECL(VBOXSTRICTRC) PGMR0NestedTrap0eHandlerNestedPaging(PGVMCPU pGVCpu, PGMMODE enmShwPagingMode, RTGCUINT uErr, + PCPUMCTX pCtx, RTGCPHYS GCPhysNestedFault, + bool fIsLinearAddrValid, RTGCPTR GCPtrNestedFault, PPGMPTWALK pWalk); +# endif +/** @} */ +#endif /* IN_RING0 */ + + + +#ifdef IN_RING3 +/** @defgroup grp_pgm_r3 The PGM Host Context Ring-3 API + * @{ + */ +VMMR3_INT_DECL(void) PGMR3EnableNemMode(PVM pVM); +VMMR3_INT_DECL(bool) PGMR3IsNemModeEnabled(PVM pVM); +VMMR3DECL(int) PGMR3Init(PVM pVM); +VMMR3DECL(int) PGMR3InitFinalize(PVM pVM); +VMMR3_INT_DECL(int) PGMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3DECL(void) PGMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3DECL(void) PGMR3ResetCpu(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(void) PGMR3Reset(PVM pVM); +VMMR3_INT_DECL(void) PGMR3ResetNoMorePhysWritesFlag(PVM pVM); +VMMR3_INT_DECL(void) PGMR3MemSetup(PVM pVM, bool fReset); +VMMR3DECL(int) PGMR3Term(PVM pVM); + +VMMR3DECL(int) PGMR3PhysRegisterRam(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, const char *pszDesc); +VMMR3DECL(int) PGMR3PhysChangeMemBalloon(PVM pVM, bool fInflate, unsigned cPages, RTGCPHYS *paPhysPage); +VMMR3DECL(int) PGMR3PhysWriteProtectRAM(PVM pVM); +VMMR3DECL(uint32_t) PGMR3PhysGetRamRangeCount(PVM pVM); +VMMR3DECL(int) PGMR3PhysGetRange(PVM pVM, uint32_t iRange, PRTGCPHYS pGCPhysStart, PRTGCPHYS pGCPhysLast, + const char **ppszDesc, bool *pfIsMmio); +VMMR3DECL(int) PGMR3QueryMemoryStats(PUVM pUVM, uint64_t *pcbTotalMem, uint64_t *pcbPrivateMem, uint64_t *pcbSharedMem, uint64_t *pcbZeroMem); +VMMR3DECL(int) PGMR3QueryGlobalMemoryStats(PUVM pUVM, uint64_t *pcbAllocMem, uint64_t *pcbFreeMem, uint64_t *pcbBallonedMem, uint64_t *pcbSharedMem); + +VMMR3DECL(int) PGMR3PhysMMIORegister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, PGMPHYSHANDLERTYPE hType, + uint64_t uUser, const char *pszDesc); +VMMR3DECL(int) PGMR3PhysMMIODeregister(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb); + +/** @name PGMPHYS_MMIO2_FLAGS_XXX - MMIO2 registration flags. + * @see PGMR3PhysMmio2Register, PDMDevHlpMmio2Create + * @{ */ +/** Track dirty pages. + * @see PGMR3PhysMmio2QueryAndResetDirtyBitmap(), PGMR3PhysMmio2ControlDirtyPageTracking(). */ +#define PGMPHYS_MMIO2_FLAGS_TRACK_DIRTY_PAGES RT_BIT_32(0) +/** Valid flags. */ +#define PGMPHYS_MMIO2_FLAGS_VALID_MASK UINT32_C(0x00000001) +/** @} */ + +VMMR3_INT_DECL(int) PGMR3PhysMmio2Register(PVM pVM, PPDMDEVINS pDevIns, uint32_t iSubDev, uint32_t iRegion, RTGCPHYS cb, + uint32_t fFlags, const char *pszDesc, void **ppv, PGMMMIO2HANDLE *phRegion); +VMMR3_INT_DECL(int) PGMR3PhysMmio2Deregister(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2); +VMMR3_INT_DECL(int) PGMR3PhysMmio2Map(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS GCPhys); +VMMR3_INT_DECL(int) PGMR3PhysMmio2Unmap(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS GCPhys); +VMMR3_INT_DECL(int) PGMR3PhysMmio2Reduce(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, RTGCPHYS cbRegion); +VMMR3_INT_DECL(int) PGMR3PhysMmio2ValidateHandle(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2); +VMMR3_INT_DECL(RTGCPHYS) PGMR3PhysMmio2GetMappingAddress(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2); +VMMR3_INT_DECL(int) PGMR3PhysMmio2ChangeRegionNo(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, uint32_t iNewRegion); +VMMR3_INT_DECL(int) PGMR3PhysMmio2QueryAndResetDirtyBitmap(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, + void *pvBitmap, size_t cbBitmap); +VMMR3_INT_DECL(int) PGMR3PhysMmio2ControlDirtyPageTracking(PVM pVM, PPDMDEVINS pDevIns, PGMMMIO2HANDLE hMmio2, bool fEnabled); + +/** @name PGMPHYS_ROM_FLAGS_XXX - ROM registration flags. + * @see PGMR3PhysRegisterRom, PDMDevHlpROMRegister + * @{ */ +/** Inidicates that ROM shadowing should be enabled. */ +#define PGMPHYS_ROM_FLAGS_SHADOWED UINT8_C(0x01) +/** Indicates that what pvBinary points to won't go away + * and can be used for strictness checks. */ +#define PGMPHYS_ROM_FLAGS_PERMANENT_BINARY UINT8_C(0x02) +/** Indicates that the ROM is allowed to be missing from saved state. + * @note This is a hack for EFI, see @bugref{6940} */ +#define PGMPHYS_ROM_FLAGS_MAYBE_MISSING_FROM_STATE UINT8_C(0x04) +/** Valid flags. */ +#define PGMPHYS_ROM_FLAGS_VALID_MASK UINT8_C(0x07) +/** @} */ + +VMMR3DECL(int) PGMR3PhysRomRegister(PVM pVM, PPDMDEVINS pDevIns, RTGCPHYS GCPhys, RTGCPHYS cb, + const void *pvBinary, uint32_t cbBinary, uint8_t fFlags, const char *pszDesc); +VMMR3DECL(int) PGMR3PhysRomProtect(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cb, PGMROMPROT enmProt); +VMMDECL(void) PGMR3PhysSetA20(PVMCPU pVCpu, bool fEnable); + +VMMR3_INT_DECL(int) PGMR3HandlerPhysicalTypeRegister(PVM pVM, PGMPHYSHANDLERKIND enmKind, uint32_t fFlags, + PFNPGMPHYSHANDLER pfnHandlerR3, const char *pszDesc, + PPGMPHYSHANDLERTYPE phType); + +VMMR3_INT_DECL(int) PGMR3PoolGrow(PVM pVM, PVMCPU pVCpu); + +VMMR3DECL(int) PGMR3PhysTlbGCPhys2Ptr(PVM pVM, RTGCPHYS GCPhys, bool fWritable, void **ppv); +VMMR3DECL(uint8_t) PGMR3PhysReadU8(PVM pVM, RTGCPHYS GCPhys, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(uint16_t) PGMR3PhysReadU16(PVM pVM, RTGCPHYS GCPhys, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(uint32_t) PGMR3PhysReadU32(PVM pVM, RTGCPHYS GCPhys, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(uint64_t) PGMR3PhysReadU64(PVM pVM, RTGCPHYS GCPhys, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(void) PGMR3PhysWriteU8(PVM pVM, RTGCPHYS GCPhys, uint8_t Value, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(void) PGMR3PhysWriteU16(PVM pVM, RTGCPHYS GCPhys, uint16_t Value, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(void) PGMR3PhysWriteU32(PVM pVM, RTGCPHYS GCPhys, uint32_t Value, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(void) PGMR3PhysWriteU64(PVM pVM, RTGCPHYS GCPhys, uint64_t Value, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(int) PGMR3PhysReadExternal(PVM pVM, RTGCPHYS GCPhys, void *pvBuf, size_t cbRead, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(int) PGMR3PhysWriteExternal(PVM pVM, RTGCPHYS GCPhys, const void *pvBuf, size_t cbWrite, PGMACCESSORIGIN enmOrigin); +VMMR3DECL(int) PGMR3PhysGCPhys2CCPtrExternal(PVM pVM, RTGCPHYS GCPhys, void **ppv, PPGMPAGEMAPLOCK pLock); +VMMR3DECL(int) PGMR3PhysGCPhys2CCPtrReadOnlyExternal(PVM pVM, RTGCPHYS GCPhys, void const **ppv, PPGMPAGEMAPLOCK pLock); +VMMR3DECL(int) PGMR3PhysBulkGCPhys2CCPtrExternal(PVM pVM, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + void **papvPages, PPGMPAGEMAPLOCK paLocks); +VMMR3DECL(int) PGMR3PhysBulkGCPhys2CCPtrReadOnlyExternal(PVM pVM, uint32_t cPages, PCRTGCPHYS paGCPhysPages, + void const **papvPages, PPGMPAGEMAPLOCK paLocks); +VMMR3DECL(void) PGMR3PhysChunkInvalidateTLB(PVM pVM); +VMMR3DECL(int) PGMR3PhysAllocateHandyPages(PVM pVM); + +VMMR3DECL(int) PGMR3CheckIntegrity(PVM pVM); + +VMMR3DECL(int) PGMR3DbgR3Ptr2GCPhys(PUVM pUVM, RTR3PTR R3Ptr, PRTGCPHYS pGCPhys); +VMMR3DECL(int) PGMR3DbgR3Ptr2HCPhys(PUVM pUVM, RTR3PTR R3Ptr, PRTHCPHYS pHCPhys); +VMMR3DECL(int) PGMR3DbgHCPhys2GCPhys(PUVM pUVM, RTHCPHYS HCPhys, PRTGCPHYS pGCPhys); +VMMR3_INT_DECL(int) PGMR3DbgReadGCPhys(PVM pVM, void *pvDst, RTGCPHYS GCPhysSrc, size_t cb, uint32_t fFlags, size_t *pcbRead); +VMMR3_INT_DECL(int) PGMR3DbgWriteGCPhys(PVM pVM, RTGCPHYS GCPhysDst, const void *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten); +VMMR3_INT_DECL(int) PGMR3DbgReadGCPtr(PVM pVM, void *pvDst, RTGCPTR GCPtrSrc, size_t cb, uint32_t fFlags, size_t *pcbRead); +VMMR3_INT_DECL(int) PGMR3DbgWriteGCPtr(PVM pVM, RTGCPTR GCPtrDst, void const *pvSrc, size_t cb, uint32_t fFlags, size_t *pcbWritten); +VMMR3_INT_DECL(int) PGMR3DbgScanPhysical(PVM pVM, RTGCPHYS GCPhys, RTGCPHYS cbRange, RTGCPHYS GCPhysAlign, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCPHYS pGCPhysHit); +VMMR3_INT_DECL(int) PGMR3DbgScanVirtual(PVM pVM, PVMCPU pVCpu, RTGCPTR GCPtr, RTGCPTR cbRange, RTGCPTR GCPtrAlign, const uint8_t *pabNeedle, size_t cbNeedle, PRTGCUINTPTR pGCPhysHit); +VMMR3_INT_DECL(int) PGMR3DumpHierarchyShw(PVM pVM, uint64_t cr3, uint32_t fFlags, uint64_t u64FirstAddr, uint64_t u64LastAddr, uint32_t cMaxDepth, PCDBGFINFOHLP pHlp); +VMMR3_INT_DECL(int) PGMR3DumpHierarchyGst(PVM pVM, uint64_t cr3, uint32_t fFlags, RTGCPTR FirstAddr, RTGCPTR LastAddr, uint32_t cMaxDepth, PCDBGFINFOHLP pHlp); + + +/** @name Page sharing + * @{ */ +VMMR3DECL(int) PGMR3SharedModuleRegister(PVM pVM, VBOXOSFAMILY enmGuestOS, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule, + uint32_t cRegions, VMMDEVSHAREDREGIONDESC const *paRegions); +VMMR3DECL(int) PGMR3SharedModuleUnregister(PVM pVM, char *pszModuleName, char *pszVersion, + RTGCPTR GCBaseAddr, uint32_t cbModule); +VMMR3DECL(int) PGMR3SharedModuleCheckAll(PVM pVM); +VMMR3DECL(int) PGMR3SharedModuleGetPageState(PVM pVM, RTGCPTR GCPtrPage, bool *pfShared, uint64_t *pfPageFlags); +/** @} */ + +/** @} */ +#endif /* IN_RING3 */ + +RT_C_DECLS_END + +/** @} */ +#endif /* !VBOX_INCLUDED_vmm_pgm_h */ + diff --git a/include/VBox/vmm/selm.h b/include/VBox/vmm/selm.h new file mode 100644 index 00000000..1b68e3f5 --- /dev/null +++ b/include/VBox/vmm/selm.h @@ -0,0 +1,114 @@ +/** @file + * SELM - The Selector Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_selm_h +#define VBOX_INCLUDED_vmm_selm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_selm The Selector Monitor(/Manager) API + * @ingroup grp_vmm + * @{ + */ + +VMMDECL(int) SELMGetTSSInfo(PVM pVM, PVMCPU pVCpu, PRTGCUINTPTR pGCPtrTss, PRTGCUINTPTR pcbTss, bool *pfCanHaveIOBitmap); +VMMDECL(RTGCPTR) SELMToFlat(PVMCPUCC pVCpu, unsigned idxSeg, PCPUMCTX pCtx, RTGCPTR Addr); +VMMDECL(RTGCPTR) SELMToFlatBySel(PVM pVM, RTSEL Sel, RTGCPTR Addr); + +/** Flags for SELMToFlatEx(). + * @{ */ +/** Don't check the RPL,DPL or CPL. */ +#define SELMTOFLAT_FLAGS_NO_PL RT_BIT(8) +/** Flags contains CPL information. */ +#define SELMTOFLAT_FLAGS_HAVE_CPL RT_BIT(9) +/** CPL is 3. */ +#define SELMTOFLAT_FLAGS_CPL3 3 +/** CPL is 2. */ +#define SELMTOFLAT_FLAGS_CPL2 2 +/** CPL is 1. */ +#define SELMTOFLAT_FLAGS_CPL1 1 +/** CPL is 0. */ +#define SELMTOFLAT_FLAGS_CPL0 0 +/** Get the CPL from the flags. */ +#define SELMTOFLAT_FLAGS_CPL(fFlags) ((fFlags) & X86_SEL_RPL) +#define SELMTOFLAT_FLAGS_HYPER RT_BIT(10) +/** @} */ + +VMMDECL(int) SELMToFlatEx(PVMCPU pVCpu, unsigned idxSeg, PCPUMCTX pCtx, RTGCPTR Addr, uint32_t fFlags, PRTGCPTR ppvGC); +VMMDECL(int) SELMValidateAndConvertCSAddr(PVMCPU pVCpu, uint32_t fEFlags, RTSEL SelCPL, RTSEL SelCS, + PCPUMSELREG pSRegCS, RTGCPTR Addr, PRTGCPTR ppvFlat); +#ifdef VBOX_WITH_RAW_MODE +VMM_INT_DECL(void) SELMLoadHiddenSelectorReg(PVMCPU pVCpu, PCCPUMCTX pCtx, PCPUMSELREG pSReg); +#endif + + +#ifdef IN_RING3 +/** @defgroup grp_selm_r3 The SELM ring-3 Context API + * @{ + */ +VMMR3DECL(int) SELMR3Init(PVM pVM); +VMMR3DECL(void) SELMR3Relocate(PVM pVM); +VMMR3DECL(int) SELMR3Term(PVM pVM); +VMMR3DECL(void) SELMR3Reset(PVM pVM); +VMMR3DECL(int) SELMR3GetSelectorInfo(PVMCPU pVCpu, RTSEL Sel, PDBGFSELINFO pSelInfo); +VMMR3DECL(void) SELMR3DumpDescriptor(X86DESC Desc, RTSEL Sel, const char *pszMsg); +VMMR3DECL(void) SELMR3DumpGuestGDT(PVM pVM); +VMMR3DECL(void) SELMR3DumpGuestLDT(PVM pVM); + +/** @def SELMR3_DEBUG_CHECK + * Invokes SELMR3DebugCheck in stricts builds. */ +# ifdef VBOX_STRICT +# define SELMR3_DEBUG_CHECK(pVM) SELMR3DebugCheck(pVM) +# else +# define SELMR3_DEBUG_CHECK(pVM) do { } while (0) +# endif +/** @} */ +#endif /* IN_RING3 */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_selm_h */ + diff --git a/include/VBox/vmm/ssm.h b/include/VBox/vmm/ssm.h new file mode 100644 index 00000000..591b5d7e --- /dev/null +++ b/include/VBox/vmm/ssm.h @@ -0,0 +1,1354 @@ +/** @file + * SSM - The Save State Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_ssm_h +#define VBOX_INCLUDED_vmm_ssm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + + +RT_C_DECLS_BEGIN + +/** @defgroup grp_ssm The Saved State Manager API + * @ingroup grp_vmm + * @{ + */ + +/** + * Determine the major version of the SSM version. If the major SSM version of two snapshots is + * different, the snapshots are incompatible. + */ +#define SSM_VERSION_MAJOR(ver) ((ver) & 0xffff0000) + +/** + * Determine the minor version of the SSM version. If the major SSM version of two snapshots is + * the same, the code must handle incompatibilies between minor version changes (e.g. use dummy + * values for non-existent fields). + */ +#define SSM_VERSION_MINOR(ver) ((ver) & 0x0000ffff) + +/** + * Determine if the major version changed between two SSM versions. + */ +#define SSM_VERSION_MAJOR_CHANGED(ver1,ver2) (SSM_VERSION_MAJOR(ver1) != SSM_VERSION_MAJOR(ver2)) + +/** The special value for the final pass. */ +#define SSM_PASS_FINAL UINT32_MAX + + +#ifdef IN_RING3 +/** @defgroup grp_ssm_r3 The SSM Host Context Ring-3 API + * @{ + */ + + +/** + * What to do after the save/load operation. + */ +typedef enum SSMAFTER +{ + /** Invalid. */ + SSMAFTER_INVALID = 0, + /** Will resume the loaded state. */ + SSMAFTER_RESUME, + /** Will destroy the VM after saving. */ + SSMAFTER_DESTROY, + /** Will continue execution after saving the VM. */ + SSMAFTER_CONTINUE, + /** Will teleport the VM. + * The source VM will be destroyed (then one saving), the destination VM + * will continue execution. */ + SSMAFTER_TELEPORT, + /** Will debug the saved state. + * This is used to drop some of the stricter consitentcy checks so it'll + * load fine in the debugger or animator. */ + SSMAFTER_DEBUG_IT, + /** The file was opened using SSMR3Open() and we have no idea what the plan is. */ + SSMAFTER_OPENED +} SSMAFTER; + + +/** Pointer to a structure field description. */ +typedef struct SSMFIELD *PSSMFIELD; +/** Pointer to a const structure field description. */ +typedef const struct SSMFIELD *PCSSMFIELD; + +/** + * SSMFIELD Get/Put callback function. + * + * This is call for getting and putting the field it is associated with. It's + * up to the callback to work the saved state correctly. + * + * @returns VBox status code. + * + * @param pSSM The saved state handle. + * @param pField The field that is being processed. + * @param pvStruct Pointer to the structure. + * @param fFlags SSMSTRUCT_FLAGS_XXX. + * @param fGetOrPut True if getting, false if putting. + * @param pvUser The user argument specified to SSMR3GetStructEx or + * SSMR3PutStructEx. + */ +typedef DECLCALLBACKTYPE(int, FNSSMFIELDGETPUT,(PSSMHANDLE pSSM, const struct SSMFIELD *pField, void *pvStruct, + uint32_t fFlags, bool fGetOrPut, void *pvUser)); +/** Pointer to a SSMFIELD Get/Put callback. */ +typedef FNSSMFIELDGETPUT *PFNSSMFIELDGETPUT; + +/** + * SSM field transformers. + * + * These are stored in the SSMFIELD::pfnGetPutOrTransformer and must therefore + * have values outside the valid pointer range. + */ +typedef enum SSMFIELDTRANS +{ + /** Invalid. */ + SSMFIELDTRANS_INVALID = 0, + /** No transformation. */ + SSMFIELDTRANS_NO_TRANSFORMATION, + /** Guest context (GC) physical address. */ + SSMFIELDTRANS_GCPHYS, + /** Guest context (GC) virtual address. */ + SSMFIELDTRANS_GCPTR, + /** Raw-mode context (RC) virtual address. */ + SSMFIELDTRANS_RCPTR, + /** Array of raw-mode context (RC) virtual addresses. */ + SSMFIELDTRANS_RCPTR_ARRAY, + /** Host context (HC) virtual address used as a NULL indicator. See + * SSMFIELD_ENTRY_HCPTR_NI. */ + SSMFIELDTRANS_HCPTR_NI, + /** Array of SSMFIELDTRANS_HCPTR_NI. */ + SSMFIELDTRANS_HCPTR_NI_ARRAY, + /** Host context (HC) virtual address used to hold a unsigned 32-bit value. */ + SSMFIELDTRANS_HCPTR_HACK_U32, + /** Load a 32-bit unsigned filed from the state and zero extend it into a 64-bit + * structure member. */ + SSMFIELDTRANS_U32_ZX_U64, + + /** Ignorable field. See SSMFIELD_ENTRY_IGNORE. */ + SSMFIELDTRANS_IGNORE, + /** Ignorable guest context (GC) physical address. */ + SSMFIELDTRANS_IGN_GCPHYS, + /** Ignorable guest context (GC) virtual address. */ + SSMFIELDTRANS_IGN_GCPTR, + /** Ignorable raw-mode context (RC) virtual address. */ + SSMFIELDTRANS_IGN_RCPTR, + /** Ignorable host context (HC) virtual address. */ + SSMFIELDTRANS_IGN_HCPTR, + + /** Old field. + * Save as zeros and skip on restore (nowhere to restore it any longer). */ + SSMFIELDTRANS_OLD, + /** Old guest context (GC) physical address. */ + SSMFIELDTRANS_OLD_GCPHYS, + /** Old guest context (GC) virtual address. */ + SSMFIELDTRANS_OLD_GCPTR, + /** Old raw-mode context (RC) virtual address. */ + SSMFIELDTRANS_OLD_RCPTR, + /** Old host context (HC) virtual address. */ + SSMFIELDTRANS_OLD_HCPTR, + /** Old host context specific padding. + * The lower word is the size of 32-bit hosts, the upper for 64-bit hosts. */ + SSMFIELDTRANS_OLD_PAD_HC, + /** Old padding specific to the 32-bit Microsoft C Compiler. */ + SSMFIELDTRANS_OLD_PAD_MSC32, + + /** Padding that differs between 32-bit and 64-bit hosts. + * The first byte of SSMFIELD::cb contains the size for 32-bit hosts. + * The second byte of SSMFIELD::cb contains the size for 64-bit hosts. + * The upper word of SSMFIELD::cb contains the actual field size. + */ + SSMFIELDTRANS_PAD_HC, + /** Padding for 32-bit hosts only. + * SSMFIELD::cb has the same format as for SSMFIELDTRANS_PAD_HC. */ + SSMFIELDTRANS_PAD_HC32, + /** Padding for 64-bit hosts only. + * SSMFIELD::cb has the same format as for SSMFIELDTRANS_PAD_HC. */ + SSMFIELDTRANS_PAD_HC64, + /** Automatic compiler padding that may differ between 32-bit and + * 64-bit hosts. SSMFIELD::cb has the same format as for + * SSMFIELDTRANS_PAD_HC. */ + SSMFIELDTRANS_PAD_HC_AUTO, + /** Automatic compiler padding specific to the 32-bit Microsoft C + * compiler. + * SSMFIELD::cb has the same format as for SSMFIELDTRANS_PAD_HC. */ + SSMFIELDTRANS_PAD_MSC32_AUTO +} SSMFIELDTRANS; + +/** Tests if it's a padding field with the special SSMFIELD::cb format. + * @returns true / false. + * @param pfn The SSMFIELD::pfnGetPutOrTransformer value. + */ +#define SSMFIELDTRANS_IS_PADDING(pfn) \ + ( (uintptr_t)(pfn) >= SSMFIELDTRANS_PAD_HC && (uintptr_t)(pfn) <= SSMFIELDTRANS_PAD_MSC32_AUTO ) + +/** Tests if it's an entry for an old field. + * + * @returns true / false. + * @param pfn The SSMFIELD::pfnGetPutOrTransformer value. + */ +#define SSMFIELDTRANS_IS_OLD(pfn) \ + ( (uintptr_t)(pfn) >= SSMFIELDTRANS_OLD && (uintptr_t)(pfn) <= SSMFIELDTRANS_OLD_PAD_MSC32 ) + +/** + * A structure field description. + */ +typedef struct SSMFIELD +{ + /** Getter and putter callback or transformer index. */ + PFNSSMFIELDGETPUT pfnGetPutOrTransformer; + /** Field offset into the structure. */ + uint32_t off; + /** The size of the field. */ + uint32_t cb; + /** This field was first saved by this unit version number. */ + uint32_t uFirstVer; + /** Field name. */ + const char *pszName; +} SSMFIELD; + +/** Emit a SSMFIELD array entry. + * @internal */ +#define SSMFIELD_ENTRY_INT(Name, off, cb, enmTransformer, uFirstVer) \ + { (PFNSSMFIELDGETPUT)(uintptr_t)(enmTransformer), (uint32_t)(off), (uint32_t)(cb), (uFirstVer), Name } +/** Emit a SSMFIELD array entry. + * @internal */ +#define SSMFIELD_ENTRY_TF_INT(Type, Field, enmTransformer, uFirstVer) \ + SSMFIELD_ENTRY_INT(#Type "::" #Field, RT_UOFFSETOF(Type, Field), RT_SIZEOFMEMB(Type, Field), enmTransformer, uFirstVer) +/** Emit a SSMFIELD array entry for an old field. + * @internal */ +#define SSMFIELD_ENTRY_OLD_INT(Field, cb, enmTransformer) \ + SSMFIELD_ENTRY_INT("old::" #Field, UINT32_MAX / 2, (cb), enmTransformer, 0) +/** Emit a SSMFIELD array entry for an alignment padding. + * @internal */ +#define SSMFIELD_ENTRY_PAD_INT(Type, Field, cb32, cb64, enmTransformer) \ + SSMFIELD_ENTRY_INT(#Type "::" #Field, RT_UOFFSETOF(Type, Field), \ + (RT_SIZEOFMEMB(Type, Field) << 16) | (cb32) | ((cb64) << 8), enmTransformer, 0) +/** Emit a SSMFIELD array entry for an alignment padding. + * @internal */ +#define SSMFIELD_ENTRY_PAD_OTHER_INT(Type, Field, cb32, cb64, enmTransformer) \ + SSMFIELD_ENTRY_INT(#Type "::" #Field, UINT32_MAX / 2, 0 | (cb32) | ((cb64) << 8), enmTransformer, 0) + +/** Emit a SSMFIELD array entry. */ +#define SSMFIELD_ENTRY(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_NO_TRANSFORMATION, 0) +/** Emit a SSMFIELD array entry with first version. */ +#define SSMFIELD_ENTRY_VER(Type, Field, uFirstVer) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_NO_TRANSFORMATION, uFirstVer) +/** Emit a SSMFIELD array entry for a custom made field. This is intended + * for working around bitfields in old structures. */ +#define SSMFIELD_ENTRY_CUSTOM(Field, off, cb) SSMFIELD_ENTRY_INT("custom::" #Field, off, cb, \ + SSMFIELDTRANS_NO_TRANSFORMATION, 0) +/** Emit a SSMFIELD array entry for a RTGCPHYS type. */ +#define SSMFIELD_ENTRY_GCPHYS(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_GCPHYS, 0) +/** Emit a SSMFIELD array entry for a RTGCPTR type. */ +#define SSMFIELD_ENTRY_GCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_GCPTR, 0) +/** Emit a SSMFIELD array entry for a raw-mode context pointer. */ +#define SSMFIELD_ENTRY_RCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_RCPTR, 0) +/** Emit a SSMFIELD array entry for a raw-mode context pointer. */ +#define SSMFIELD_ENTRY_RCPTR_ARRAY(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_RCPTR_ARRAY, 0) +/** Emit a SSMFIELD array entry for a ring-0 or ring-3 pointer type that is only + * of interest as a NULL indicator. + * + * This is always restored as a 0 (NULL) or 1 value. When + * SSMSTRUCT_FLAGS_DONT_IGNORE is set, the pointer will be saved in its + * entirety, when clear it will be saved as a boolean. */ +#define SSMFIELD_ENTRY_HCPTR_NI(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_HCPTR_NI, 0) +/** Same as SSMFIELD_ENTRY_HCPTR_NI, except it's an array of the buggers. */ +#define SSMFIELD_ENTRY_HCPTR_NI_ARRAY(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_HCPTR_NI_ARRAY, 0) +/** Emit a SSMFIELD array entry for a ring-0 or ring-3 pointer type that has + * been hacked such that it will never exceed 32-bit. No sign extending. */ +#define SSMFIELD_ENTRY_HCPTR_HACK_U32(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_HCPTR_HACK_U32, 0) +/** Emit a SSMFIELD array entry for loading a 32-bit field into a 64-bit + * structure member, zero extending the value. */ +#define SSMFIELD_ENTRY_U32_ZX_U64(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_U32_ZX_U64, 0) + +/** Emit a SSMFIELD array entry for a field that can be ignored. + * It is stored as zeros if SSMSTRUCT_FLAGS_DONT_IGNORE is specified to + * SSMR3PutStructEx. The member is never touched upon restore. */ +#define SSMFIELD_ENTRY_IGNORE(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGNORE, 0) +/** Emit a SSMFIELD array entry for an ignorable RTGCPHYS type. */ +#define SSMFIELD_ENTRY_IGN_GCPHYS(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGN_GCPHYS, 0) +/** Emit a SSMFIELD array entry for an ignorable RTGCPHYS type. */ +#define SSMFIELD_ENTRY_IGN_GCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGN_GCPTR, 0) +/** Emit a SSMFIELD array entry for an ignorable raw-mode context pointer. */ +#define SSMFIELD_ENTRY_IGN_RCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGN_RCPTR, 0) +/** Emit a SSMFIELD array entry for an ignorable ring-3 or/and ring-0 pointer. */ +#define SSMFIELD_ENTRY_IGN_HCPTR(Type, Field) SSMFIELD_ENTRY_TF_INT(Type, Field, SSMFIELDTRANS_IGN_HCPTR, 0) + +/** Emit a SSMFIELD array entry for an old field that should be ignored now. + * It is stored as zeros and skipped on load. */ +#define SSMFIELD_ENTRY_OLD(Field, cb) SSMFIELD_ENTRY_OLD_INT(Field, cb, SSMFIELDTRANS_OLD) +/** Same as SSMFIELD_ENTRY_IGN_GCPHYS, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_GCPHYS(Field) SSMFIELD_ENTRY_OLD_INT(Field, sizeof(RTGCPHYS), SSMFIELDTRANS_OLD_GCPHYS) +/** Same as SSMFIELD_ENTRY_IGN_GCPTR, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_GCPTR(Field) SSMFIELD_ENTRY_OLD_INT(Field, sizeof(RTGCPTR), SSMFIELDTRANS_OLD_GCPTR) +/** Same as SSMFIELD_ENTRY_IGN_RCPTR, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_RCPTR(Field) SSMFIELD_ENTRY_OLD_INT(Field, sizeof(RTRCPTR), SSMFIELDTRANS_OLD_RCPTR) +/** Same as SSMFIELD_ENTRY_IGN_HCPTR, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_HCPTR(Field) SSMFIELD_ENTRY_OLD_INT(Field, sizeof(RTHCPTR), SSMFIELDTRANS_OLD_HCPTR) +/** Same as SSMFIELD_ENTRY_PAD_HC, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_PAD_HC(Field, cb32, cb64) \ + SSMFIELD_ENTRY_OLD_INT(Field, RT_MAKE_U32((cb32), (cb64)), SSMFIELDTRANS_OLD_PAD_HC) +/** Same as SSMFIELD_ENTRY_PAD_HC64, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_PAD_HC64(Field, cb) SSMFIELD_ENTRY_OLD_PAD_HC(Field, 0, cb) +/** Same as SSMFIELD_ENTRY_PAD_HC32, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_PAD_HC32(Field, cb) SSMFIELD_ENTRY_OLD_PAD_HC(Field, cb, 0) +/** Same as SSMFIELD_ENTRY_PAD_HC, except there is no structure field. */ +#define SSMFIELD_ENTRY_OLD_PAD_MSC32(Field, cb) SSMFIELD_ENTRY_OLD_INT(Field, cb, SSMFIELDTRANS_OLD_PAD_MSC32) + +/** Emit a SSMFIELD array entry for a padding that differs in size between + * 64-bit and 32-bit hosts. */ +#define SSMFIELD_ENTRY_PAD_HC(Type, Field, cb32, cb64) SSMFIELD_ENTRY_PAD_INT( Type, Field, cb32, cb64, SSMFIELDTRANS_PAD_HC) +/** Emit a SSMFIELD array entry for a padding that is exclusive to 64-bit hosts. */ +#if HC_ARCH_BITS == 64 +# define SSMFIELD_ENTRY_PAD_HC64(Type, Field, cb) SSMFIELD_ENTRY_PAD_INT( Type, Field, 0, cb, SSMFIELDTRANS_PAD_HC64) +#else +# define SSMFIELD_ENTRY_PAD_HC64(Type, Field, cb) SSMFIELD_ENTRY_PAD_OTHER_INT(Type, Field, 0, cb, SSMFIELDTRANS_PAD_HC64) +#endif +/** Emit a SSMFIELD array entry for a 32-bit padding for on 64-bits hosts. */ +#if HC_ARCH_BITS == 32 +# define SSMFIELD_ENTRY_PAD_HC32(Type, Field, cb) SSMFIELD_ENTRY_PAD_INT( Type, Field, cb, 0, SSMFIELDTRANS_PAD_HC32) +#else +# define SSMFIELD_ENTRY_PAD_HC32(Type, Field, cb) SSMFIELD_ENTRY_PAD_OTHER_INT(Type, Field, cb, 0, SSMFIELDTRANS_PAD_HC32) +#endif +/** Emit a SSMFIELD array entry for an automatic compiler padding that may + * differ in size between 64-bit and 32-bit hosts. */ +#if HC_ARCH_BITS == 64 +# define SSMFIELD_ENTRY_PAD_HC_AUTO(cb32, cb64) \ + { \ + (PFNSSMFIELDGETPUT)(uintptr_t)(SSMFIELDTRANS_PAD_HC_AUTO), \ + UINT32_MAX / 2, (cb64 << 16) | (cb32) | ((cb64) << 8), 0, "" \ + } +#else +# define SSMFIELD_ENTRY_PAD_HC_AUTO(cb32, cb64) \ + { \ + (PFNSSMFIELDGETPUT)(uintptr_t)(SSMFIELDTRANS_PAD_HC_AUTO), \ + UINT32_MAX / 2, (cb32 << 16) | (cb32) | ((cb64) << 8), 0, "" \ + } +#endif +/** Emit a SSMFIELD array entry for an automatic compiler padding that is unique + * to the 32-bit microsoft compiler. This is usually used together with + * SSMFIELD_ENTRY_PAD_HC*. */ +#if HC_ARCH_BITS == 32 && defined(_MSC_VER) +# define SSMFIELD_ENTRY_PAD_MSC32_AUTO(cb) \ + { \ + (PFNSSMFIELDGETPUT)(uintptr_t)(SSMFIELDTRANS_PAD_MSC32_AUTO), \ + UINT32_MAX / 2, ((cb) << 16) | (cb), 0, "" \ + } +#else +# define SSMFIELD_ENTRY_PAD_MSC32_AUTO(cb) \ + { \ + (PFNSSMFIELDGETPUT)(uintptr_t)(SSMFIELDTRANS_PAD_MSC32_AUTO), \ + UINT32_MAX / 2, (cb), 0, "" \ + } +#endif + +/** Emit a SSMFIELD array entry for a field with a custom callback. */ +#define SSMFIELD_ENTRY_CALLBACK(Type, Field, pfnGetPut) \ + { (pfnGetPut), RT_UOFFSETOF(Type, Field), RT_SIZEOFMEMB(Type, Field), 0, #Type "::" #Field } +/** Emit the terminating entry of a SSMFIELD array. */ +#define SSMFIELD_ENTRY_TERM() \ + { (PFNSSMFIELDGETPUT)(uintptr_t)SSMFIELDTRANS_INVALID, UINT32_MAX, UINT32_MAX, UINT32_MAX, NULL } + + +/** @name SSMR3GetStructEx and SSMR3PutStructEx flags. + * @{ */ +/** The field descriptors must exactly cover the entire struct, A to Z. */ +#define SSMSTRUCT_FLAGS_FULL_STRUCT RT_BIT_32(0) +/** No start and end markers, just the raw bits. */ +#define SSMSTRUCT_FLAGS_NO_MARKERS RT_BIT_32(1) +/** Do not ignore any ignorable fields. */ +#define SSMSTRUCT_FLAGS_DONT_IGNORE RT_BIT_32(2) +/** Saved using SSMR3PutMem, don't be too strict. */ +#define SSMSTRUCT_FLAGS_SAVED_AS_MEM RT_BIT_32(3) +/** No introductory structure marker. Use when splitting up structures. */ +#define SSMSTRUCT_FLAGS_NO_LEAD_MARKER RT_BIT_32(4) +/** No trailing structure marker. Use when splitting up structures. */ +#define SSMSTRUCT_FLAGS_NO_TAIL_MARKER RT_BIT_32(5) + +/** Band-aid for old SSMR3PutMem/SSMR3GetMem of structurs with host pointers. + * @remarks This type is normally only used up to the first changes to the + * structures take place in order to make sure the conversion from + * SSMR3PutMem to field descriptors went smoothly. Replace with + * SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED when changing the structure. */ +#define SSMSTRUCT_FLAGS_MEM_BAND_AID ( SSMSTRUCT_FLAGS_DONT_IGNORE | SSMSTRUCT_FLAGS_FULL_STRUCT \ + | SSMSTRUCT_FLAGS_NO_MARKERS | SSMSTRUCT_FLAGS_SAVED_AS_MEM) +/** Band-aid for old SSMR3PutMem/SSMR3GetMem of structurs with host + * pointers, with relaxed checks. */ +#define SSMSTRUCT_FLAGS_MEM_BAND_AID_RELAXED ( SSMSTRUCT_FLAGS_DONT_IGNORE \ + | SSMSTRUCT_FLAGS_NO_MARKERS | SSMSTRUCT_FLAGS_SAVED_AS_MEM) +/** Mask of the valid bits. */ +#define SSMSTRUCT_FLAGS_VALID_MASK UINT32_C(0x0000003f) +/** @} */ + + +/** The PDM Device callback variants. + * @{ + */ + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @remarks The caller enters the device critical section prior to the call. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVLIVEPREP,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDEVLIVEPREP() function. */ +typedef FNSSMDEVLIVEPREP *PFNSSMDEVLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @param uPass The pass. + * @remarks The caller enters the device critical section prior to the call. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVLIVEEXEC,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMDEVLIVEEXEC() function. */ +typedef FNSSMDEVLIVEEXEC *PFNSSMDEVLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @remarks The caller enters the device critical section prior to the call. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVLIVEVOTE,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMDEVLIVEVOTE() function. */ +typedef FNSSMDEVLIVEVOTE *PFNSSMDEVLIVEVOTE; + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVSAVEPREP,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDEVSAVEPREP() function. */ +typedef FNSSMDEVSAVEPREP *PFNSSMDEVSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVSAVEEXEC,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDEVSAVEEXEC() function. */ +typedef FNSSMDEVSAVEEXEC *PFNSSMDEVSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVSAVEDONE,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDEVSAVEDONE() function. */ +typedef FNSSMDEVSAVEDONE *PFNSSMDEVSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVLOADPREP,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDEVLOADPREP() function. */ +typedef FNSSMDEVLOADPREP *PFNSSMDEVLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVLOADEXEC,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)); +/** Pointer to a FNSSMDEVLOADEXEC() function. */ +typedef FNSSMDEVLOADEXEC *PFNSSMDEVLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pDevIns Device instance of the device which registered the data unit. + * @param pSSM SSM operation handle. + * @remarks The caller enters the device critical section prior to the call. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDEVLOADDONE,(PPDMDEVINS pDevIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDEVLOADDONE() function. */ +typedef FNSSMDEVLOADDONE *PFNSSMDEVLOADDONE; + +/** @} */ + + +/** The PDM USB device callback variants. + * @{ + */ + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBLIVEPREP,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMUSBLIVEPREP() function. */ +typedef FNSSMUSBLIVEPREP *PFNSSMUSBLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + * @param uPass The pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBLIVEEXEC,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMUSBLIVEEXEC() function. */ +typedef FNSSMUSBLIVEEXEC *PFNSSMUSBLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBLIVEVOTE,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMUSBLIVEVOTE() function. */ +typedef FNSSMUSBLIVEVOTE *PFNSSMUSBLIVEVOTE; + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBSAVEPREP,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMUSBSAVEPREP() function. */ +typedef FNSSMUSBSAVEPREP *PFNSSMUSBSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBSAVEEXEC,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMUSBSAVEEXEC() function. */ +typedef FNSSMUSBSAVEEXEC *PFNSSMUSBSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBSAVEDONE,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMUSBSAVEDONE() function. */ +typedef FNSSMUSBSAVEDONE *PFNSSMUSBSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBLOADPREP,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMUSBLOADPREP() function. */ +typedef FNSSMUSBLOADPREP *PFNSSMUSBLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBLOADEXEC,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)); +/** Pointer to a FNSSMUSBLOADEXEC() function. */ +typedef FNSSMUSBLOADEXEC *PFNSSMUSBLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pUsbIns The USB device instance of the USB device which + * registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMUSBLOADDONE,(PPDMUSBINS pUsbIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMUSBLOADDONE() function. */ +typedef FNSSMUSBLOADDONE *PFNSSMUSBLOADDONE; + +/** @} */ + + +/** The PDM Driver callback variants. + * @{ + */ + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the + * data unit. + * @param pSSM SSM operation handle. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVLIVEPREP,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDRVLIVEPREP() function. */ +typedef FNSSMDRVLIVEPREP *PFNSSMDRVLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the + * data unit. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVLIVEEXEC,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMDRVLIVEEXEC() function. */ +typedef FNSSMDRVLIVEEXEC *PFNSSMDRVLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pDrvIns Driver instance of the driver which registered the + * data unit. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVLIVEVOTE,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMDRVLIVEVOTE() function. */ +typedef FNSSMDRVLIVEVOTE *PFNSSMDRVLIVEVOTE; + + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVSAVEPREP,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDRVSAVEPREP() function. */ +typedef FNSSMDRVSAVEPREP *PFNSSMDRVSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVSAVEEXEC,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDRVSAVEEXEC() function. */ +typedef FNSSMDRVSAVEEXEC *PFNSSMDRVSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVSAVEDONE,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDRVSAVEDONE() function. */ +typedef FNSSMDRVSAVEDONE *PFNSSMDRVSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVLOADPREP,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDRVLOADPREP() function. */ +typedef FNSSMDRVLOADPREP *PFNSSMDRVLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVLOADEXEC,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)); +/** Pointer to a FNSSMDRVLOADEXEC() function. */ +typedef FNSSMDRVLOADEXEC *PFNSSMDRVLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pDrvIns Driver instance of the driver which registered the data unit. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMDRVLOADDONE,(PPDMDRVINS pDrvIns, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMDRVLOADDONE() function. */ +typedef FNSSMDRVLOADDONE *PFNSSMDRVLOADDONE; + +/** @} */ + + +/** The internal callback variants. + * @{ + */ + + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTLIVEPREP,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTLIVEPREP() function. */ +typedef FNSSMINTLIVEPREP *PFNSSMINTLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTLIVEEXEC,(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMINTLIVEEXEC() function. */ +typedef FNSSMINTLIVEEXEC *PFNSSMINTLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTLIVEVOTE,(PVM pVM, PSSMHANDLE pSSM, uint32_t uPass)); +/** Pointer to a FNSSMINTLIVEVOTE() function. */ +typedef FNSSMINTLIVEVOTE *PFNSSMINTLIVEVOTE; + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTSAVEPREP,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTSAVEPREP() function. */ +typedef FNSSMINTSAVEPREP *PFNSSMINTSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTSAVEEXEC,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTSAVEEXEC() function. */ +typedef FNSSMINTSAVEEXEC *PFNSSMINTSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTSAVEDONE,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTSAVEDONE() function. */ +typedef FNSSMINTSAVEDONE *PFNSSMINTSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTLOADPREP,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTLOADPREP() function. */ +typedef FNSSMINTLOADPREP *PFNSSMINTLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTLOADEXEC,(PVM pVM, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass)); +/** Pointer to a FNSSMINTLOADEXEC() function. */ +typedef FNSSMINTLOADEXEC *PFNSSMINTLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pVM The cross context VM structure. + * @param pSSM SSM operation handle. + */ +typedef DECLCALLBACKTYPE(int, FNSSMINTLOADDONE,(PVM pVM, PSSMHANDLE pSSM)); +/** Pointer to a FNSSMINTLOADDONE() function. */ +typedef FNSSMINTLOADDONE *PFNSSMINTLOADDONE; + +/** @} */ + + +/** The External callback variants. + * @{ + */ + +/** + * Prepare state live save operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLIVEPREP,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTLIVEPREP() function. */ +typedef FNSSMEXTLIVEPREP *PFNSSMEXTLIVEPREP; + +/** + * Execute state live save operation. + * + * This will be called repeatedly until all units vote that the live phase has + * been concluded. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLIVEEXEC,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser, uint32_t uPass)); +/** Pointer to a FNSSMEXTLIVEEXEC() function. */ +typedef FNSSMEXTLIVEEXEC *PFNSSMEXTLIVEEXEC; + +/** + * Vote on whether the live part of the saving has been concluded. + * + * The vote stops once a unit has vetoed the decision, so don't rely upon this + * being called every time. + * + * @returns VBox status code. + * @retval VINF_SUCCESS if done. + * @retval VINF_SSM_VOTE_FOR_ANOTHER_PASS if another pass is needed. + * @retval VINF_SSM_VOTE_DONE_DONT_CALL_AGAIN if the live saving of the unit is + * done and there is not need calling it again before the final pass. + * @retval VERR_SSM_VOTE_FOR_GIVING_UP if its time to give up. + * + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + * @param uPass The data pass. + * @thread Any. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLIVEVOTE,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser, uint32_t uPass)); +/** Pointer to a FNSSMEXTLIVEVOTE() function. */ +typedef FNSSMEXTLIVEVOTE *PFNSSMEXTLIVEVOTE; + +/** + * Prepare state save operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTSAVEPREP,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTSAVEPREP() function. */ +typedef FNSSMEXTSAVEPREP *PFNSSMEXTSAVEPREP; + +/** + * Execute state save operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTSAVEEXEC,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTSAVEEXEC() function. */ +typedef FNSSMEXTSAVEEXEC *PFNSSMEXTSAVEEXEC; + +/** + * Done state save operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTSAVEDONE,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTSAVEDONE() function. */ +typedef FNSSMEXTSAVEDONE *PFNSSMEXTSAVEDONE; + +/** + * Prepare state load operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLOADPREP,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTLOADPREP() function. */ +typedef FNSSMEXTLOADPREP *PFNSSMEXTLOADPREP; + +/** + * Execute state load operation. + * + * @returns VBox status code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + * @param uVersion Data layout version. + * @param uPass The pass. This is always SSM_PASS_FINAL for units + * that doesn't specify a pfnSaveLive callback. + * @remark The odd return value is for legacy reasons. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLOADEXEC,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser, + uint32_t uVersion, uint32_t uPass)); +/** Pointer to a FNSSMEXTLOADEXEC() function. */ +typedef FNSSMEXTLOADEXEC *PFNSSMEXTLOADEXEC; + +/** + * Done state load operation. + * + * @returns VBox load code. + * @param pSSM SSM operation handle. + * @param pVMM The VMM ring-3 vtable. + * @param pvUser User argument. + */ +typedef DECLCALLBACKTYPE(int, FNSSMEXTLOADDONE,(PSSMHANDLE pSSM, PCVMMR3VTABLE pVMM, void *pvUser)); +/** Pointer to a FNSSMEXTLOADDONE() function. */ +typedef FNSSMEXTLOADDONE *PFNSSMEXTLOADDONE; + +/** @} */ + + +/** + * SSM stream method table. + * + * This is used by external parties for teleporting over TCP or any other media. + * SSM also uses this internally for file access, thus the 2-3 file centric + * methods. + */ +typedef struct SSMSTRMOPS +{ + /** Struct magic + version (SSMSTRMOPS_VERSION). */ + uint32_t u32Version; + + /** + * Write bytes to the stream. + * + * @returns VBox status code. + * @param pvUser The user argument. + * @param offStream The stream offset we're (supposed to be) at. + * @param pvBuf Pointer to the data. + * @param cbToWrite The number of bytes to write. + */ + DECLCALLBACKMEMBER(int, pfnWrite,(void *pvUser, uint64_t offStream, const void *pvBuf, size_t cbToWrite)); + + /** + * Read bytes to the stream. + * + * @returns VBox status code. + * @param pvUser The user argument. + * @param offStream The stream offset we're (supposed to be) at. + * @param pvBuf Where to return the bytes. + * @param cbToRead The number of bytes to read. + * @param pcbRead Where to return the number of bytes actually + * read. This may differ from cbToRead when the + * end of the stream is encountered. + */ + DECLCALLBACKMEMBER(int, pfnRead,(void *pvUser, uint64_t offStream, void *pvBuf, size_t cbToRead, size_t *pcbRead)); + + /** + * Seeks in the stream. + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if the stream doesn't support this action. + * + * @param pvUser The user argument. + * @param offSeek The seek offset. + * @param uMethod RTFILE_SEEK_BEGIN, RTFILE_SEEK_END or + * RTFILE_SEEK_CURRENT. + * @param poffActual Where to store the new file position. Optional. + */ + DECLCALLBACKMEMBER(int, pfnSeek,(void *pvUser, int64_t offSeek, unsigned uMethod, uint64_t *poffActual)); + + /** + * Get the current stream position. + * + * @returns The correct stream position. + * @param pvUser The user argument. + */ + DECLCALLBACKMEMBER(uint64_t, pfnTell,(void *pvUser)); + + /** + * Get the size/length of the stream. + * + * @returns VBox status code. + * @retval VERR_NOT_SUPPORTED if the stream doesn't support this action. + * + * @param pvUser The user argument. + * @param pcb Where to return the size/length. + */ + DECLCALLBACKMEMBER(int, pfnSize,(void *pvUser, uint64_t *pcb)); + + /** + * Check if the stream is OK or not (cancelled). + * + * @returns VBox status code. + * @param pvUser The user argument. + * + * @remarks The method is expected to do a LogRel on failure. + */ + DECLCALLBACKMEMBER(int, pfnIsOk,(void *pvUser)); + + /** + * Close the stream. + * + * @returns VBox status code. + * @param pvUser The user argument. + * @param fCancelled True if the operation was cancelled. + */ + DECLCALLBACKMEMBER(int, pfnClose,(void *pvUser, bool fCancelled)); + + /** Struct magic + version (SSMSTRMOPS_VERSION). */ + uint32_t u32EndVersion; +} SSMSTRMOPS; +/** Struct magic + version (SSMSTRMOPS_VERSION). */ +#define SSMSTRMOPS_VERSION UINT32_C(0x55aa0001) + + +VMMR3DECL(void) SSMR3Term(PVM pVM); +VMMR3_INT_DECL(int) +SSMR3RegisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, + size_t cbGuess, const char *pszBefore, + PFNSSMDEVLIVEPREP pfnLivePrep, PFNSSMDEVLIVEEXEC pfnLiveExec, PFNSSMDEVLIVEVOTE pfnLiveVote, + PFNSSMDEVSAVEPREP pfnSavePrep, PFNSSMDEVSAVEEXEC pfnSaveExec, PFNSSMDEVSAVEDONE pfnSaveDone, + PFNSSMDEVLOADPREP pfnLoadPrep, PFNSSMDEVLOADEXEC pfnLoadExec, PFNSSMDEVLOADDONE pfnLoadDone); +VMMR3_INT_DECL(int) +SSMR3RegisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, + PFNSSMDRVLIVEPREP pfnLivePrep, PFNSSMDRVLIVEEXEC pfnLiveExec, PFNSSMDRVLIVEVOTE pfnLiveVote, + PFNSSMDRVSAVEPREP pfnSavePrep, PFNSSMDRVSAVEEXEC pfnSaveExec, PFNSSMDRVSAVEDONE pfnSaveDone, + PFNSSMDRVLOADPREP pfnLoadPrep, PFNSSMDRVLOADEXEC pfnLoadExec, PFNSSMDRVLOADDONE pfnLoadDone); +VMMR3_INT_DECL(int) +SSMR3RegisterUsb(PVM pVM, PPDMUSBINS pUsbIns, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, + PFNSSMUSBLIVEPREP pfnLivePrep, PFNSSMUSBLIVEEXEC pfnLiveExec, PFNSSMUSBLIVEVOTE pfnLiveVote, + PFNSSMUSBSAVEPREP pfnSavePrep, PFNSSMUSBSAVEEXEC pfnSaveExec, PFNSSMUSBSAVEDONE pfnSaveDone, + PFNSSMUSBLOADPREP pfnLoadPrep, PFNSSMUSBLOADEXEC pfnLoadExec, PFNSSMUSBLOADDONE pfnLoadDone); +VMMR3DECL(int) +SSMR3RegisterInternal(PVM pVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, + PFNSSMINTLIVEPREP pfnLivePrep, PFNSSMINTLIVEEXEC pfnLiveExec, PFNSSMINTLIVEVOTE pfnLiveVote, + PFNSSMINTSAVEPREP pfnSavePrep, PFNSSMINTSAVEEXEC pfnSaveExec, PFNSSMINTSAVEDONE pfnSaveDone, + PFNSSMINTLOADPREP pfnLoadPrep, PFNSSMINTLOADEXEC pfnLoadExec, PFNSSMINTLOADDONE pfnLoadDone); +VMMR3DECL(int) +SSMR3RegisterExternal(PUVM pUVM, const char *pszName, uint32_t uInstance, uint32_t uVersion, size_t cbGuess, + PFNSSMEXTLIVEPREP pfnLivePrep, PFNSSMEXTLIVEEXEC pfnLiveExec, PFNSSMEXTLIVEVOTE pfnLiveVote, + PFNSSMEXTSAVEPREP pfnSavePrep, PFNSSMEXTSAVEEXEC pfnSaveExec, PFNSSMEXTSAVEDONE pfnSaveDone, + PFNSSMEXTLOADPREP pfnLoadPrep, PFNSSMEXTLOADEXEC pfnLoadExec, PFNSSMEXTLOADDONE pfnLoadDone, void *pvUser); +VMMR3DECL(int) SSMR3RegisterStub(PVM pVM, const char *pszName, uint32_t uInstance); +VMMR3_INT_DECL(int) SSMR3DeregisterDevice(PVM pVM, PPDMDEVINS pDevIns, const char *pszName, uint32_t uInstance); +VMMR3_INT_DECL(int) SSMR3DeregisterDriver(PVM pVM, PPDMDRVINS pDrvIns, const char *pszName, uint32_t uInstance); +VMMR3_INT_DECL(int) SSMR3DeregisterUsb(PVM pVM, PPDMUSBINS pUsbIns, const char *pszName, uint32_t uInstance); +VMMR3DECL(int) SSMR3DeregisterInternal(PVM pVM, const char *pszName); +VMMR3DECL(int) SSMR3DeregisterExternal(PUVM pUVM, const char *pszName); +VMMR3DECL(int) SSMR3Save(PVM pVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvUser); +VMMR3_INT_DECL(int) SSMR3LiveSave(PVM pVM, uint32_t cMsMaxDowntime, + const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOps, + SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvProgressUser, + PSSMHANDLE *ppSSM); +VMMR3_INT_DECL(int) SSMR3LiveDoStep1(PSSMHANDLE pSSM); +VMMR3_INT_DECL(int) SSMR3LiveDoStep2(PSSMHANDLE pSSM); +VMMR3_INT_DECL(int) SSMR3LiveDone(PSSMHANDLE pSSM); +VMMR3DECL(int) SSMR3Load(PVM pVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, + SSMAFTER enmAfter, PFNVMPROGRESS pfnProgress, void *pvProgressUser); +VMMR3DECL(int) SSMR3ValidateFile(const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOps, + bool fChecksumIt); +VMMR3DECL(int) SSMR3Open(const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOps, + unsigned fFlags, PSSMHANDLE *ppSSM); +VMMR3DECL(int) SSMR3Close(PSSMHANDLE pSSM); +VMMR3DECL(int) SSMR3Seek(PSSMHANDLE pSSM, const char *pszUnit, uint32_t iInstance, uint32_t *piVersion); +VMMR3DECL(int) SSMR3HandleGetStatus(PSSMHANDLE pSSM); +VMMR3DECL(int) SSMR3HandleSetStatus(PSSMHANDLE pSSM, int iStatus); +VMMR3DECL(SSMAFTER) SSMR3HandleGetAfter(PSSMHANDLE pSSM); +VMMR3DECL(bool) SSMR3HandleIsLiveSave(PSSMHANDLE pSSM); +VMMR3DECL(uint32_t) SSMR3HandleMaxDowntime(PSSMHANDLE pSSM); +VMMR3DECL(uint32_t) SSMR3HandleHostBits(PSSMHANDLE pSSM); +VMMR3DECL(uint32_t) SSMR3HandleRevision(PSSMHANDLE pSSM); +VMMR3DECL(uint32_t) SSMR3HandleVersion(PSSMHANDLE pSSM); +VMMR3DECL(const char *) SSMR3HandleHostOSAndArch(PSSMHANDLE pSSM); +VMMR3_INT_DECL(int) SSMR3HandleSetGCPtrSize(PSSMHANDLE pSSM, unsigned cbGCPtr); +VMMR3DECL(void) SSMR3HandleReportLivePercent(PSSMHANDLE pSSM, unsigned uPercent); +#ifdef DEBUG +VMMR3DECL(uint64_t) SSMR3HandleTellInUnit(PSSMHANDLE pSSM); +#endif +VMMR3DECL(int) SSMR3Cancel(PUVM pUVM); + + +/** Save operations. + * @{ + */ +VMMR3DECL(int) SSMR3PutStruct(PSSMHANDLE pSSM, const void *pvStruct, PCSSMFIELD paFields); +VMMR3DECL(int) SSMR3PutStructEx(PSSMHANDLE pSSM, const void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser); +VMMR3DECL(int) SSMR3PutBool(PSSMHANDLE pSSM, bool fBool); +VMMR3DECL(int) SSMR3PutU8(PSSMHANDLE pSSM, uint8_t u8); +VMMR3DECL(int) SSMR3PutS8(PSSMHANDLE pSSM, int8_t i8); +VMMR3DECL(int) SSMR3PutU16(PSSMHANDLE pSSM, uint16_t u16); +VMMR3DECL(int) SSMR3PutS16(PSSMHANDLE pSSM, int16_t i16); +VMMR3DECL(int) SSMR3PutU32(PSSMHANDLE pSSM, uint32_t u32); +VMMR3DECL(int) SSMR3PutS32(PSSMHANDLE pSSM, int32_t i32); +VMMR3DECL(int) SSMR3PutU64(PSSMHANDLE pSSM, uint64_t u64); +VMMR3DECL(int) SSMR3PutS64(PSSMHANDLE pSSM, int64_t i64); +VMMR3DECL(int) SSMR3PutU128(PSSMHANDLE pSSM, uint128_t u128); +VMMR3DECL(int) SSMR3PutS128(PSSMHANDLE pSSM, int128_t i128); +VMMR3DECL(int) SSMR3PutUInt(PSSMHANDLE pSSM, RTUINT u); +VMMR3DECL(int) SSMR3PutSInt(PSSMHANDLE pSSM, RTINT i); +VMMR3DECL(int) SSMR3PutGCUInt(PSSMHANDLE pSSM, RTGCUINT u); +VMMR3DECL(int) SSMR3PutGCUIntReg(PSSMHANDLE pSSM, RTGCUINTREG u); +VMMR3DECL(int) SSMR3PutGCPhys32(PSSMHANDLE pSSM, RTGCPHYS32 GCPhys); +VMMR3DECL(int) SSMR3PutGCPhys64(PSSMHANDLE pSSM, RTGCPHYS64 GCPhys); +VMMR3DECL(int) SSMR3PutGCPhys(PSSMHANDLE pSSM, RTGCPHYS GCPhys); +VMMR3DECL(int) SSMR3PutGCPtr(PSSMHANDLE pSSM, RTGCPTR GCPtr); +VMMR3DECL(int) SSMR3PutGCUIntPtr(PSSMHANDLE pSSM, RTGCUINTPTR GCPtr); +VMMR3DECL(int) SSMR3PutRCPtr(PSSMHANDLE pSSM, RTRCPTR RCPtr); +VMMR3DECL(int) SSMR3PutIOPort(PSSMHANDLE pSSM, RTIOPORT IOPort); +VMMR3DECL(int) SSMR3PutSel(PSSMHANDLE pSSM, RTSEL Sel); +VMMR3DECL(int) SSMR3PutMem(PSSMHANDLE pSSM, const void *pv, size_t cb); +VMMR3DECL(int) SSMR3PutStrZ(PSSMHANDLE pSSM, const char *psz); +/** @} */ + + + +/** Load operations. + * @{ + */ +VMMR3DECL(int) SSMR3GetStruct(PSSMHANDLE pSSM, void *pvStruct, PCSSMFIELD paFields); +VMMR3DECL(int) SSMR3GetStructEx(PSSMHANDLE pSSM, void *pvStruct, size_t cbStruct, uint32_t fFlags, PCSSMFIELD paFields, void *pvUser); +VMMR3DECL(int) SSMR3GetBool(PSSMHANDLE pSSM, bool *pfBool); +VMMR3DECL(int) SSMR3GetBoolV(PSSMHANDLE pSSM, bool volatile *pfBool); +VMMR3DECL(int) SSMR3GetU8(PSSMHANDLE pSSM, uint8_t *pu8); +VMMR3DECL(int) SSMR3GetU8V(PSSMHANDLE pSSM, uint8_t volatile *pu8); +VMMR3DECL(int) SSMR3GetS8(PSSMHANDLE pSSM, int8_t *pi8); +VMMR3DECL(int) SSMR3GetS8V(PSSMHANDLE pSSM, int8_t volatile *pi8); +VMMR3DECL(int) SSMR3GetU16(PSSMHANDLE pSSM, uint16_t *pu16); +VMMR3DECL(int) SSMR3GetU16V(PSSMHANDLE pSSM, uint16_t volatile *pu16); +VMMR3DECL(int) SSMR3GetS16(PSSMHANDLE pSSM, int16_t *pi16); +VMMR3DECL(int) SSMR3GetS16V(PSSMHANDLE pSSM, int16_t volatile *pi16); +VMMR3DECL(int) SSMR3GetU32(PSSMHANDLE pSSM, uint32_t *pu32); +VMMR3DECL(int) SSMR3GetU32V(PSSMHANDLE pSSM, uint32_t volatile *pu32); +VMMR3DECL(int) SSMR3GetS32(PSSMHANDLE pSSM, int32_t *pi32); +VMMR3DECL(int) SSMR3GetS32V(PSSMHANDLE pSSM, int32_t volatile *pi32); +VMMR3DECL(int) SSMR3GetU64(PSSMHANDLE pSSM, uint64_t *pu64); +VMMR3DECL(int) SSMR3GetU64V(PSSMHANDLE pSSM, uint64_t volatile *pu64); +VMMR3DECL(int) SSMR3GetS64(PSSMHANDLE pSSM, int64_t *pi64); +VMMR3DECL(int) SSMR3GetS64V(PSSMHANDLE pSSM, int64_t volatile *pi64); +VMMR3DECL(int) SSMR3GetU128(PSSMHANDLE pSSM, uint128_t *pu128); +VMMR3DECL(int) SSMR3GetU128V(PSSMHANDLE pSSM, uint128_t volatile *pu128); +VMMR3DECL(int) SSMR3GetS128(PSSMHANDLE pSSM, int128_t *pi128); +VMMR3DECL(int) SSMR3GetS128V(PSSMHANDLE pSSM, int128_t volatile *pi128); +VMMR3DECL(int) SSMR3GetGCPhys32(PSSMHANDLE pSSM, PRTGCPHYS32 pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys32V(PSSMHANDLE pSSM, RTGCPHYS32 volatile *pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys64(PSSMHANDLE pSSM, PRTGCPHYS64 pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys64V(PSSMHANDLE pSSM, RTGCPHYS64 volatile *pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhys(PSSMHANDLE pSSM, PRTGCPHYS pGCPhys); +VMMR3DECL(int) SSMR3GetGCPhysV(PSSMHANDLE pSSM, RTGCPHYS volatile *pGCPhys); +VMMR3DECL(int) SSMR3GetUInt(PSSMHANDLE pSSM, PRTUINT pu); +VMMR3DECL(int) SSMR3GetSInt(PSSMHANDLE pSSM, PRTINT pi); +VMMR3DECL(int) SSMR3GetGCUInt(PSSMHANDLE pSSM, PRTGCUINT pu); +VMMR3DECL(int) SSMR3GetGCUIntReg(PSSMHANDLE pSSM, PRTGCUINTREG pu); +VMMR3DECL(int) SSMR3GetGCPtr(PSSMHANDLE pSSM, PRTGCPTR pGCPtr); +VMMR3DECL(int) SSMR3GetGCUIntPtr(PSSMHANDLE pSSM, PRTGCUINTPTR pGCPtr); +VMMR3DECL(int) SSMR3GetRCPtr(PSSMHANDLE pSSM, PRTRCPTR pRCPtr); +VMMR3DECL(int) SSMR3GetIOPort(PSSMHANDLE pSSM, PRTIOPORT pIOPort); +VMMR3DECL(int) SSMR3GetSel(PSSMHANDLE pSSM, PRTSEL pSel); +VMMR3DECL(int) SSMR3GetMem(PSSMHANDLE pSSM, void *pv, size_t cb); +VMMR3DECL(int) SSMR3GetStrZ(PSSMHANDLE pSSM, char *psz, size_t cbMax); +VMMR3DECL(int) SSMR3GetStrZEx(PSSMHANDLE pSSM, char *psz, size_t cbMax, size_t *pcbStr); +VMMR3DECL(int) SSMR3Skip(PSSMHANDLE pSSM, size_t cb); +VMMR3DECL(int) SSMR3SkipToEndOfUnit(PSSMHANDLE pSSM); +VMMR3DECL(int) SSMR3SetLoadError(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMR3DECL(int) SSMR3SetLoadErrorV(PSSMHANDLE pSSM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0); +VMMR3DECL(int) SSMR3SetCfgError(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(5, 6); +VMMR3DECL(int) SSMR3SetCfgErrorV(PSSMHANDLE pSSM, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(5, 0); + +/** Wrapper around SSMR3GetU32 for simplifying getting enum values saved as uint32_t. */ +# define SSM_GET_ENUM32_RET(a_pSSM, a_enmDst, a_EnumType) \ + do { \ + uint32_t u32GetEnumTmp = 0; \ + int rcGetEnum32Tmp = SSMR3GetU32((a_pSSM), &u32GetEnumTmp); \ + AssertRCReturn(rcGetEnum32Tmp, rcGetEnum32Tmp); \ + (a_enmDst) = (a_EnumType)u32GetEnumTmp; \ + AssertCompile(sizeof(a_EnumType) == sizeof(u32GetEnumTmp)); \ + } while (0) + +/** @} */ + +/** @} */ +#endif /* IN_RING3 */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_ssm_h */ + diff --git a/include/VBox/vmm/stam.h b/include/VBox/vmm/stam.h new file mode 100644 index 00000000..4c5764b4 --- /dev/null +++ b/include/VBox/vmm/stam.h @@ -0,0 +1,1376 @@ +/** @file + * STAM - Statistics Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_stam_h +#define VBOX_INCLUDED_vmm_stam_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#ifdef _MSC_VER +# if RT_MSC_PREREQ(RT_MSC_VER_VS2005) +# include +# endif +#endif +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) +# include +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_stam The Statistics Manager API + * @ingroup grp_vmm + * @{ + */ + +#if defined(VBOX_WITHOUT_RELEASE_STATISTICS) && defined(VBOX_WITH_STATISTICS) +# error "Both VBOX_WITHOUT_RELEASE_STATISTICS and VBOX_WITH_STATISTICS are defined! Make up your mind!" +#endif + + +/** @def STAM_GET_TS + * Gets the CPU timestamp counter. + * + * @param u64 The 64-bit variable which the timestamp shall be saved in. + */ +#if defined(RT_ARCH_ARM64) || defined(RT_ARCH_ARM32) +# define STAM_GET_TS(u64) do { (u64) = ASMReadTSC(); } while (0) +#elif defined(__GNUC__) +# if defined(RT_ARCH_X86) + /* This produces optimal assembler code for x86 but does not work for AMD64 ('A' means 'either rax or rdx') */ +# define STAM_GET_TS(u64) __asm__ __volatile__ ("rdtsc\n\t" : "=A" (u64)) +# elif defined(RT_ARCH_AMD64) +# define STAM_GET_TS(u64) \ + do { uint64_t low; uint64_t high; \ + __asm__ __volatile__ ("rdtsc\n\t" : "=a"(low), "=d"(high)); \ + (u64) = ((high << 32) | low); \ + } while (0) +# endif +#else +# if RT_MSC_PREREQ(RT_MSC_VER_VS2005) +# pragma intrinsic(__rdtsc) +# define STAM_GET_TS(u64) \ + do { (u64) = __rdtsc(); } while (0) +# else +# define STAM_GET_TS(u64) \ + do { \ + uint64_t u64Tmp; \ + __asm { \ + __asm rdtsc \ + __asm mov dword ptr [u64Tmp], eax \ + __asm mov dword ptr [u64Tmp + 4], edx \ + } \ + (u64) = u64Tmp; \ + } while (0) +# endif +#endif + + +/** @def STAM_REL_STATS + * Code for inclusion only when VBOX_WITH_STATISTICS is defined. + * @param code A code block enclosed in {}. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_STATS(code) do code while(0) +#else +# define STAM_REL_STATS(code) do {} while(0) +#endif +/** @def STAM_STATS + * Code for inclusion only when VBOX_WITH_STATISTICS is defined. + * @param code A code block enclosed in {}. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_STATS(code) STAM_REL_STATS(code) +#else +# define STAM_STATS(code) do {} while(0) +#endif + + +/** + * Sample type. + */ +typedef enum STAMTYPE +{ + /** Invalid entry. */ + STAMTYPE_INVALID = 0, + /** Generic counter. */ + STAMTYPE_COUNTER, + /** Profiling of an function. */ + STAMTYPE_PROFILE, + /** Profiling of an operation. */ + STAMTYPE_PROFILE_ADV, + /** Ratio of A to B, uint32_t types. Not reset. */ + STAMTYPE_RATIO_U32, + /** Ratio of A to B, uint32_t types. Reset both to 0. */ + STAMTYPE_RATIO_U32_RESET, + /** Callback. */ + STAMTYPE_CALLBACK, + /** Generic unsigned 8-bit value. Not reset. */ + STAMTYPE_U8, + /** Generic unsigned 8-bit value. Reset to 0. */ + STAMTYPE_U8_RESET, + /** Generic hexadecimal unsigned 8-bit value. Not reset. */ + STAMTYPE_X8, + /** Generic hexadecimal unsigned 8-bit value. Reset to 0. */ + STAMTYPE_X8_RESET, + /** Generic unsigned 16-bit value. Not reset. */ + STAMTYPE_U16, + /** Generic unsigned 16-bit value. Reset to 0. */ + STAMTYPE_U16_RESET, + /** Generic hexadecimal unsigned 16-bit value. Not reset. */ + STAMTYPE_X16, + /** Generic hexadecimal unsigned 16-bit value. Reset to 0. */ + STAMTYPE_X16_RESET, + /** Generic unsigned 32-bit value. Not reset. */ + STAMTYPE_U32, + /** Generic unsigned 32-bit value. Reset to 0. */ + STAMTYPE_U32_RESET, + /** Generic hexadecimal unsigned 32-bit value. Not reset. */ + STAMTYPE_X32, + /** Generic hexadecimal unsigned 32-bit value. Reset to 0. */ + STAMTYPE_X32_RESET, + /** Generic unsigned 64-bit value. Not reset. */ + STAMTYPE_U64, + /** Generic unsigned 64-bit value. Reset to 0. */ + STAMTYPE_U64_RESET, + /** Generic hexadecimal unsigned 64-bit value. Not reset. */ + STAMTYPE_X64, + /** Generic hexadecimal unsigned 64-bit value. Reset to 0. */ + STAMTYPE_X64_RESET, + /** Generic boolean value. Not reset. */ + STAMTYPE_BOOL, + /** Generic boolean value. Reset to false. */ + STAMTYPE_BOOL_RESET, + /** The end (exclusive). */ + STAMTYPE_END +} STAMTYPE; + +/** + * Sample visibility type. + */ +typedef enum STAMVISIBILITY +{ + /** Invalid entry. */ + STAMVISIBILITY_INVALID = 0, + /** Always visible. */ + STAMVISIBILITY_ALWAYS, + /** Only visible when used (/hit). */ + STAMVISIBILITY_USED, + /** Not visible in the GUI. */ + STAMVISIBILITY_NOT_GUI, + /** The end (exclusive). */ + STAMVISIBILITY_END +} STAMVISIBILITY; + +/** + * Sample unit. + */ +typedef enum STAMUNIT +{ + /** Invalid entry .*/ + STAMUNIT_INVALID = 0, + /** No unit. */ + STAMUNIT_NONE, + /** Number of calls. */ + STAMUNIT_CALLS, + /** Count of whatever. */ + STAMUNIT_COUNT, + /** Count of bytes. */ + STAMUNIT_BYTES, + /** Count of bytes per call. */ + STAMUNIT_BYTES_PER_CALL, + /** Count of bytes. */ + STAMUNIT_PAGES, + /** Error count. */ + STAMUNIT_ERRORS, + /** Number of occurences. */ + STAMUNIT_OCCURENCES, + /** Ticks. */ + STAMUNIT_TICKS, + /** Ticks per call. */ + STAMUNIT_TICKS_PER_CALL, + /** Ticks per occurence. */ + STAMUNIT_TICKS_PER_OCCURENCE, + /** Ratio of good vs. bad. */ + STAMUNIT_GOOD_BAD, + /** Megabytes. */ + STAMUNIT_MEGABYTES, + /** Kilobytes. */ + STAMUNIT_KILOBYTES, + /** Nano seconds. */ + STAMUNIT_NS, + /** Nanoseconds per call. */ + STAMUNIT_NS_PER_CALL, + /** Nanoseconds per call. */ + STAMUNIT_NS_PER_OCCURENCE, + /** Percentage. */ + STAMUNIT_PCT, + /** Hertz. */ + STAMUNIT_HZ, + /** The end (exclusive). */ + STAMUNIT_END +} STAMUNIT; + +/** @name STAM_REFRESH_GRP_XXX - STAM refresh groups + * @{ */ +#define STAM_REFRESH_GRP_NONE UINT8_MAX +#define STAM_REFRESH_GRP_GVMM 0 +#define STAM_REFRESH_GRP_GMM 1 +#define STAM_REFRESH_GRP_NEM 2 +/** @} */ + + +/** @def STAM_REL_U8_INC + * Increments a uint8_t sample by one. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U8_INC(pCounter) \ + do { ++*(pCounter); } while (0) +#else +# define STAM_REL_U8_INC(pCounter) do { } while (0) +#endif +/** @def STAM_U8_INC + * Increments a uint8_t sample by one. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U8_INC(pCounter) STAM_REL_U8_INC(pCounter) +#else +# define STAM_U8_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U8_DEC + * Decrements a uint8_t sample by one. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U8_DEC(pCounter) \ + do { --*(pCounter); } while (0) +#else +# define STAM_REL_U8_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_U8_DEC + * Decrements a uint8_t sample by one. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U8_DEC(pCounter) STAM_REL_U8_DEC(pCounter) +#else +# define STAM_U8_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U8_ADD + * Increments a uint8_t sample by a value. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + * @param Addend The value to add. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U8_ADD(pCounter, Addend) \ + do { *(pCounter) += (Addend); } while (0) +#else +# define STAM_REL_U8_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_U8_ADD + * Increments a uint8_t sample by a value. + * + * @param pCounter Pointer to the uint8_t variable to operate on. + * @param Addend The value to add. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U8_ADD(pCounter, Addend) STAM_REL_U8_ADD(pCounter, Addend +#else +# define STAM_U8_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** @def STAM_REL_U16_INC + * Increments a uint16_t sample by one. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U16_INC(pCounter) \ + do { ++*(pCounter); } while (0) +#else +# define STAM_REL_U16_INC(pCounter) do { } while (0) +#endif +/** @def STAM_U16_INC + * Increments a uint16_t sample by one. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U16_INC(pCounter) STAM_REL_U16_INC(pCounter) +#else +# define STAM_U16_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U16_DEC + * Decrements a uint16_t sample by one. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U16_DEC(pCounter) \ + do { --*(pCounter); } while (0) +#else +# define STAM_REL_U16_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_U16_DEC + * Decrements a uint16_t sample by one. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U16_DEC(pCounter) STAM_REL_U16_DEC(pCounter) +#else +# define STAM_U16_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U16_ADD + * Increments a uint16_t sample by a value. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + * @param Addend The value to add. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U16_ADD(pCounter, Addend) \ + do { *(pCounter) += (Addend); } while (0) +#else +# define STAM_REL_U16_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_U16_ADD + * Increments a uint16_t sample by a value. + * + * @param pCounter Pointer to the uint16_t variable to operate on. + * @param Addend The value to add. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U16_ADD(pCounter, Addend) STAM_REL_U16_ADD(pCounter, Addend) +#else +# define STAM_U16_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** @def STAM_REL_U32_INC + * Increments a uint32_t sample by one. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U32_INC(pCounter) \ + do { ++*(pCounter); } while (0) +#else +# define STAM_REL_U32_INC(pCounter) do { } while (0) +#endif +/** @def STAM_U32_INC + * Increments a uint32_t sample by one. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U32_INC(pCounter) STAM_REL_U32_INC(pCounter) +#else +# define STAM_U32_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U32_DEC + * Decrements a uint32_t sample by one. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U32_DEC(pCounter) \ + do { --*(pCounter); } while (0) +#else +# define STAM_REL_U32_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_U32_DEC + * Decrements a uint32_t sample by one. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U32_DEC(pCounter) STAM_REL_U32_DEC(pCounter) +#else +# define STAM_U32_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U32_ADD + * Increments a uint32_t sample by value. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + * @param Addend The value to add. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U32_ADD(pCounter, Addend) \ + do { *(pCounter) += (Addend); } while (0) +#else +# define STAM_REL_U32_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_U32_ADD + * Increments a uint32_t sample by value. + * + * @param pCounter Pointer to the uint32_t variable to operate on. + * @param Addend The value to add. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U32_ADD(pCounter, Addend) STAM_REL_U32_ADD(pCounter, Addend) +#else +# define STAM_U32_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** @def STAM_REL_U64_INC + * Increments a uint64_t sample by one. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U64_INC(pCounter) \ + do { ++*(pCounter); } while (0) +#else +# define STAM_REL_U64_INC(pCounter) do { } while (0) +#endif +/** @def STAM_U64_INC + * Increments a uint64_t sample by one. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U64_INC(pCounter) STAM_REL_U64_INC(pCounter) +#else +# define STAM_U64_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U64_DEC + * Decrements a uint64_t sample by one. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U64_DEC(pCounter) \ + do { --*(pCounter); } while (0) +#else +# define STAM_REL_U64_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_U64_DEC + * Decrements a uint64_t sample by one. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U64_DEC(pCounter) STAM_REL_U64_DEC(pCounter) +#else +# define STAM_U64_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_U64_ADD + * Increments a uint64_t sample by a value. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + * @param Addend The value to add. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_U64_ADD(pCounter, Addend) \ + do { *(pCounter) += (Addend); } while (0) +#else +# define STAM_REL_U64_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_U64_ADD + * Increments a uint64_t sample by a value. + * + * @param pCounter Pointer to the uint64_t variable to operate on. + * @param Addend The value to add. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_U64_ADD(pCounter, Addend) STAM_REL_U64_ADD(pCounter, Addend) +#else +# define STAM_U64_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** + * Counter sample - STAMTYPE_COUNTER. + */ +typedef struct STAMCOUNTER +{ + /** The current count. */ + volatile uint64_t c; +} STAMCOUNTER; +/** Pointer to a counter. */ +typedef STAMCOUNTER *PSTAMCOUNTER; +/** Pointer to a const counter. */ +typedef const STAMCOUNTER *PCSTAMCOUNTER; + + +/** @def STAM_REL_COUNTER_INC + * Increments a counter sample by one. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_COUNTER_INC(pCounter) \ + do { (pCounter)->c++; } while (0) +#else +# define STAM_REL_COUNTER_INC(pCounter) do { } while (0) +#endif +/** @def STAM_COUNTER_INC + * Increments a counter sample by one. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_COUNTER_INC(pCounter) STAM_REL_COUNTER_INC(pCounter) +#else +# define STAM_COUNTER_INC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_COUNTER_DEC + * Decrements a counter sample by one. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_COUNTER_DEC(pCounter) \ + do { (pCounter)->c--; } while (0) +#else +# define STAM_REL_COUNTER_DEC(pCounter) do { } while (0) +#endif +/** @def STAM_COUNTER_DEC + * Decrements a counter sample by one. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_COUNTER_DEC(pCounter) STAM_REL_COUNTER_DEC(pCounter) +#else +# define STAM_COUNTER_DEC(pCounter) do { } while (0) +#endif + + +/** @def STAM_REL_COUNTER_ADD + * Increments a counter sample by a value. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + * @param Addend The value to add to the counter. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_COUNTER_ADD(pCounter, Addend) \ + do { (pCounter)->c += (Addend); } while (0) +#else +# define STAM_REL_COUNTER_ADD(pCounter, Addend) do { } while (0) +#endif +/** @def STAM_COUNTER_ADD + * Increments a counter sample by a value. + * + * @param pCounter Pointer to the STAMCOUNTER structure to operate on. + * @param Addend The value to add to the counter. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_COUNTER_ADD(pCounter, Addend) STAM_REL_COUNTER_ADD(pCounter, Addend) +#else +# define STAM_COUNTER_ADD(pCounter, Addend) do { } while (0) +#endif + + +/** @def STAM_REL_COUNTER_RESET + * Resets the statistics sample. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_COUNTER_RESET(pCounter) do { (pCounter)->c = 0; } while (0) +#else +# define STAM_REL_COUNTER_RESET(pCounter) do { } while (0) +#endif +/** @def STAM_COUNTER_RESET + * Resets the statistics sample. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_COUNTER_RESET(pCounter) STAM_REL_COUNTER_RESET(pCounter) +#else +# define STAM_COUNTER_RESET(pCounter) do { } while (0) +#endif + + + +/** + * Profiling sample - STAMTYPE_PROFILE. + */ +typedef struct STAMPROFILE +{ + /** Number of periods. */ + volatile uint64_t cPeriods; + /** Total count of ticks. */ + volatile uint64_t cTicks; + /** Maximum tick count during a sampling. */ + volatile uint64_t cTicksMax; + /** Minimum tick count during a sampling. */ + volatile uint64_t cTicksMin; +} STAMPROFILE; +/** Pointer to a profile sample. */ +typedef STAMPROFILE *PSTAMPROFILE; +/** Pointer to a const profile sample. */ +typedef const STAMPROFILE *PCSTAMPROFILE; + + +/** @def STAM_REL_PROFILE_ADD_PERIOD + * Adds a period. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param cTicksInPeriod The number of tick (or whatever) of the preiod + * being added. This is only referenced once. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) \ + do { \ + uint64_t const StamPrefix_cTicks = (cTicksInPeriod); \ + (pProfile)->cTicks += StamPrefix_cTicks; \ + (pProfile)->cPeriods++; \ + if ((pProfile)->cTicksMax < StamPrefix_cTicks) \ + (pProfile)->cTicksMax = StamPrefix_cTicks; \ + if ((pProfile)->cTicksMin > StamPrefix_cTicks) \ + (pProfile)->cTicksMin = StamPrefix_cTicks; \ + } while (0) +#else +# define STAM_REL_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) do { } while (0) +#endif +/** @def STAM_PROFILE_ADD_PERIOD + * Adds a period. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param cTicksInPeriod The number of tick (or whatever) of the preiod + * being added. This is only referenced once. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) STAM_REL_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) +#else +# define STAM_PROFILE_ADD_PERIOD(pProfile, cTicksInPeriod) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_START + * Samples the start time of a profiling period. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + * + * @remarks Declears a stack variable that will be used by related macros. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_START(pProfile, Prefix) \ + uint64_t Prefix##_tsStart; \ + STAM_GET_TS(Prefix##_tsStart) +#else +# define STAM_REL_PROFILE_START(pProfile, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_START + * Samples the start time of a profiling period. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + * + * @remarks Declears a stack variable that will be used by related macros. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_START(pProfile, Prefix) STAM_REL_PROFILE_START(pProfile, Prefix) +#else +# define STAM_PROFILE_START(pProfile, Prefix) do { } while (0) +#endif + +/** @def STAM_REL_PROFILE_STOP + * Samples the stop time of a profiling period and updates the sample. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_STOP(pProfile, Prefix) \ + do { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + Prefix##_cTicks -= Prefix##_tsStart; \ + (pProfile)->cTicks += Prefix##_cTicks; \ + (pProfile)->cPeriods++; \ + if ((pProfile)->cTicksMax < Prefix##_cTicks) \ + (pProfile)->cTicksMax = Prefix##_cTicks; \ + if ((pProfile)->cTicksMin > Prefix##_cTicks) \ + (pProfile)->cTicksMin = Prefix##_cTicks; \ + } while (0) +#else +# define STAM_REL_PROFILE_STOP(pProfile, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_STOP + * Samples the stop time of a profiling period and updates the sample. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_STOP(pProfile, Prefix) STAM_REL_PROFILE_STOP(pProfile, Prefix) +#else +# define STAM_PROFILE_STOP(pProfile, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_STOP_EX + * Samples the stop time of a profiling period and updates both the sample + * and an attribution sample. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param pProfile2 Pointer to the STAMPROFILE structure which this + * interval should be attributed to as well. This may be NULL. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) \ + do { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + Prefix##_cTicks -= Prefix##_tsStart; \ + (pProfile)->cTicks += Prefix##_cTicks; \ + (pProfile)->cPeriods++; \ + if ((pProfile)->cTicksMax < Prefix##_cTicks) \ + (pProfile)->cTicksMax = Prefix##_cTicks; \ + if ((pProfile)->cTicksMin > Prefix##_cTicks) \ + (pProfile)->cTicksMin = Prefix##_cTicks; \ + \ + if ((pProfile2)) \ + { \ + (pProfile2)->cTicks += Prefix##_cTicks; \ + (pProfile2)->cPeriods++; \ + if ((pProfile2)->cTicksMax < Prefix##_cTicks) \ + (pProfile2)->cTicksMax = Prefix##_cTicks; \ + if ((pProfile2)->cTicksMin > Prefix##_cTicks) \ + (pProfile2)->cTicksMin = Prefix##_cTicks; \ + } \ + } while (0) +#else +# define STAM_REL_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_STOP_EX + * Samples the stop time of a profiling period and updates both the sample + * and an attribution sample. + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param pProfile2 Pointer to the STAMPROFILE structure which this + * interval should be attributed to as well. This may be NULL. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) STAM_REL_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) +#else +# define STAM_PROFILE_STOP_EX(pProfile, pProfile2, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_STOP_START + * Stops one profile counter (if running) and starts another one. + * + * @param pProfile1 Pointer to the STAMPROFILE structure to stop. + * @param pProfile2 Pointer to the STAMPROFILE structure to start. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \ + do { \ + uint64_t Prefix##_tsStop; \ + STAM_GET_TS(Prefix##_tsStop); \ + STAM_REL_PROFILE_ADD_PERIOD(pProfile1, Prefix##_tsStop - Prefix##_tsStart); \ + Prefix##_tsStart = Prefix##_tsStop; \ + } while (0) +#else +# define STAM_REL_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \ + do { } while (0) +#endif +/** @def STAM_PROFILE_STOP_START + * Samples the stop time of a profiling period (if running) and updates the + * sample. + * + * @param pProfile1 Pointer to the STAMPROFILE structure to stop. + * @param pProfile2 Pointer to the STAMPROFILE structure to start. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \ + STAM_REL_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) +#else +# define STAM_PROFILE_STOP_START(pProfile1, pProfile2, Prefix) \ + do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_START_NS + * Samples the start time of a profiling period, using RTTimeNanoTS(). + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + * + * @remarks Declears a stack variable that will be used by related macros. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_START_NS(pProfile, Prefix) \ + uint64_t const Prefix##_tsStart = RTTimeNanoTS() +#else +# define STAM_REL_PROFILE_START_NS(pProfile, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_START_NS + * Samples the start time of a profiling period, using RTTimeNanoTS(). + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + * + * @remarks Declears a stack variable that will be used by related macros. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_START_NS(pProfile, Prefix) STAM_REL_PROFILE_START_NS(pProfile, Prefix) +#else +# define STAM_PROFILE_START_NS(pProfile, Prefix) do { } while (0) +#endif + +/** @def STAM_REL_PROFILE_STOP_NS + * Samples the stop time of a profiling period and updates the sample, using + * RTTimeNanoTS(). + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_STOP_NS(pProfile, Prefix) \ + STAM_REL_PROFILE_ADD_PERIOD(pProfile, RTTimeNanoTS() - Prefix##_tsStart) +#else +# define STAM_REL_PROFILE_STOP_NS(pProfile, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_STOP_NS + * Samples the stop time of a profiling period and updates the sample, using + * RTTimeNanoTS(). + * + * @param pProfile Pointer to the STAMPROFILE structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_STOP_NS(pProfile, Prefix) STAM_REL_PROFILE_STOP_NS(pProfile, Prefix) +#else +# define STAM_PROFILE_STOP_NS(pProfile, Prefix) do { } while (0) +#endif + + +/** + * Advanced profiling sample - STAMTYPE_PROFILE_ADV. + * + * Identical to a STAMPROFILE sample, but the start timestamp + * is stored after the STAMPROFILE structure so the sampling + * can start and stop in different functions. + */ +typedef struct STAMPROFILEADV +{ + /** The STAMPROFILE core. */ + STAMPROFILE Core; + /** The start timestamp. */ + volatile uint64_t tsStart; +} STAMPROFILEADV; +/** Pointer to a advanced profile sample. */ +typedef STAMPROFILEADV *PSTAMPROFILEADV; +/** Pointer to a const advanced profile sample. */ +typedef const STAMPROFILEADV *PCSTAMPROFILEADV; + + +/** @def STAM_REL_PROFILE_ADV_START + * Samples the start time of a profiling period. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_START(pProfileAdv, Prefix) \ + STAM_GET_TS((pProfileAdv)->tsStart) +#else +# define STAM_REL_PROFILE_ADV_START(pProfileAdv, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_START + * Samples the start time of a profiling period. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_START(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_START(pProfileAdv, Prefix) +#else +# define STAM_PROFILE_ADV_START(pProfileAdv, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_STOP + * Samples the stop time of a profiling period (if running) and updates the + * sample. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_STOP(pProfileAdv, Prefix) \ + do { \ + if ((pProfileAdv)->tsStart) \ + { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + Prefix##_cTicks -= (pProfileAdv)->tsStart; \ + (pProfileAdv)->tsStart = 0; \ + (pProfileAdv)->Core.cTicks += Prefix##_cTicks; \ + (pProfileAdv)->Core.cPeriods++; \ + if ((pProfileAdv)->Core.cTicksMax < Prefix##_cTicks) \ + (pProfileAdv)->Core.cTicksMax = Prefix##_cTicks; \ + if ((pProfileAdv)->Core.cTicksMin > Prefix##_cTicks) \ + (pProfileAdv)->Core.cTicksMin = Prefix##_cTicks; \ + } \ + } while (0) +#else +# define STAM_REL_PROFILE_ADV_STOP(pProfileAdv, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_STOP + * Samples the stop time of a profiling period (if running) and updates the + * sample. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_STOP(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_STOP(pProfileAdv, Prefix) +#else +# define STAM_PROFILE_ADV_STOP(pProfileAdv, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_STOP_START + * Stops one profile counter (if running) and starts another one. + * + * @param pProfileAdv1 Pointer to the STAMPROFILEADV structure to stop. + * @param pProfileAdv2 Pointer to the STAMPROFILEADV structure to start. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \ + do { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + (pProfileAdv2)->tsStart = Prefix##_cTicks; \ + if ((pProfileAdv1)->tsStart) \ + { \ + Prefix##_cTicks -= (pProfileAdv1)->tsStart; \ + (pProfileAdv1)->tsStart = 0; \ + (pProfileAdv1)->Core.cTicks += Prefix##_cTicks; \ + (pProfileAdv1)->Core.cPeriods++; \ + if ((pProfileAdv1)->Core.cTicksMax < Prefix##_cTicks) \ + (pProfileAdv1)->Core.cTicksMax = Prefix##_cTicks; \ + if ((pProfileAdv1)->Core.cTicksMin > Prefix##_cTicks) \ + (pProfileAdv1)->Core.cTicksMin = Prefix##_cTicks; \ + } \ + } while (0) +#else +# define STAM_REL_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \ + do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_STOP_START + * Samples the stop time of a profiling period (if running) and updates the + * sample. + * + * @param pProfileAdv1 Pointer to the STAMPROFILEADV structure to stop. + * @param pProfileAdv2 Pointer to the STAMPROFILEADV structure to start. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \ + STAM_REL_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) +#else +# define STAM_PROFILE_ADV_STOP_START(pProfileAdv1, pProfileAdv2, Prefix) \ + do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_SUSPEND + * Suspends the sampling for a while. This can be useful to exclude parts + * covered by other samples without screwing up the count, and average+min times. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. The prefix + * must match that of the resume one since it stores the + * suspend time in a stack variable. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) \ + uint64_t Prefix##_tsSuspend; \ + STAM_GET_TS(Prefix##_tsSuspend) +#else +# define STAM_REL_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_SUSPEND + * Suspends the sampling for a while. This can be useful to exclude parts + * covered by other samples without screwing up the count, and average+min times. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. The prefix + * must match that of the resume one since it stores the + * suspend time in a stack variable. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) +#else +# define STAM_PROFILE_ADV_SUSPEND(pProfileAdv, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_RESUME + * Counter to STAM_REL_PROFILE_ADV_SUSPEND. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. This must + * match the one used with the SUSPEND! + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_RESUME(pProfileAdv, Prefix) \ + do { \ + uint64_t Prefix##_tsNow; \ + STAM_GET_TS(Prefix##_tsNow); \ + (pProfileAdv)->tsStart += Prefix##_tsNow - Prefix##_tsSuspend; \ + } while (0) +#else +# define STAM_REL_PROFILE_ADV_RESUME(pProfileAdv, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_RESUME + * Counter to STAM_PROFILE_ADV_SUSPEND. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param Prefix Identifier prefix used to internal variables. This must + * match the one used with the SUSPEND! + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_RESUME(pProfileAdv, Prefix) STAM_REL_PROFILE_ADV_RESUME(pProfileAdv, Prefix) +#else +# define STAM_PROFILE_ADV_RESUME(pProfileAdv, Prefix) do { } while (0) +#endif + + +/** @def STAM_REL_PROFILE_ADV_STOP_EX + * Samples the stop time of a profiling period (if running) and updates both + * the sample and an attribution sample. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param pProfile2 Pointer to the STAMPROFILE structure which this + * interval should be attributed to as well. This may be NULL. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) \ + do { \ + if ((pProfileAdv)->tsStart) \ + { \ + uint64_t Prefix##_cTicks; \ + STAM_GET_TS(Prefix##_cTicks); \ + Prefix##_cTicks -= (pProfileAdv)->tsStart; \ + (pProfileAdv)->tsStart = 0; \ + (pProfileAdv)->Core.cTicks += Prefix##_cTicks; \ + (pProfileAdv)->Core.cPeriods++; \ + if ((pProfileAdv)->Core.cTicksMax < Prefix##_cTicks) \ + (pProfileAdv)->Core.cTicksMax = Prefix##_cTicks; \ + if ((pProfileAdv)->Core.cTicksMin > Prefix##_cTicks) \ + (pProfileAdv)->Core.cTicksMin = Prefix##_cTicks; \ + if ((pProfile2)) \ + { \ + (pProfile2)->cTicks += Prefix##_cTicks; \ + (pProfile2)->cPeriods++; \ + if ((pProfile2)->cTicksMax < Prefix##_cTicks) \ + (pProfile2)->cTicksMax = Prefix##_cTicks; \ + if ((pProfile2)->cTicksMin > Prefix##_cTicks) \ + (pProfile2)->cTicksMin = Prefix##_cTicks; \ + } \ + } \ + } while (0) +#else +# define STAM_REL_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_STOP_EX + * Samples the stop time of a profiling period (if running) and updates both + * the sample and an attribution sample. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + * @param pProfile2 Pointer to the STAMPROFILE structure which this + * interval should be attributed to as well. This may be NULL. + * @param Prefix Identifier prefix used to internal variables. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) STAM_REL_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) +#else +# define STAM_PROFILE_ADV_STOP_EX(pProfileAdv, pProfile2, Prefix) do { } while (0) +#endif + +/** @def STAM_REL_PROFILE_ADV_IS_RUNNING + * Checks if it is running. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_IS_RUNNING(pProfileAdv) (pProfileAdv)->tsStart +#else +# define STAM_REL_PROFILE_ADV_IS_RUNNING(pProfileAdv) (false) +#endif +/** @def STAM_PROFILE_ADV_IS_RUNNING + * Checks if it is running. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_IS_RUNNING(pProfileAdv) STAM_REL_PROFILE_ADV_IS_RUNNING(pProfileAdv) +#else +# define STAM_PROFILE_ADV_IS_RUNNING(pProfileAdv) (false) +#endif + +/** @def STAM_REL_PROFILE_ADV_SET_STOPPED + * Marks the profile counter as stopped. + * + * This is for avoiding screwups in twisty code. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + */ +#ifndef VBOX_WITHOUT_RELEASE_STATISTICS +# define STAM_REL_PROFILE_ADV_SET_STOPPED(pProfileAdv) do { (pProfileAdv)->tsStart = 0; } while (0) +#else +# define STAM_REL_PROFILE_ADV_SET_STOPPED(pProfileAdv) do { } while (0) +#endif +/** @def STAM_PROFILE_ADV_SET_STOPPED + * Marks the profile counter as stopped. + * + * This is for avoiding screwups in twisty code. + * + * @param pProfileAdv Pointer to the STAMPROFILEADV structure to operate on. + */ +#ifdef VBOX_WITH_STATISTICS +# define STAM_PROFILE_ADV_SET_STOPPED(pProfileAdv) STAM_REL_PROFILE_ADV_SET_STOPPED(pProfileAdv) +#else +# define STAM_PROFILE_ADV_SET_STOPPED(pProfileAdv) do { } while (0) +#endif + + +/** + * Ratio of A to B, uint32_t types. + * @remark Use STAM_STATS or STAM_REL_STATS for modifying A & B values. + */ +typedef struct STAMRATIOU32 +{ + /** Sample A. */ + uint32_t volatile u32A; + /** Sample B. */ + uint32_t volatile u32B; +} STAMRATIOU32; +/** Pointer to a uint32_t ratio. */ +typedef STAMRATIOU32 *PSTAMRATIOU32; +/** Pointer to const a uint32_t ratio. */ +typedef const STAMRATIOU32 *PCSTAMRATIOU32; + + + + +/** @defgroup grp_stam_r3 The STAM Host Context Ring 3 API + * @{ + */ + +VMMR3DECL(int) STAMR3InitUVM(PUVM pUVM); +VMMR3DECL(void) STAMR3TermUVM(PUVM pUVM); +VMMR3DECL(int) STAMR3RegisterU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + const char *pszName, STAMUNIT enmUnit, const char *pszDesc); +VMMR3DECL(int) STAMR3Register(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + const char *pszName, STAMUNIT enmUnit, const char *pszDesc); + +/** @def STAM_REL_REG + * Registers a statistics sample. + * + * @param pVM The cross context VM structure. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "//". + * Further nesting is possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ +#define STAM_REL_REG(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \ + STAM_REL_STATS({ int rcStam = STAMR3Register(pVM, pvSample, enmType, STAMVISIBILITY_ALWAYS, pszName, enmUnit, pszDesc); \ + AssertRC(rcStam); }) +/** @def STAM_REG + * Registers a statistics sample if statistics are enabled. + * + * @param pVM The cross context VM structure. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "//". + * Further nesting is possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ +#define STAM_REG(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \ + STAM_STATS({STAM_REL_REG(pVM, pvSample, enmType, pszName, enmUnit, pszDesc);}) + +/** @def STAM_REL_REG_USED + * Registers a statistics sample which only shows when used. + * + * @param pVM The cross context VM structure. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "//". + * Further nesting is possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ +#define STAM_REL_REG_USED(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \ + STAM_REL_STATS({ int rcStam = STAMR3Register(pVM, pvSample, enmType, STAMVISIBILITY_USED, pszName, enmUnit, pszDesc); \ + AssertRC(rcStam);}) +/** @def STAM_REG_USED + * Registers a statistics sample which only shows when used, if statistics are enabled. + * + * @param pVM The cross context VM structure. + * @param pvSample Pointer to the sample. + * @param enmType Sample type. This indicates what pvSample is pointing at. + * @param pszName Sample name. The name is on this form "//". + * Further nesting is possible. + * @param enmUnit Sample unit. + * @param pszDesc Sample description. + */ +#define STAM_REG_USED(pVM, pvSample, enmType, pszName, enmUnit, pszDesc) \ + STAM_STATS({ STAM_REL_REG_USED(pVM, pvSample, enmType, pszName, enmUnit, pszDesc); }) + +VMMR3DECL(int) STAMR3RegisterFU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, ...) RT_IPRT_FORMAT_ATTR(7, 8); +VMMR3DECL(int) STAMR3RegisterF(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, ...) RT_IPRT_FORMAT_ATTR(7, 8); +VMMR3DECL(int) STAMR3RegisterVU(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(7, 0); +VMMR3DECL(int) STAMR3RegisterV(PVM pVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + const char *pszDesc, const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(7, 0); + +/** + * Resets the sample. + * @param pVM The cross context VM structure. + * @param pvSample The sample registered using STAMR3RegisterCallback. + */ +typedef DECLCALLBACKTYPE(void, FNSTAMR3CALLBACKRESET,(PVM pVM, void *pvSample)); +/** Pointer to a STAM sample reset callback. */ +typedef FNSTAMR3CALLBACKRESET *PFNSTAMR3CALLBACKRESET; + +/** + * Prints the sample into the buffer. + * + * @param pVM The cross context VM structure. + * @param pvSample The sample registered using STAMR3RegisterCallback. + * @param pszBuf The buffer to print into. + * @param cchBuf The size of the buffer. + */ +typedef DECLCALLBACKTYPE(void, FNSTAMR3CALLBACKPRINT,(PVM pVM, void *pvSample, char *pszBuf, size_t cchBuf)); +/** Pointer to a STAM sample print callback. */ +typedef FNSTAMR3CALLBACKPRINT *PFNSTAMR3CALLBACKPRINT; + +VMMR3DECL(int) STAMR3RegisterCallback(PVM pVM, void *pvSample, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint, + const char *pszDesc, const char *pszName, ...) RT_IPRT_FORMAT_ATTR(8, 9); +VMMR3DECL(int) STAMR3RegisterCallbackV(PVM pVM, void *pvSample, STAMVISIBILITY enmVisibility, STAMUNIT enmUnit, + PFNSTAMR3CALLBACKRESET pfnReset, PFNSTAMR3CALLBACKPRINT pfnPrint, + const char *pszDesc, const char *pszName, va_list args) RT_IPRT_FORMAT_ATTR(8, 0); + +VMMR3DECL(int) STAMR3RegisterRefresh(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, uint8_t iRefreshGrp, const char *pszDesc, + const char *pszName, ...) RT_IPRT_FORMAT_ATTR(8, 9); +VMMR3DECL(int) STAMR3RegisterRefreshV(PUVM pUVM, void *pvSample, STAMTYPE enmType, STAMVISIBILITY enmVisibility, + STAMUNIT enmUnit, uint8_t iRefreshGrp, const char *pszDesc, + const char *pszName, va_list va) RT_IPRT_FORMAT_ATTR(8, 0); + +VMMR3DECL(int) STAMR3Deregister(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3DeregisterF(PUVM pUVM, const char *pszPatFmt, ...) RT_IPRT_FORMAT_ATTR(2, 3); +VMMR3DECL(int) STAMR3DeregisterV(PUVM pUVM, const char *pszPatFmt, va_list va) RT_IPRT_FORMAT_ATTR(2, 0); +VMMR3DECL(int) STAMR3DeregisterByPrefix(PUVM pUVM, const char *pszPrefix); +VMMR3DECL(int) STAMR3DeregisterByAddr(PUVM pUVM, void *pvSample); + +VMMR3DECL(int) STAMR3Reset(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3Snapshot(PUVM pUVM, const char *pszPat, char **ppszSnapshot, size_t *pcchSnapshot, bool fWithDesc); +VMMR3DECL(int) STAMR3SnapshotFree(PUVM pUVM, char *pszSnapshot); +VMMR3DECL(int) STAMR3Dump(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3DumpToReleaseLog(PUVM pUVM, const char *pszPat); +VMMR3DECL(int) STAMR3Print(PUVM pUVM, const char *pszPat); + +/** + * Callback function for STAMR3Enum(). + * + * @returns non-zero to halt the enumeration. + * + * @param pszName The name of the sample. + * @param enmType The type. + * @param pvSample Pointer to the data. enmType indicates the format of this data. + * @param enmUnit The unit. + * @param pszUnit The unit as string. This is a permanent string, + * same as returned by STAMR3GetUnit(). + * @param enmVisibility The visibility. + * @param pszDesc The description. + * @param pvUser The pvUser argument given to STAMR3Enum(). + */ +typedef DECLCALLBACKTYPE(int, FNSTAMR3ENUM,(const char *pszName, STAMTYPE enmType, void *pvSample, STAMUNIT enmUnit, + const char *pszUnit, STAMVISIBILITY enmVisibility, const char *pszDesc, void *pvUser)); +/** Pointer to a FNSTAMR3ENUM(). */ +typedef FNSTAMR3ENUM *PFNSTAMR3ENUM; + +VMMR3DECL(int) STAMR3Enum(PUVM pUVM, const char *pszPat, PFNSTAMR3ENUM pfnEnum, void *pvUser); +VMMR3DECL(const char *) STAMR3GetUnit(STAMUNIT enmUnit); +VMMR3DECL(const char *) STAMR3GetUnit1(STAMUNIT enmUnit); +VMMR3DECL(const char *) STAMR3GetUnit2(STAMUNIT enmUnit); + +/** @} */ + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_stam_h */ + diff --git a/include/VBox/vmm/stam.mac b/include/VBox/vmm/stam.mac new file mode 100644 index 00000000..b70a881a --- /dev/null +++ b/include/VBox/vmm/stam.mac @@ -0,0 +1,392 @@ +;; @file +; STAM - Statistics Manager. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_vmm_stam_mac__ +%define ___VBox_vmm_stam_mac__ + + +%ifndef VBOX_WITH_STATISTICS + %ifdef DEBUG + %define VBOX_WITH_STATISTICS + %endif +%endif + + + +;; +; Counter sample - STAMTYPE_COUNTER. +struc STAMCOUNTER + .c resd 2 +endstruc + +;; +; Increments a counter sample by one. +; @param %1 Pointer to the STAMCOUNTER structure to operate on. +%macro STAM32_COUNTER_INC 1 +%ifdef VBOX_WITH_STATISTICS + push ebx + mov ebx, %1 + inc dword [ebx + STAMCOUNTER.c] + adc dword [ebx + STAMCOUNTER.c + 1], byte 0 + pop ebx +%endif +%endmacro + +%macro STAM64_COUNTER_INC 1 +%ifdef VBOX_WITH_STATISTICS + push rbx + mov rbx, %1 + inc qword [rbx + STAMCOUNTER.c] + pop rbx +%endif +%endmacro + +%macro STAM_COUNTER_INC 1 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_COUNTER_INC %1 + %else + STAM32_COUNTER_INC %1 + %endif +%endif +%endmacro + + +;; +; Increments a counter sample by a value. +; +; @param %1 Pointer to the STAMCOUNTER structure to operate on. +; @param %2 The value to add to the counter. +%macro STAM32_COUNTER_ADD 2 +%ifdef VBOX_WITH_STATISTICS + push ebx + mov ebx, %1 + push eax + mov eax, %2 + + add [ebx + STAMCOUNTER.c], eax + adc dword [ebx + STAMCOUNTER.c], byte 0 + + pop eax + pop ebx +%endif +%endmacro + +%macro STAM64_COUNTER_ADD 2 +%ifdef VBOX_WITH_STATISTICS + push rbx + mov rbx, %1 + push rax + mov rax, %2 + + add [rbx + STAMCOUNTER.c], rax + + pop rax + pop rbx +%endif +%endmacro + +%macro STAM_COUNTER_ADD 2 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_COUNTER_ADD %1, %2 + %else + STAM32_COUNTER_ADD %1, %2 + %endif +%endif +%endmacro + + +;; +; Profiling sample - STAMTYPE_PROFILE. +struc STAMPROFILE + .cPeriods resd 2 + .cTicks resd 2 + .cTicksMax resd 2 + .cTicksMin resd 2 +endstruc + + +;; +; Samples the start time of a profiling period. +; +; @param %1 Pointer to somewhere one can store a 64-bit timestamp until STAM_PROFILE_STOPP +%macro STAM32_PROFILE_START 1 +%ifdef VBOX_WITH_STATISTICS + push ebx + mov ebx, %1 + push eax + push edx + + rdtsc + mov [ebx], eax + mov [ebx + 4], edx + + pop edx + pop eax + pop ebx +%endif +%endmacro + +%macro STAM64_PROFILE_START 1 +%ifdef VBOX_WITH_STATISTICS + push rbx + mov rbx, %1 + push rax + push rdx + + rdtsc + mov [rbx], eax + mov [rbx + 4], edx + + pop rdx + pop rax + pop rbx +%endif +%endmacro + +%macro STAM_PROFILE_START 1 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_PROFILE_START %1 + %else + STAM32_PROFILE_START %1 + %endif +%endif +%endmacro + + +;; +; Samples the stop time of a profiling period and updates the sample. +; +; @param %1 Pointer to the STAMPROFILE structure to operate on. +; @param %2 Pointer to where the 64-bit timestamp from STAM_PROFILE_START was stored. +%macro STAM32_PROFILE_STOP 2 +%ifdef VBOX_WITH_STATISTICS + push ebx + mov ebx, %1 + push eax + push edx + + ; calc cTicks + push ecx + mov ecx, %2 + rdtsc + sub eax, [ecx] + sbb edx, [ecx + 4] + pop ecx + + ; update STAMPROFILE.cTicks + add [ebx + STAMPROFILE.cTicks], eax + adc [ebx + STAMPROFILE.cTicks + 4], edx + ; update STAMPROFILE.cPeriods + inc dword [ebx + STAMPROFILE.cPeriods] + adc dword [ebx + STAMPROFILE.cPeriods + 4], byte 0 + + ; update max? + cmp edx, [ebx + STAMPROFILE.cTicksMax + 4] + jb short %%not_update_max + ja short %%update_max + cmp eax, [ebx + STAMPROFILE.cTicksMax] + jbe short %%not_update_max +%%update_max: + mov [ebx + STAMPROFILE.cTicksMax], eax + mov [ebx + STAMPROFILE.cTicksMax + 4], edx +%%not_update_max: + + ; update min? + cmp edx, [ebx + STAMPROFILE.cTicksMin + 4] + ja short %%not_update_min + jb short %%update_min + cmp eax, [ebx + STAMPROFILE.cTicksMin] + jae short %%not_update_min +%%update_min: + mov [ebx + STAMPROFILE.cTicksMin], eax + mov [ebx + STAMPROFILE.cTicksMin + 4], edx +%%not_update_min: + + pop edx + pop eax + pop ebx +%endif +%endmacro + +%macro STAM64_PROFILE_STOP 2 +%ifdef VBOX_WITH_STATISTICS + push rbx + mov rbx, %1 + push rax + push rdx + + ; calc cTicks + push rcx + mov rcx, %2 + rdtsc + sub rax, [ecx] + sbb rdx, [ecx + 4] + pop rcx + + ; update STAMPROFILE.cTicks + shl rdx, 32 + or rdx, rax + add [rbx + STAMPROFILE.cTicks], rdx + ; update STAMPROFILE.cPeriods + inc qword [rbx + STAMPROFILE.cPeriods] + + ; update max? + cmp rdx, [rbx + STAMPROFILE.cTicksMax] + jbe short %%not_update_max + mov [rbx + STAMPROFILE.cTicksMax], rdx +%%not_update_max: + + ; update min? + cmp rdx, [rbx + STAMPROFILE.cTicksMin] + jae short %%not_update_min + mov [rbx + STAMPROFILE.cTicksMin], rax +%%not_update_min: + + pop rdx + pop rax + pop rbx +%endif +%endmacro + +%macro STAM_PROFILE_STOP 2 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_PROFILE_STOP %1, %2 + %else + STAM32_PROFILE_STOP %1, %2 + %endif +%endif +%endmacro + + + +struc STAMPROFILEADV + .cPeriods resd 2 + .cTicks resd 2 + .cTicksMax resd 2 + .cTicksMin resd 2 + .tsStart resd 2 +endstruc + + +;; +; Samples the start time of a profiling period. +; +; @param %1 Pointer to the STAMPROFILEADV structure to operate on. +%macro STAM32_PROFILE_ADV_START 1 +%ifdef VBOX_WITH_STATISTICS + push ecx + mov ecx, %1 + lea ecx, [ecx + STAMPROFILEADV.tsStart] + STAM32_PROFILE_START ecx + pop ecx +%endif +%endmacro + +%macro STAM64_PROFILE_ADV_START 1 +%ifdef VBOX_WITH_STATISTICS + push rcx + mov rcx, %1 + lea rcx, [rcx + STAMPROFILEADV.tsStart] + STAM64_PROFILE_START rcx + pop rcx +%endif +%endmacro + +%macro STAM_PROFILE_ADV_START 1 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_PROFILE_ADV_START %1 + %else + STAM32_PROFILE_ADV_START %1 + %endif +%endif +%endmacro + + +;; +; Samples the stop time of a profiling period and updates the sample. +; +; @param %1 Pointer to the STAMPROFILEADV structure to operate on. + +%macro STAM32_PROFILE_ADV_STOP 1 +%ifdef VBOX_WITH_STATISTICS + push ecx + mov ecx, %1 + lea ecx, [ecx + STAMPROFILEADV.tsStart] + cmp dword [ecx], byte 0 + jnz short %%doit + cmp dword [ecx + 4], byte 0 + jz short %%dont +%%doit: + STAM32_PROFILE_STOP %1, ecx +%%dont: + mov dword [ecx], 0 + mov dword [ecx + 4], 0 + pop ecx +%endif +%endmacro + +%macro STAM64_PROFILE_ADV_STOP 1 +%ifdef VBOX_WITH_STATISTICS + push rcx + mov rcx, %1 + lea rcx, [rcx + STAMPROFILEADV.tsStart] + cmp qword [rcx], byte 0 + jz short %%dont +%%doit: + STAM64_PROFILE_STOP %1, rcx +%%dont: + mov qword [rcx], 0 + pop rcx +%endif +%endmacro + +%macro STAM_PROFILE_ADV_STOP 1 +%ifdef VBOX_WITH_STATISTICS + %ifdef RT_ARCH_AMD64 + STAM64_PROFILE_ADV_STOP %1 + %else + STAM32_PROFILE_ADV_STOP %1 + %endif +%endif +%endmacro + + + +%endif diff --git a/include/VBox/vmm/tm.h b/include/VBox/vmm/tm.h new file mode 100644 index 00000000..2bd62d3a --- /dev/null +++ b/include/VBox/vmm/tm.h @@ -0,0 +1,322 @@ +/** @file + * TM - Time Manager. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_tm_h +#define VBOX_INCLUDED_vmm_tm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#ifdef IN_RING3 +# include +#endif + +RT_C_DECLS_BEGIN + +/** @defgroup grp_tm The Time Manager API + * @ingroup grp_vmm + * @{ + */ + +/** Enable a timer hack which improves the timer response/resolution a bit. */ +#define VBOX_HIGH_RES_TIMERS_HACK + + +/** + * Clock type. + */ +typedef enum TMCLOCK +{ + /** Real host time. + * This clock ticks all the time, so use with care. */ + TMCLOCK_REAL = 0, + /** Virtual guest time. + * This clock only ticks when the guest is running. It's implemented + * as an offset to monotonic real time (GIP). */ + TMCLOCK_VIRTUAL, + /** Virtual guest synchronized timer time. + * This is a special clock and timer queue for synchronizing virtual timers + * and virtual time sources. This clock is trying to keep up with + * TMCLOCK_VIRTUAL, but will wait for timers to be executed. If it lags + * too far behind TMCLOCK_VIRTUAL, it will try speed up to close the + * distance. + * @remarks Do not use this unless you really *must*. */ + TMCLOCK_VIRTUAL_SYNC, + /** Virtual CPU timestamp. + * By default this is a function of TMCLOCK_VIRTUAL_SYNC and the virtual + * CPU frequency. */ + TMCLOCK_TSC, + /** Number of clocks. */ + TMCLOCK_MAX +} TMCLOCK; + + +/** @defgroup grp_tm_timer_flags Timer flags. + * @{ */ +/** Use the default critical section for the class of timers. */ +#define TMTIMER_FLAGS_DEFAULT_CRIT_SECT 0 +/** No critical section needed or a custom one is set using + * TMR3TimerSetCritSect(). */ +#define TMTIMER_FLAGS_NO_CRIT_SECT RT_BIT_32(0) +/** Used in ring-0. Must set this or TMTIMER_FLAGS_NO_RING0. */ +#define TMTIMER_FLAGS_RING0 RT_BIT_32(1) +/** Not used in ring-0 (for refactoring and doc purposes). */ +#define TMTIMER_FLAGS_NO_RING0 RT_BIT_32(31) +/** @} */ + + +VMMDECL(void) TMNotifyStartOfExecution(PVMCC pVM, PVMCPUCC pVCpu); +VMMDECL(void) TMNotifyEndOfExecution(PVMCC pVM, PVMCPUCC pVCpu, uint64_t uTsc); +VMM_INT_DECL(void) TMNotifyStartOfHalt(PVMCPUCC pVCpu); +VMM_INT_DECL(void) TMNotifyEndOfHalt(PVMCPUCC pVCpu); +#ifdef IN_RING3 +VMMR3DECL(int) TMR3NotifySuspend(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) TMR3NotifyResume(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) TMR3SetWarpDrive(PUVM pUVM, uint32_t u32Percent); +VMMR3DECL(uint32_t) TMR3GetWarpDrive(PUVM pUVM); +#endif +VMM_INT_DECL(uint32_t) TMCalcHostTimerFrequency(PVMCC pVM, PVMCPUCC pVCpu); +#ifdef IN_RING3 +VMMR3DECL(int) TMR3GetCpuLoadTimes(PVM pVM, VMCPUID idCpu, uint64_t *pcNsTotal, uint64_t *pcNsExecuting, + uint64_t *pcNsHalted, uint64_t *pcNsOther); +VMMR3DECL(int) TMR3GetCpuLoadPercents(PUVM pVUM, VMCPUID idCpu, uint64_t *pcMsInterval, uint8_t *pcPctExecuting, + uint8_t *pcPctHalted, uint8_t *pcPctOther); +#endif + + +/** @name Real Clock Methods + * @{ + */ +VMM_INT_DECL(uint64_t) TMRealGet(PVM pVM); +VMM_INT_DECL(uint64_t) TMRealGetFreq(PVM pVM); +/** @} */ + + +/** @name Virtual Clock Methods + * @{ + */ +VMM_INT_DECL(uint64_t) TMVirtualGet(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualGetNoCheck(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetLag(PVMCC pVM); +VMM_INT_DECL(uint32_t) TMVirtualSyncGetCatchUpPct(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualGetFreq(PVM pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGet(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetNoCheck(PVMCC pVM); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetNoCheckWithTsc(PVMCC pVM, uint64_t *puTscNow); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetEx(PVMCC pVM, bool fCheckTimers); +VMM_INT_DECL(uint64_t) TMVirtualSyncGetWithDeadlineNoCheck(PVMCC pVM, uint64_t *pcNsToDeadline, + uint64_t *puDeadlineVersion, uint64_t *puTscNow); +VMMDECL(uint64_t) TMVirtualSyncGetNsToDeadline(PVMCC pVM, uint64_t *puDeadlineVersion, uint64_t *puTscNow); +VMM_INT_DECL(bool) TMVirtualSyncIsCurrentDeadlineVersion(PVMCC pVM, uint64_t uDeadlineVersion); +VMM_INT_DECL(uint64_t) TMVirtualToNano(PVM pVM, uint64_t u64VirtualTicks); +VMM_INT_DECL(uint64_t) TMVirtualToMicro(PVM pVM, uint64_t u64VirtualTicks); +VMM_INT_DECL(uint64_t) TMVirtualToMilli(PVM pVM, uint64_t u64VirtualTicks); +VMM_INT_DECL(uint64_t) TMVirtualFromNano(PVM pVM, uint64_t u64NanoTS); +VMM_INT_DECL(uint64_t) TMVirtualFromMicro(PVM pVM, uint64_t u64MicroTS); +VMM_INT_DECL(uint64_t) TMVirtualFromMilli(PVM pVM, uint64_t u64MilliTS); +VMM_INT_DECL(bool) TMVirtualIsTicking(PVM pVM); + +VMMR3DECL(uint64_t) TMR3TimeVirtGet(PUVM pUVM); +VMMR3DECL(uint64_t) TMR3TimeVirtGetMilli(PUVM pUVM); +VMMR3DECL(uint64_t) TMR3TimeVirtGetMicro(PUVM pUVM); +VMMR3DECL(uint64_t) TMR3TimeVirtGetNano(PUVM pUVM); +/** @} */ + + +/** @name CPU Clock Methods + * @{ + */ +VMMDECL(uint64_t) TMCpuTickGet(PVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) TMCpuTickGetNoCheck(PVMCPUCC pVCpu); +VMM_INT_DECL(bool) TMCpuTickCanUseRealTSC(PVMCC pVM, PVMCPUCC pVCpu, uint64_t *poffRealTSC, bool *pfParavirtTsc); +VMM_INT_DECL(uint64_t) TMCpuTickGetDeadlineAndTscOffset(PVMCC pVM, PVMCPUCC pVCpu, uint64_t *poffRealTsc, + bool *pfOffsettedTsc, bool *pfParavirtTsc, + uint64_t *puTscNow, uint64_t *puDeadlineVersion); +VMM_INT_DECL(int) TMCpuTickSet(PVMCC pVM, PVMCPUCC pVCpu, uint64_t u64Tick); +VMM_INT_DECL(int) TMCpuTickSetLastSeen(PVMCPUCC pVCpu, uint64_t u64LastSeenTick); +VMM_INT_DECL(uint64_t) TMCpuTickGetLastSeen(PVMCPUCC pVCpu); +VMMDECL(uint64_t) TMCpuTicksPerSecond(PVMCC pVM); +VMM_INT_DECL(bool) TMCpuTickIsTicking(PVMCPUCC pVCpu); +/** @} */ + + +/** @name Timer Methods + * @{ + */ +/** + * Device timer callback function. + * + * @param pDevIns Device instance of the device which registered the timer. + * @param hTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERDEV,(PPDMDEVINS pDevIns, TMTIMERHANDLE hTimer, void *pvUser)); +/** Pointer to a device timer callback function. */ +typedef FNTMTIMERDEV *PFNTMTIMERDEV; + +/** + * USB device timer callback function. + * + * @param pUsbIns The USB device instance the timer is associated + * with. + * @param hTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERUSB,(PPDMUSBINS pUsbIns, TMTIMERHANDLE hTimer, void *pvUser)); +/** Pointer to a timer callback for a USB device. */ +typedef FNTMTIMERUSB *PFNTMTIMERUSB; + +/** + * Driver timer callback function. + * + * @param pDrvIns Device instance of the device which registered the timer. + * @param hTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERDRV,(PPDMDRVINS pDrvIns, TMTIMERHANDLE hTimer, void *pvUser)); +/** Pointer to a driver timer callback function. */ +typedef FNTMTIMERDRV *PFNTMTIMERDRV; + +/** + * Service timer callback function. + * + * @param pSrvIns Service instance of the device which registered the timer. + * @param hTimer The timer handle. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERSRV,(PPDMSRVINS pSrvIns, TMTIMERHANDLE hTimer)); +/** Pointer to a service timer callback function. */ +typedef FNTMTIMERSRV *PFNTMTIMERSRV; + +/** + * Internal timer callback function. + * + * @param pVM The cross context VM structure. + * @param hTimer The timer handle. + * @param pvUser User argument specified upon timer creation. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMERINT,(PVM pVM, TMTIMERHANDLE hTimer, void *pvUser)); +/** Pointer to internal timer callback function. */ +typedef FNTMTIMERINT *PFNTMTIMERINT; + +/** + * External timer callback function. + * + * @param pvUser User argument as specified when the timer was created. + */ +typedef DECLCALLBACKTYPE(void, FNTMTIMEREXT,(void *pvUser)); +/** Pointer to an external timer callback function. */ +typedef FNTMTIMEREXT *PFNTMTIMEREXT; + +VMMDECL(int) TMTimerLock(PVMCC pVM, TMTIMERHANDLE hTimer, int rcBusy); +VMMDECL(void) TMTimerUnlock(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(bool) TMTimerIsLockOwner(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(int) TMTimerSet(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t u64Expire); +VMMDECL(int) TMTimerSetRelative(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cTicksToNext, uint64_t *pu64Now); +VMMDECL(int) TMTimerSetFrequencyHint(PVMCC pVM, TMTIMERHANDLE hTimer, uint32_t uHz); +VMMDECL(uint64_t) TMTimerGet(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(int) TMTimerStop(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(bool) TMTimerIsActive(PVMCC pVM, TMTIMERHANDLE hTimer); + +VMMDECL(int) TMTimerSetMillies(PVMCC pVM, TMTIMERHANDLE hTimer, uint32_t cMilliesToNext); +VMMDECL(int) TMTimerSetMicro(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cMicrosToNext); +VMMDECL(int) TMTimerSetNano(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cNanosToNext); +VMMDECL(uint64_t) TMTimerGetNano(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerGetMicro(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerGetMilli(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerGetFreq(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerGetExpire(PVMCC pVM, TMTIMERHANDLE hTimer); +VMMDECL(uint64_t) TMTimerToNano(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cTicks); +VMMDECL(uint64_t) TMTimerToMicro(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cTicks); +VMMDECL(uint64_t) TMTimerToMilli(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cTicks); +VMMDECL(uint64_t) TMTimerFromNano(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cNanoSecs); +VMMDECL(uint64_t) TMTimerFromMicro(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cMicroSecs); +VMMDECL(uint64_t) TMTimerFromMilli(PVMCC pVM, TMTIMERHANDLE hTimer, uint64_t cMilliSecs); + +VMMDECL(bool) TMTimerPollBool(PVMCC pVM, PVMCPUCC pVCpu); +VMM_INT_DECL(void) TMTimerPollVoid(PVMCC pVM, PVMCPUCC pVCpu); +VMM_INT_DECL(uint64_t) TMTimerPollGIP(PVMCC pVM, PVMCPUCC pVCpu, uint64_t *pu64Delta); +/** @} */ + + +/** @defgroup grp_tm_r3 The TM Host Context Ring-3 API + * @{ + */ +VMM_INT_DECL(int) TMR3Init(PVM pVM); +VMM_INT_DECL(int) TMR3InitFinalize(PVM pVM); +VMM_INT_DECL(void) TMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMM_INT_DECL(int) TMR3Term(PVM pVM); +VMM_INT_DECL(void) TMR3Reset(PVM pVM); +VMM_INT_DECL(int) TMR3TimerCreateDevice(PVM pVM, PPDMDEVINS pDevIns, TMCLOCK enmClock, PFNTMTIMERDEV pfnCallback, + void *pvUser, uint32_t fFlags, const char *pszName, PTMTIMERHANDLE phTimer); +VMM_INT_DECL(int) TMR3TimerCreateUsb(PVM pVM, PPDMUSBINS pUsbIns, TMCLOCK enmClock, PFNTMTIMERUSB pfnCallback, + void *pvUser, uint32_t fFlags, const char *pszName, PTMTIMERHANDLE phTimer); +VMM_INT_DECL(int) TMR3TimerCreateDriver(PVM pVM, PPDMDRVINS pDrvIns, TMCLOCK enmClock, PFNTMTIMERDRV pfnCallback, + void *pvUser, uint32_t fFlags, const char *pszName, PTMTIMERHANDLE phTimer); +VMMR3DECL(int) TMR3TimerCreate(PVM pVM, TMCLOCK enmClock, PFNTMTIMERINT pfnCallback, void *pvUser, uint32_t fFlags, + const char *pszName, PTMTIMERHANDLE phTimer); +VMMR3DECL(int) TMR3TimerDestroy(PVM pVM, TMTIMERHANDLE hTimer); +VMM_INT_DECL(int) TMR3TimerDestroyDevice(PVM pVM, PPDMDEVINS pDevIns); +VMM_INT_DECL(int) TMR3TimerDestroyUsb(PVM pVM, PPDMUSBINS pUsbIns); +VMM_INT_DECL(int) TMR3TimerDestroyDriver(PVM pVM, PPDMDRVINS pDrvIns); +VMMR3DECL(int) TMR3TimerSave(PVMCC pVM, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM); +VMMR3DECL(int) TMR3TimerLoad(PVMCC pVM, TMTIMERHANDLE hTimer, PSSMHANDLE pSSM); +VMMR3DECL(int) TMR3TimerSkip(PSSMHANDLE pSSM, bool *pfActive); +VMMR3DECL(int) TMR3TimerSetCritSect(PVMCC pVM, TMTIMERHANDLE hTimer, PPDMCRITSECT pCritSect); +VMMR3DECL(void) TMR3TimerQueuesDo(PVM pVM); +VMMR3_INT_DECL(void) TMR3VirtualSyncFF(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(PRTTIMESPEC) TMR3UtcNow(PVM pVM, PRTTIMESPEC pTime); + +VMMR3_INT_DECL(int) TMR3CpuTickParavirtEnable(PVM pVM); +VMMR3_INT_DECL(int) TMR3CpuTickParavirtDisable(PVM pVM); +VMMR3_INT_DECL(bool) TMR3CpuTickIsFixedRateMonotonic(PVM pVM, bool fWithParavirtEnabled); +/** @} */ + + +/** @defgroup grp_tm_r0 The TM Host Context Ring-0 API + * @{ + */ +VMMR0_INT_DECL(void) TMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(void) TMR0CleanupVM(PGVM pGVM); +VMMR0_INT_DECL(int) TMR0TimerQueueGrow(PGVM pGVM, uint32_t idxQueue, uint32_t cMinTimers); +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_tm_h */ + diff --git a/include/VBox/vmm/trpm.h b/include/VBox/vmm/trpm.h new file mode 100644 index 00000000..0e23dd5b --- /dev/null +++ b/include/VBox/vmm/trpm.h @@ -0,0 +1,102 @@ +/** @file + * TRPM - The Trap Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_trpm_h +#define VBOX_INCLUDED_vmm_trpm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + + +RT_C_DECLS_BEGIN +/** @defgroup grp_trpm The Trap Monitor API + * @ingroup grp_vmm + * @{ + */ + +/** + * TRPM event type. + */ +typedef enum +{ + TRPM_TRAP = 0, + TRPM_HARDWARE_INT = 1, + TRPM_SOFTWARE_INT = 2, + /** The usual 32-bit paranoia. */ + TRPM_32BIT_HACK = 0x7fffffff +} TRPMEVENT; +/** Pointer to a TRPM event type. */ +typedef TRPMEVENT *PTRPMEVENT; +/** Pointer to a const TRPM event type. */ +typedef TRPMEVENT const *PCTRPMEVENT; + +VMMDECL(int) TRPMQueryTrap(PVMCPU pVCpu, uint8_t *pu8TrapNo, PTRPMEVENT penmType); +VMMDECL(uint8_t) TRPMGetTrapNo(PVMCPU pVCpu); +VMMDECL(uint32_t) TRPMGetErrorCode(PVMCPU pVCpu); +VMMDECL(RTGCUINTPTR) TRPMGetFaultAddress(PVMCPU pVCpu); +VMMDECL(uint8_t) TRPMGetInstrLength(PVMCPU pVCpu); +VMMDECL(bool) TRPMIsTrapDueToIcebp(PVMCPU pVCpu); +VMMDECL(int) TRPMResetTrap(PVMCPU pVCpu); +VMMDECL(int) TRPMAssertTrap(PVMCPUCC pVCpu, uint8_t u8TrapNo, TRPMEVENT enmType); +VMMDECL(int) TRPMAssertXcptPF(PVMCPUCC pVCpu, RTGCUINTPTR uCR2, uint32_t uErrorCode); +VMMDECL(void) TRPMSetErrorCode(PVMCPU pVCpu, uint32_t uErrorCode); +VMMDECL(void) TRPMSetFaultAddress(PVMCPU pVCpu, RTGCUINTPTR uCR2); +VMMDECL(void) TRPMSetInstrLength(PVMCPU pVCpu, uint8_t cbInstr); +VMMDECL(void) TRPMSetTrapDueToIcebp(PVMCPU pVCpu); +VMMDECL(bool) TRPMIsSoftwareInterrupt(PVMCPU pVCpu); +VMMDECL(bool) TRPMHasTrap(PVMCPU pVCpu); +VMMDECL(int) TRPMQueryTrapAll(PVMCPU pVCpu, uint8_t *pu8TrapNo, PTRPMEVENT pEnmType, uint32_t *puErrorCode, + PRTGCUINTPTR puCR2, uint8_t *pcbInstr, bool *pfIcebp); + +#ifdef IN_RING3 +/** @defgroup grp_trpm_r3 TRPM Host Context Ring 3 API + * @{ + */ +VMMR3DECL(int) TRPMR3Init(PVM pVM); +VMMR3DECL(void) TRPMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3DECL(void) TRPMR3ResetCpu(PVMCPU pVCpu); +VMMR3DECL(void) TRPMR3Reset(PVM pVM); +VMMR3DECL(int) TRPMR3Term(PVM pVM); +VMMR3DECL(int) TRPMR3InjectEvent(PVM pVM, PVMCPU pVCpu, TRPMEVENT enmEvent, bool *pfInjected); +/** @} */ +#endif + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_trpm_h */ diff --git a/include/VBox/vmm/trpm.mac b/include/VBox/vmm/trpm.mac new file mode 100644 index 00000000..6e1c1cd6 --- /dev/null +++ b/include/VBox/vmm/trpm.mac @@ -0,0 +1,57 @@ +;; @file +; TRPM - The Trap Monitor. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_vmm_trpm_mac__ +%define ___VBox_vmm_trpm_mac__ + + +;/** +; * TRPM event type +; */ +;/** Note: must match trpm.mac! */ +;typedef enum +;{ +; TRPM_TRAP = 0, +; TRPM_HARDWARE_INT = 1, +; TRPM_SOFTWARE_INT = 2, +; /** The usual 32-bit paranoia. */ +; TRPM_32BIT_HACK = 0x7fffffff +;} TRPMEVENT; + +%define TRPM_TRAP 0 +%define TRPM_HARDWARE_INT 1 +%define TRPM_SOFTWARE_INT 2 +%endif + diff --git a/include/VBox/vmm/uvm.h b/include/VBox/vmm/uvm.h new file mode 100644 index 00000000..2edc65db --- /dev/null +++ b/include/VBox/vmm/uvm.h @@ -0,0 +1,195 @@ +/** @file + * GVM - The Global VM Data. + */ + +/* + * Copyright (C) 2007-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_uvm_h +#define VBOX_INCLUDED_vmm_uvm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +/** @addtogroup grp_vm + * @{ */ + + +/** + * Per virtual CPU ring-3 (user mode) data. + */ +typedef struct UVMCPU +{ + /** Pointer to the UVM structure. */ + PUVM pUVM; + /** Pointer to the VM structure. */ + PVM pVM; + /** Pointer to the VMCPU structure. */ + PVMCPU pVCpu; + /** The virtual CPU ID. */ + RTCPUID idCpu; + /** Alignment padding. */ + uint8_t abAlignment0[HC_ARCH_BITS == 32 ? 16 : 4]; + + /** The VM internal data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_VMInternal_h + struct VMINTUSERPERVMCPU s; +#endif + uint8_t padding[512]; + } vm; + + /** The DBGF data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_DBGFInternal_h + struct DBGFUSERPERVMCPU s; +#endif + uint8_t padding[64]; + } dbgf; + +} UVMCPU; +AssertCompileMemberAlignment(UVMCPU, vm, 32); + + +/** + * The ring-3 (user mode) VM structure. + * + * This structure is similar to VM and GVM except that it resides in swappable + * user memory. The main purpose is to assist bootstrapping, where it allows us + * to start EMT much earlier and gives PDMLdr somewhere to put it's VMMR0 data. + * It is also a nice place to put big things that are user mode only. + */ +typedef struct UVM +{ + /** Magic / eye-catcher (UVM_MAGIC). */ + uint32_t u32Magic; + /** The number of virtual CPUs. */ + uint32_t cCpus; + /** The ring-3 mapping of the shared VM structure. */ + PVM pVM; + /** Pointer to the next VM. + * We keep a per process list of VM for the event that a process could + * contain more than one VM. + * @todo move this into vm.s! + */ + struct UVM *pNext; + + /** Pointer to the optional method table provided by the VMM user. */ + PCVMM2USERMETHODS pVmm2UserMethods; + +#if HC_ARCH_BITS == 32 + /** Align the next member on a 32 byte boundary. */ + uint8_t abAlignment0[HC_ARCH_BITS == 32 ? 12 : 0]; +#endif + + /** The VM internal data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_VMInternal_h + struct VMINTUSERPERVM s; +#endif + uint8_t padding[512]; + } vm; + + /** The MM data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_MMInternal_h + struct MMUSERPERVM s; +#endif + uint8_t padding[32]; + } mm; + + /** The PDM data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_PDMInternal_h + struct PDMUSERPERVM s; +#endif + uint8_t padding[256]; + } pdm; + + /** The STAM data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_STAMInternal_h + struct STAMUSERPERVM s; +#endif + uint8_t padding[30208]; + } stam; + + /** The DBGF data. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_DBGFInternal_h + struct DBGFUSERPERVM s; +#endif + uint8_t padding[1024]; + } dbgf; + + /** Per virtual CPU data. */ + UVMCPU aCpus[1]; +} UVM; +AssertCompileMemberAlignment(UVM, vm, 32); +AssertCompileMemberAlignment(UVM, mm, 32); +AssertCompileMemberAlignment(UVM, pdm, 32); +AssertCompileMemberAlignment(UVM, stam, 32); +AssertCompileMemberAlignment(UVM, aCpus, 32); + +/** The UVM::u32Magic value (Brad Mehldau). */ +#define UVM_MAGIC 0x19700823 + +/** @def UVM_ASSERT_VALID_EXT_RETURN + * Asserts a user mode VM handle is valid for external access. + */ +#define UVM_ASSERT_VALID_EXT_RETURN(a_pUVM, a_rc) \ + AssertMsgReturn( RT_VALID_ALIGNED_PTR(a_pUVM, PAGE_SIZE) \ + && (a_pUVM)->u32Magic == UVM_MAGIC, \ + ("a_pUVM=%p u32Magic=%#x\n", (a_pUVM), \ + RT_VALID_ALIGNED_PTR(a_pUVM, PAGE_SIZE) ? (a_pUVM)->u32Magic : 0), \ + (a_rc)) +/** @def UVM_ASSERT_VALID_EXT_RETURN + * Asserts a user mode VM handle is valid for external access. + */ +#define UVM_ASSERT_VALID_EXT_RETURN_VOID(a_pUVM) \ + AssertMsgReturnVoid( RT_VALID_ALIGNED_PTR(a_pUVM, PAGE_SIZE) \ + && (a_pUVM)->u32Magic == UVM_MAGIC, \ + ("a_pUVM=%p u32Magic=%#x\n", (a_pUVM), \ + RT_VALID_ALIGNED_PTR(a_pUVM, PAGE_SIZE) ? (a_pUVM)->u32Magic : 0)) + +/** @} */ +#endif /* !VBOX_INCLUDED_vmm_uvm_h */ + diff --git a/include/VBox/vmm/vm.h b/include/VBox/vmm/vm.h new file mode 100644 index 00000000..2ebdda94 --- /dev/null +++ b/include/VBox/vmm/vm.h @@ -0,0 +1,1519 @@ +/** @file + * VM - The Virtual Machine, data. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vm_h +#define VBOX_INCLUDED_vmm_vm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#ifndef VBOX_FOR_DTRACE_LIB +# ifndef USING_VMM_COMMON_DEFS +# error "Compile job does not include VMM_COMMON_DEFS from src/VBox/VMM/Config.kmk - make sure you really need to include this file!" +# endif +# include +# include +# include +# include +# include +# include +# include +# include +#else +# pragma D depends_on library vbox-types.d +# pragma D depends_on library CPUMInternal.d +# define VMM_INCLUDED_SRC_include_CPUMInternal_h +#endif + + + +/** @defgroup grp_vm The Virtual Machine + * @ingroup grp_vmm + * @{ + */ + +/** + * The state of a Virtual CPU. + * + * The basic state indicated here is whether the CPU has been started or not. In + * addition, there are sub-states when started for assisting scheduling (GVMM + * mostly). + * + * The transition out of the STOPPED state is done by a vmR3PowerOn. + * The transition back to the STOPPED state is done by vmR3PowerOff. + * + * (Alternatively we could let vmR3PowerOn start CPU 0 only and let the SPIP + * handling switch on the other CPUs. Then vmR3Reset would stop all but CPU 0.) + */ +typedef enum VMCPUSTATE +{ + /** The customary invalid zero. */ + VMCPUSTATE_INVALID = 0, + + /** Virtual CPU has not yet been started. */ + VMCPUSTATE_STOPPED, + + /** CPU started. */ + VMCPUSTATE_STARTED, + /** CPU started in HM context. */ + VMCPUSTATE_STARTED_HM, + /** Executing guest code and can be poked (RC or STI bits of HM). */ + VMCPUSTATE_STARTED_EXEC, + /** Executing guest code using NEM. */ + VMCPUSTATE_STARTED_EXEC_NEM, + VMCPUSTATE_STARTED_EXEC_NEM_WAIT, + VMCPUSTATE_STARTED_EXEC_NEM_CANCELED, + /** Halted. */ + VMCPUSTATE_STARTED_HALTED, + + /** The end of valid virtual CPU states. */ + VMCPUSTATE_END, + + /** Ensure 32-bit type. */ + VMCPUSTATE_32BIT_HACK = 0x7fffffff +} VMCPUSTATE; + +/** Enables 64-bit FFs. */ +#define VMCPU_WITH_64_BIT_FFS + + +/** + * The cross context virtual CPU structure. + * + * Run 'kmk run-struct-tests' (from src/VBox/VMM if you like) after updating! + */ +typedef struct VMCPU +{ + /** @name Volatile per-cpu data. + * @{ */ + /** Per CPU forced action. + * See the VMCPU_FF_* \#defines. Updated atomically. */ +#ifdef VMCPU_WITH_64_BIT_FFS + uint64_t volatile fLocalForcedActions; +#else + uint32_t volatile fLocalForcedActions; + uint32_t fForLocalForcedActionsExpansion; +#endif + /** The CPU state. */ + VMCPUSTATE volatile enmState; + + /** Padding up to 64 bytes. */ + uint8_t abAlignment0[64 - 12]; + /** @} */ + + /** IEM part. + * @remarks This comes first as it allows the use of 8-bit immediates for the + * first 64 bytes of the structure, reducing code size a wee bit. */ +#ifdef VMM_INCLUDED_SRC_include_IEMInternal_h /* For PDB hacking. */ + union VMCPUUNIONIEMFULL +#else + union VMCPUUNIONIEMSTUB +#endif + { +#ifdef VMM_INCLUDED_SRC_include_IEMInternal_h + struct IEMCPU s; +#endif + uint8_t padding[32832]; /* multiple of 64 */ + } iem; + + /** @name Static per-cpu data. + * (Putting this after IEM, hoping that it's less frequently used than it.) + * @{ */ + /** Ring-3 Host Context VM Pointer. */ + PVMR3 pVMR3; + /** Ring-0 Host Context VM Pointer, currently used by VTG/dtrace. */ + RTR0PTR pVCpuR0ForVtg; + /** Raw-mode Context VM Pointer. */ + uint32_t pVMRC; + /** Padding for new raw-mode (long mode). */ + uint32_t pVMRCPadding; + /** Pointer to the ring-3 UVMCPU structure. */ + PUVMCPU pUVCpu; + /** The native thread handle. */ + RTNATIVETHREAD hNativeThread; + /** The native R0 thread handle. (different from the R3 handle!) */ + RTNATIVETHREAD hNativeThreadR0; + /** The IPRT thread handle (for VMMDevTesting). */ + RTTHREAD hThread; + /** The CPU ID. + * This is the index into the VM::aCpu array. */ +#ifdef IN_RING0 + VMCPUID idCpuUnsafe; +#else + VMCPUID idCpu; +#endif + + /** Align the structures below bit on a 64-byte boundary and make sure it starts + * at the same offset in both 64-bit and 32-bit builds. + * + * @remarks The alignments of the members that are larger than 48 bytes should be + * 64-byte for cache line reasons. structs containing small amounts of + * data could be lumped together at the end with a < 64 byte padding + * following it (to grow into and align the struct size). + */ + uint8_t abAlignment1[64 - 6 * (HC_ARCH_BITS == 32 ? 4 : 8) - 8 - 4]; + /** @} */ + + /** HM part. */ + union VMCPUUNIONHM + { +#ifdef VMM_INCLUDED_SRC_include_HMInternal_h + struct HMCPU s; +#endif + uint8_t padding[9984]; /* multiple of 64 */ + } hm; + + /** NEM part. */ + union VMCPUUNIONNEM + { +#ifdef VMM_INCLUDED_SRC_include_NEMInternal_h + struct NEMCPU s; +#endif + uint8_t padding[4608]; /* multiple of 64 */ + } nem; + + /** TRPM part. */ + union VMCPUUNIONTRPM + { +#ifdef VMM_INCLUDED_SRC_include_TRPMInternal_h + struct TRPMCPU s; +#endif + uint8_t padding[128]; /* multiple of 64 */ + } trpm; + + /** TM part. */ + union VMCPUUNIONTM + { +#ifdef VMM_INCLUDED_SRC_include_TMInternal_h + struct TMCPU s; +#endif + uint8_t padding[5760]; /* multiple of 64 */ + } tm; + + /** VMM part. */ + union VMCPUUNIONVMM + { +#ifdef VMM_INCLUDED_SRC_include_VMMInternal_h + struct VMMCPU s; +#endif + uint8_t padding[9536]; /* multiple of 64 */ + } vmm; + + /** PDM part. */ + union VMCPUUNIONPDM + { +#ifdef VMM_INCLUDED_SRC_include_PDMInternal_h + struct PDMCPU s; +#endif + uint8_t padding[256]; /* multiple of 64 */ + } pdm; + + /** IOM part. */ + union VMCPUUNIONIOM + { +#ifdef VMM_INCLUDED_SRC_include_IOMInternal_h + struct IOMCPU s; +#endif + uint8_t padding[512]; /* multiple of 64 */ + } iom; + + /** DBGF part. + * @todo Combine this with other tiny structures. */ + union VMCPUUNIONDBGF + { +#ifdef VMM_INCLUDED_SRC_include_DBGFInternal_h + struct DBGFCPU s; +#endif + uint8_t padding[512]; /* multiple of 64 */ + } dbgf; + + /** GIM part. */ + union VMCPUUNIONGIM + { +#ifdef VMM_INCLUDED_SRC_include_GIMInternal_h + struct GIMCPU s; +#endif + uint8_t padding[512]; /* multiple of 64 */ + } gim; + + /** APIC part. */ + union VMCPUUNIONAPIC + { +#ifdef VMM_INCLUDED_SRC_include_APICInternal_h + struct APICCPU s; +#endif + uint8_t padding[3840]; /* multiple of 64 */ + } apic; + + /* + * Some less frequently used global members that doesn't need to take up + * precious space at the head of the structure. + */ + + /** Trace groups enable flags. */ + uint32_t fTraceGroups; /* 64 / 44 */ + /** Number of collisions hashing the ring-0 EMT handle. */ + uint8_t cEmtHashCollisions; + uint8_t abAdHoc[3]; + /** Profiling samples for use by ad hoc profiling. */ + STAMPROFILEADV aStatAdHoc[8]; /* size: 40*8 = 320 */ + + /** Align the following members on page boundary. */ + uint8_t abAlignment2[696]; + + /** PGM part. */ + union VMCPUUNIONPGM + { +#ifdef VMM_INCLUDED_SRC_include_PGMInternal_h + struct PGMCPU s; +#endif + uint8_t padding[4096 + 28672]; /* multiple of 4096 */ + } pgm; + + /** CPUM part. */ + union VMCPUUNIONCPUM + { +#ifdef VMM_INCLUDED_SRC_include_CPUMInternal_h + struct CPUMCPU s; +#endif +#ifdef VMCPU_INCL_CPUM_GST_CTX + /** The guest CPUM context for direct use by execution engines. + * This is not for general consumption, but for HM, REM, IEM, and maybe a few + * others. The rest will use the function based CPUM API. */ + CPUMCTX GstCtx; +#endif + uint8_t padding[102400]; /* multiple of 4096 */ + } cpum; + + /** EM part. */ + union VMCPUUNIONEM + { +#ifdef VMM_INCLUDED_SRC_include_EMInternal_h + struct EMCPU s; +#endif + uint8_t padding[40960]; /* multiple of 4096 */ + } em; + +} VMCPU; + + +#ifndef VBOX_FOR_DTRACE_LIB +/* Make sure the structure size is aligned on a 16384 boundary for arm64 purposes. */ +AssertCompileSizeAlignment(VMCPU, 16384); + +/** @name Operations on VMCPU::enmState + * @{ */ +/** Gets the VMCPU state. */ +#define VMCPU_GET_STATE(pVCpu) ( (pVCpu)->enmState ) +/** Sets the VMCPU state. */ +#define VMCPU_SET_STATE(pVCpu, enmNewState) \ + ASMAtomicWriteU32((uint32_t volatile *)&(pVCpu)->enmState, (enmNewState)) +/** Cmpares and sets the VMCPU state. */ +#define VMCPU_CMPXCHG_STATE(pVCpu, enmNewState, enmOldState) \ + ASMAtomicCmpXchgU32((uint32_t volatile *)&(pVCpu)->enmState, (enmNewState), (enmOldState)) +/** Checks the VMCPU state. */ +#ifdef VBOX_STRICT +# define VMCPU_ASSERT_STATE(pVCpu, enmExpectedState) \ + do { \ + VMCPUSTATE enmState = VMCPU_GET_STATE(pVCpu); \ + AssertMsg(enmState == (enmExpectedState), \ + ("enmState=%d enmExpectedState=%d idCpu=%u\n", \ + enmState, enmExpectedState, (pVCpu)->idCpu)); \ + } while (0) + +# define VMCPU_ASSERT_STATE_2(pVCpu, enmExpectedState, a_enmExpectedState2) \ + do { \ + VMCPUSTATE enmState = VMCPU_GET_STATE(pVCpu); \ + AssertMsg( enmState == (enmExpectedState) \ + || enmState == (a_enmExpectedState2), \ + ("enmState=%d enmExpectedState=%d enmExpectedState2=%d idCpu=%u\n", \ + enmState, enmExpectedState, a_enmExpectedState2, (pVCpu)->idCpu)); \ + } while (0) +#else +# define VMCPU_ASSERT_STATE(pVCpu, enmExpectedState) do { } while (0) +# define VMCPU_ASSERT_STATE_2(pVCpu, enmExpectedState, a_enmExpectedState2) do { } while (0) +#endif +/** Tests if the state means that the CPU is started. */ +#define VMCPUSTATE_IS_STARTED(enmState) ( (enmState) > VMCPUSTATE_STOPPED ) +/** Tests if the state means that the CPU is stopped. */ +#define VMCPUSTATE_IS_STOPPED(enmState) ( (enmState) == VMCPUSTATE_STOPPED ) +/** @} */ + + +/** The name of the raw-mode context VMM Core module. */ +#define VMMRC_MAIN_MODULE_NAME "VMMRC.rc" +/** The name of the ring-0 context VMM Core module. */ +#define VMMR0_MAIN_MODULE_NAME "VMMR0.r0" + + +/** VM Forced Action Flags. + * + * Use the VM_FF_SET() and VM_FF_CLEAR() macros to change the force + * action mask of a VM. + * + * Available VM bits: + * 0, 1, 5, 6, 7, 13, 14, 15, 16, 17, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30 + * + * + * Available VMCPU bits: + * 14, 15, 36 to 63 + * + * @todo If we run low on VMCPU, we may consider merging the SELM bits + * + * @{ + */ +/** The virtual sync clock has been stopped, go to TM until it has been + * restarted... */ +#define VM_FF_TM_VIRTUAL_SYNC RT_BIT_32(VM_FF_TM_VIRTUAL_SYNC_BIT) +#define VM_FF_TM_VIRTUAL_SYNC_BIT 2 +/** PDM Queues are pending. */ +#define VM_FF_PDM_QUEUES RT_BIT_32(VM_FF_PDM_QUEUES_BIT) +/** The bit number for VM_FF_PDM_QUEUES. */ +#define VM_FF_PDM_QUEUES_BIT 3 +/** PDM DMA transfers are pending. */ +#define VM_FF_PDM_DMA RT_BIT_32(VM_FF_PDM_DMA_BIT) +/** The bit number for VM_FF_PDM_DMA. */ +#define VM_FF_PDM_DMA_BIT 4 +/** This action forces the VM to call DBGF so DBGF can service debugger + * requests in the emulation thread. + * This action flag stays asserted till DBGF clears it.*/ +#define VM_FF_DBGF RT_BIT_32(VM_FF_DBGF_BIT) +/** The bit number for VM_FF_DBGF. */ +#define VM_FF_DBGF_BIT 8 +/** This action forces the VM to service pending requests from other + * thread or requests which must be executed in another context. */ +#define VM_FF_REQUEST RT_BIT_32(VM_FF_REQUEST_BIT) +#define VM_FF_REQUEST_BIT 9 +/** Check for VM state changes and take appropriate action. */ +#define VM_FF_CHECK_VM_STATE RT_BIT_32(VM_FF_CHECK_VM_STATE_BIT) +/** The bit number for VM_FF_CHECK_VM_STATE. */ +#define VM_FF_CHECK_VM_STATE_BIT 10 +/** Reset the VM. (postponed) */ +#define VM_FF_RESET RT_BIT_32(VM_FF_RESET_BIT) +/** The bit number for VM_FF_RESET. */ +#define VM_FF_RESET_BIT 11 +/** EMT rendezvous in VMM. */ +#define VM_FF_EMT_RENDEZVOUS RT_BIT_32(VM_FF_EMT_RENDEZVOUS_BIT) +/** The bit number for VM_FF_EMT_RENDEZVOUS. */ +#define VM_FF_EMT_RENDEZVOUS_BIT 12 + +/** PGM needs to allocate handy pages. */ +#define VM_FF_PGM_NEED_HANDY_PAGES RT_BIT_32(VM_FF_PGM_NEED_HANDY_PAGES_BIT) +#define VM_FF_PGM_NEED_HANDY_PAGES_BIT 18 +/** PGM is out of memory. + * Abandon all loops and code paths which can be resumed and get up to the EM + * loops. */ +#define VM_FF_PGM_NO_MEMORY RT_BIT_32(VM_FF_PGM_NO_MEMORY_BIT) +#define VM_FF_PGM_NO_MEMORY_BIT 19 + /** PGM is about to perform a lightweight pool flush + * Guest SMP: all EMT threads should return to ring 3 + */ +#define VM_FF_PGM_POOL_FLUSH_PENDING RT_BIT_32(VM_FF_PGM_POOL_FLUSH_PENDING_BIT) +#define VM_FF_PGM_POOL_FLUSH_PENDING_BIT 20 +/** Suspend the VM - debug only. */ +#define VM_FF_DEBUG_SUSPEND RT_BIT_32(VM_FF_DEBUG_SUSPEND_BIT) +#define VM_FF_DEBUG_SUSPEND_BIT 31 + + +/** This action forces the VM to check any pending interrupts on the APIC. */ +#define VMCPU_FF_INTERRUPT_APIC RT_BIT_64(VMCPU_FF_INTERRUPT_APIC_BIT) +#define VMCPU_FF_INTERRUPT_APIC_BIT 0 +/** This action forces the VM to check any pending interrups on the PIC. */ +#define VMCPU_FF_INTERRUPT_PIC RT_BIT_64(VMCPU_FF_INTERRUPT_PIC_BIT) +#define VMCPU_FF_INTERRUPT_PIC_BIT 1 +/** This action forces the VM to schedule and run pending timer (TM). + * @remarks Don't move - PATM compatibility. */ +#define VMCPU_FF_TIMER RT_BIT_64(VMCPU_FF_TIMER_BIT) +#define VMCPU_FF_TIMER_BIT 2 +/** This action forces the VM to check any pending NMIs. */ +#define VMCPU_FF_INTERRUPT_NMI RT_BIT_64(VMCPU_FF_INTERRUPT_NMI_BIT) +#define VMCPU_FF_INTERRUPT_NMI_BIT 3 +/** This action forces the VM to check any pending SMIs. */ +#define VMCPU_FF_INTERRUPT_SMI RT_BIT_64(VMCPU_FF_INTERRUPT_SMI_BIT) +#define VMCPU_FF_INTERRUPT_SMI_BIT 4 +/** PDM critical section unlocking is pending, process promptly upon return to R3. */ +#define VMCPU_FF_PDM_CRITSECT RT_BIT_64(VMCPU_FF_PDM_CRITSECT_BIT) +#define VMCPU_FF_PDM_CRITSECT_BIT 5 +/** Special EM internal force flag that is used by EMUnhaltAndWakeUp() to force + * the virtual CPU out of the next (/current) halted state. It is not processed + * nor cleared by emR3ForcedActions (similar to VMCPU_FF_BLOCK_NMIS), instead it + * is cleared the next time EM leaves the HALTED state. */ +#define VMCPU_FF_UNHALT RT_BIT_64(VMCPU_FF_UNHALT_BIT) +#define VMCPU_FF_UNHALT_BIT 6 +/** Pending IEM action (mask). */ +#define VMCPU_FF_IEM RT_BIT_64(VMCPU_FF_IEM_BIT) +/** Pending IEM action (bit number). */ +#define VMCPU_FF_IEM_BIT 7 +/** Pending APIC action (bit number). */ +#define VMCPU_FF_UPDATE_APIC_BIT 8 +/** This action forces the VM to update APIC's asynchronously arrived + * interrupts as pending interrupts. */ +#define VMCPU_FF_UPDATE_APIC RT_BIT_64(VMCPU_FF_UPDATE_APIC_BIT) +/** This action forces the VM to service pending requests from other + * thread or requests which must be executed in another context. */ +#define VMCPU_FF_REQUEST RT_BIT_64(VMCPU_FF_REQUEST_BIT) +#define VMCPU_FF_REQUEST_BIT 9 +/** Pending DBGF event (alternative to passing VINF_EM_DBG_EVENT around). */ +#define VMCPU_FF_DBGF RT_BIT_64(VMCPU_FF_DBGF_BIT) +/** The bit number for VMCPU_FF_DBGF. */ +#define VMCPU_FF_DBGF_BIT 10 +/** Hardware virtualized nested-guest interrupt pending. */ +#define VMCPU_FF_INTERRUPT_NESTED_GUEST RT_BIT_64(VMCPU_FF_INTERRUPT_NESTED_GUEST_BIT) +#define VMCPU_FF_INTERRUPT_NESTED_GUEST_BIT 11 +/** This action forces PGM to update changes to CR3 when the guest was in HM mode + * (when using nested paging). */ +#define VMCPU_FF_HM_UPDATE_CR3 RT_BIT_64(VMCPU_FF_HM_UPDATE_CR3_BIT) +#define VMCPU_FF_HM_UPDATE_CR3_BIT 12 +/* Bit 13 used to be VMCPU_FF_HM_UPDATE_PAE_PDPES. */ +/** This action forces the VM to resync the page tables before going + * back to execute guest code. (GLOBAL FLUSH) */ +#define VMCPU_FF_PGM_SYNC_CR3 RT_BIT_64(VMCPU_FF_PGM_SYNC_CR3_BIT) +#define VMCPU_FF_PGM_SYNC_CR3_BIT 16 +/** Same as VM_FF_PGM_SYNC_CR3 except that global pages can be skipped. + * (NON-GLOBAL FLUSH) */ +#define VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL RT_BIT_64(VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL_BIT) +#define VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL_BIT 17 +/** Check for pending TLB shootdown actions (deprecated) + * Reserved for future HM re-use if necessary / safe. + * Consumer: HM */ +#define VMCPU_FF_TLB_SHOOTDOWN_UNUSED RT_BIT_64(VMCPU_FF_TLB_SHOOTDOWN_UNUSED_BIT) +#define VMCPU_FF_TLB_SHOOTDOWN_UNUSED_BIT 18 +/** Check for pending TLB flush action. + * Consumer: HM + * @todo rename to VMCPU_FF_HM_TLB_FLUSH */ +#define VMCPU_FF_TLB_FLUSH RT_BIT_64(VMCPU_FF_TLB_FLUSH_BIT) +/** The bit number for VMCPU_FF_TLB_FLUSH. */ +#define VMCPU_FF_TLB_FLUSH_BIT 19 +/* 20 used to be VMCPU_FF_TRPM_SYNC_IDT (raw-mode only). */ +/* 21 used to be VMCPU_FF_SELM_SYNC_TSS (raw-mode only). */ +/* 22 used to be VMCPU_FF_SELM_SYNC_GDT (raw-mode only). */ +/* 23 used to be VMCPU_FF_SELM_SYNC_LDT (raw-mode only). */ +/* 24 used to be VMCPU_FF_INHIBIT_INTERRUPTS, which moved to CPUMCTX::eflags.uBoth in v7.0.4. */ +/* 25 used to be VMCPU_FF_BLOCK_NMIS, which moved to CPUMCTX::eflags.uBoth in v7.0.4. */ +/** Force return to Ring-3. */ +#define VMCPU_FF_TO_R3 RT_BIT_64(VMCPU_FF_TO_R3_BIT) +#define VMCPU_FF_TO_R3_BIT 28 +/** Force return to ring-3 to service pending I/O or MMIO write. + * This is a backup for mechanism VINF_IOM_R3_IOPORT_COMMIT_WRITE and + * VINF_IOM_R3_MMIO_COMMIT_WRITE, allowing VINF_EM_DBG_BREAKPOINT and similar + * status codes to be propagated at the same time without loss. */ +#define VMCPU_FF_IOM RT_BIT_64(VMCPU_FF_IOM_BIT) +#define VMCPU_FF_IOM_BIT 29 +/* 30 used to be VMCPU_FF_CPUM */ +/** VMX-preemption timer expired. */ +#define VMCPU_FF_VMX_PREEMPT_TIMER RT_BIT_64(VMCPU_FF_VMX_PREEMPT_TIMER_BIT) +#define VMCPU_FF_VMX_PREEMPT_TIMER_BIT 31 +/** Pending MTF (Monitor Trap Flag) event. */ +#define VMCPU_FF_VMX_MTF RT_BIT_64(VMCPU_FF_VMX_MTF_BIT) +#define VMCPU_FF_VMX_MTF_BIT 32 +/** VMX APIC-write emulation pending. + * @todo possible candidate for internal EFLAGS, or maybe just a summary bit + * (see also VMCPU_FF_VMX_INT_WINDOW). */ +#define VMCPU_FF_VMX_APIC_WRITE RT_BIT_64(VMCPU_FF_VMX_APIC_WRITE_BIT) +#define VMCPU_FF_VMX_APIC_WRITE_BIT 33 +/** VMX interrupt-window event pending. + * + * "Pending" is misleading here, it would be better to say that the event need + * to be generated at the next opportunity and that this flag causes it to be + * polled for on every instruction boundrary and such. + * + * @todo Change the IEM side of this to not poll but to track down the places + * where it can be generated and set an internal EFLAGS bit that causes it + * to be checked out when finishing the current instruction. */ +#define VMCPU_FF_VMX_INT_WINDOW RT_BIT_64(VMCPU_FF_VMX_INT_WINDOW_BIT) +#define VMCPU_FF_VMX_INT_WINDOW_BIT 34 +/** VMX NMI-window event pending. + * Same "pending" comment and todo in VMCPU_FF_VMX_INT_WINDOW. */ +#define VMCPU_FF_VMX_NMI_WINDOW RT_BIT_64(VMCPU_FF_VMX_NMI_WINDOW_BIT) +#define VMCPU_FF_VMX_NMI_WINDOW_BIT 35 + + +/** Externally VM forced actions. Used to quit the idle/wait loop. */ +#define VM_FF_EXTERNAL_SUSPENDED_MASK ( VM_FF_CHECK_VM_STATE | VM_FF_DBGF | VM_FF_REQUEST | VM_FF_EMT_RENDEZVOUS ) +/** Externally VMCPU forced actions. Used to quit the idle/wait loop. */ +#define VMCPU_FF_EXTERNAL_SUSPENDED_MASK ( VMCPU_FF_REQUEST | VMCPU_FF_DBGF ) + +/** Externally forced VM actions. Used to quit the idle/wait loop. */ +#define VM_FF_EXTERNAL_HALTED_MASK ( VM_FF_CHECK_VM_STATE | VM_FF_DBGF | VM_FF_REQUEST \ + | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_EMT_RENDEZVOUS ) +/** Externally forced VMCPU actions. Used to quit the idle/wait loop. */ +#define VMCPU_FF_EXTERNAL_HALTED_MASK ( VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC \ + | VMCPU_FF_REQUEST | VMCPU_FF_INTERRUPT_NMI | VMCPU_FF_INTERRUPT_SMI \ + | VMCPU_FF_UNHALT | VMCPU_FF_TIMER | VMCPU_FF_DBGF \ + | VMCPU_FF_INTERRUPT_NESTED_GUEST) + +/** High priority VM pre-execution actions. */ +#define VM_FF_HIGH_PRIORITY_PRE_MASK ( VM_FF_CHECK_VM_STATE | VM_FF_DBGF | VM_FF_TM_VIRTUAL_SYNC \ + | VM_FF_DEBUG_SUSPEND | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY \ + | VM_FF_EMT_RENDEZVOUS ) +/** High priority VMCPU pre-execution actions. */ +#define VMCPU_FF_HIGH_PRIORITY_PRE_MASK ( VMCPU_FF_TIMER | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_INTERRUPT_PIC \ + | VMCPU_FF_UPDATE_APIC | VMCPU_FF_DBGF \ + | VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL \ + | VMCPU_FF_INTERRUPT_NESTED_GUEST | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_APIC_WRITE \ + | VMCPU_FF_VMX_PREEMPT_TIMER | VMCPU_FF_VMX_NMI_WINDOW | VMCPU_FF_VMX_INT_WINDOW ) + +/** High priority VM pre raw-mode execution mask. */ +#define VM_FF_HIGH_PRIORITY_PRE_RAW_MASK ( VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY ) +/** High priority VMCPU pre raw-mode execution mask. */ +#define VMCPU_FF_HIGH_PRIORITY_PRE_RAW_MASK ( VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL ) + +/** High priority post-execution actions. */ +#define VM_FF_HIGH_PRIORITY_POST_MASK ( VM_FF_PGM_NO_MEMORY ) +/** High priority post-execution actions. */ +#define VMCPU_FF_HIGH_PRIORITY_POST_MASK ( VMCPU_FF_PDM_CRITSECT | VMCPU_FF_HM_UPDATE_CR3 | VMCPU_FF_IEM | VMCPU_FF_IOM ) + +/** Normal priority VM post-execution actions. */ +#define VM_FF_NORMAL_PRIORITY_POST_MASK ( VM_FF_CHECK_VM_STATE | VM_FF_DBGF | VM_FF_RESET \ + | VM_FF_PGM_NO_MEMORY | VM_FF_EMT_RENDEZVOUS) +/** Normal priority VMCPU post-execution actions. */ +#define VMCPU_FF_NORMAL_PRIORITY_POST_MASK ( VMCPU_FF_DBGF ) + +/** Normal priority VM actions. */ +#define VM_FF_NORMAL_PRIORITY_MASK ( VM_FF_REQUEST | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_EMT_RENDEZVOUS) +/** Normal priority VMCPU actions. */ +#define VMCPU_FF_NORMAL_PRIORITY_MASK ( VMCPU_FF_REQUEST ) + +/** Flags to clear before resuming guest execution. */ +#define VMCPU_FF_RESUME_GUEST_MASK ( VMCPU_FF_TO_R3 ) + + +/** VM flags that cause the REP[|NE|E] STRINS loops to yield immediately. */ +#define VM_FF_HIGH_PRIORITY_POST_REPSTR_MASK ( VM_FF_TM_VIRTUAL_SYNC | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY \ + | VM_FF_EMT_RENDEZVOUS | VM_FF_PGM_POOL_FLUSH_PENDING | VM_FF_RESET) +/** VM flags that cause the REP[|NE|E] STRINS loops to yield. */ +#define VM_FF_YIELD_REPSTR_MASK ( VM_FF_HIGH_PRIORITY_POST_REPSTR_MASK \ + | VM_FF_PDM_QUEUES | VM_FF_PDM_DMA | VM_FF_DBGF | VM_FF_DEBUG_SUSPEND ) +/** VMCPU flags that cause the REP[|NE|E] STRINS loops to yield immediately. */ +#ifdef IN_RING3 +# define VMCPU_FF_HIGH_PRIORITY_POST_REPSTR_MASK ( VMCPU_FF_PGM_SYNC_CR3 | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_DBGF \ + | VMCPU_FF_VMX_MTF ) +#else +# define VMCPU_FF_HIGH_PRIORITY_POST_REPSTR_MASK ( VMCPU_FF_TO_R3 | VMCPU_FF_IEM | VMCPU_FF_IOM | VMCPU_FF_PGM_SYNC_CR3 \ + | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_DBGF | VMCPU_FF_VMX_MTF ) +#endif +/** VMCPU flags that cause the REP[|NE|E] STRINS loops to yield, interrupts + * enabled. */ +#define VMCPU_FF_YIELD_REPSTR_MASK ( VMCPU_FF_HIGH_PRIORITY_POST_REPSTR_MASK \ + | VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_PIC \ + | VMCPU_FF_INTERRUPT_NMI | VMCPU_FF_INTERRUPT_SMI | VMCPU_FF_PDM_CRITSECT \ + | VMCPU_FF_TIMER | VMCPU_FF_REQUEST \ + | VMCPU_FF_INTERRUPT_NESTED_GUEST ) +/** VMCPU flags that cause the REP[|NE|E] STRINS loops to yield, interrupts + * disabled. */ +#define VMCPU_FF_YIELD_REPSTR_NOINT_MASK ( VMCPU_FF_YIELD_REPSTR_MASK \ + & ~( VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_PIC \ + | VMCPU_FF_INTERRUPT_NESTED_GUEST) ) + +/** VM Flags that cause the HM loops to go back to ring-3. */ +#define VM_FF_HM_TO_R3_MASK ( VM_FF_TM_VIRTUAL_SYNC | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY \ + | VM_FF_PDM_QUEUES | VM_FF_EMT_RENDEZVOUS) +/** VMCPU Flags that cause the HM loops to go back to ring-3. */ +#define VMCPU_FF_HM_TO_R3_MASK ( VMCPU_FF_TO_R3 | VMCPU_FF_TIMER | VMCPU_FF_PDM_CRITSECT \ + | VMCPU_FF_IEM | VMCPU_FF_IOM) + +/** High priority ring-0 VM pre HM-mode execution mask. */ +#define VM_FF_HP_R0_PRE_HM_MASK (VM_FF_HM_TO_R3_MASK | VM_FF_REQUEST | VM_FF_PGM_POOL_FLUSH_PENDING | VM_FF_PDM_DMA) +/** High priority ring-0 VMCPU pre HM-mode execution mask. */ +#define VMCPU_FF_HP_R0_PRE_HM_MASK ( VMCPU_FF_HM_TO_R3_MASK | VMCPU_FF_PGM_SYNC_CR3 \ + | VMCPU_FF_PGM_SYNC_CR3_NON_GLOBAL | VMCPU_FF_REQUEST \ + | VMCPU_FF_VMX_APIC_WRITE | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_PREEMPT_TIMER) +/** High priority ring-0 VM pre HM-mode execution mask, single stepping. */ +#define VM_FF_HP_R0_PRE_HM_STEP_MASK (VM_FF_HP_R0_PRE_HM_MASK & ~( VM_FF_TM_VIRTUAL_SYNC | VM_FF_PDM_QUEUES \ + | VM_FF_EMT_RENDEZVOUS | VM_FF_REQUEST \ + | VM_FF_PDM_DMA) ) +/** High priority ring-0 VMCPU pre HM-mode execution mask, single stepping. */ +#define VMCPU_FF_HP_R0_PRE_HM_STEP_MASK (VMCPU_FF_HP_R0_PRE_HM_MASK & ~( VMCPU_FF_TO_R3 | VMCPU_FF_TIMER \ + | VMCPU_FF_PDM_CRITSECT | VMCPU_FF_REQUEST) ) + +/** All the VMX nested-guest flags. */ +#define VMCPU_FF_VMX_ALL_MASK ( VMCPU_FF_VMX_PREEMPT_TIMER | VMCPU_FF_VMX_MTF | VMCPU_FF_VMX_APIC_WRITE \ + | VMCPU_FF_VMX_INT_WINDOW | VMCPU_FF_VMX_NMI_WINDOW ) + +/** All the forced VM flags. */ +#define VM_FF_ALL_MASK (UINT32_MAX) +/** All the forced VMCPU flags. */ +#define VMCPU_FF_ALL_MASK (UINT32_MAX) + +/** All the forced VM flags except those related to raw-mode and hardware + * assisted execution. */ +#define VM_FF_ALL_REM_MASK (~(VM_FF_HIGH_PRIORITY_PRE_RAW_MASK) | VM_FF_PGM_NEED_HANDY_PAGES | VM_FF_PGM_NO_MEMORY) +/** All the forced VMCPU flags except those related to raw-mode and hardware + * assisted execution. */ +#define VMCPU_FF_ALL_REM_MASK (~(VMCPU_FF_HIGH_PRIORITY_PRE_RAW_MASK | VMCPU_FF_PDM_CRITSECT | VMCPU_FF_TLB_FLUSH)) +/** @} */ + +/** @def VM_FF_SET + * Sets a single force action flag. + * + * @param pVM The cross context VM structure. + * @param fFlag The flag to set. + */ +#define VM_FF_SET(pVM, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + ASMAtomicOrU32(&(pVM)->fGlobalForcedActions, (fFlag)); \ + } while (0) + +/** @def VMCPU_FF_SET + * Sets a single force action flag for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlag The flag to set. + * @sa VMCPU_FF_SET_MASK + */ +#ifdef VMCPU_WITH_64_BIT_FFS +# define VMCPU_FF_SET(pVCpu, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_64(fFlag##_BIT)); \ + ASMAtomicBitSet(&(pVCpu)->fLocalForcedActions, fFlag##_BIT); \ + } while (0) +#else +# define VMCPU_FF_SET(pVCpu, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + ASMAtomicOrU32(&(pVCpu)->fLocalForcedActions, (fFlag)); \ + } while (0) +#endif + +/** @def VMCPU_FF_SET_MASK + * Sets a two or more force action flag for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlags The flags to set. + * @sa VMCPU_FF_SET + */ +#ifdef VMCPU_WITH_64_BIT_FFS +# if ARCH_BITS > 32 +# define VMCPU_FF_SET_MASK(pVCpu, fFlags) \ + do { ASMAtomicOrU64(&pVCpu->fLocalForcedActions, (fFlags)); } while (0) +# else +# define VMCPU_FF_SET_MASK(pVCpu, fFlags) do { \ + if (!((fFlags) >> 32)) ASMAtomicOrU32((uint32_t volatile *)&pVCpu->fLocalForcedActions, (uint32_t)(fFlags)); \ + else ASMAtomicOrU64(&pVCpu->fLocalForcedActions, (fFlags)); \ + } while (0) +# endif +#else +# define VMCPU_FF_SET_MASK(pVCpu, fFlags) \ + do { ASMAtomicOrU32(&pVCpu->fLocalForcedActions, (fFlags)); } while (0) +#endif + +/** @def VM_FF_CLEAR + * Clears a single force action flag. + * + * @param pVM The cross context VM structure. + * @param fFlag The flag to clear. + */ +#define VM_FF_CLEAR(pVM, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + ASMAtomicAndU32(&(pVM)->fGlobalForcedActions, ~(fFlag)); \ + } while (0) + +/** @def VMCPU_FF_CLEAR + * Clears a single force action flag for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlag The flag to clear. + */ +#ifdef VMCPU_WITH_64_BIT_FFS +# define VMCPU_FF_CLEAR(pVCpu, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_64(fFlag##_BIT)); \ + ASMAtomicBitClear(&(pVCpu)->fLocalForcedActions, fFlag##_BIT); \ + } while (0) +#else +# define VMCPU_FF_CLEAR(pVCpu, fFlag) do { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + ASMAtomicAndU32(&(pVCpu)->fLocalForcedActions, ~(fFlag)); \ + } while (0) +#endif + +/** @def VMCPU_FF_CLEAR_MASK + * Clears two or more force action flags for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlags The flags to clear. + */ +#ifdef VMCPU_WITH_64_BIT_FFS +# if ARCH_BITS > 32 +# define VMCPU_FF_CLEAR_MASK(pVCpu, fFlags) \ + do { ASMAtomicAndU64(&(pVCpu)->fLocalForcedActions, ~(fFlags)); } while (0) +# else +# define VMCPU_FF_CLEAR_MASK(pVCpu, fFlags) do { \ + if (!((fFlags) >> 32)) ASMAtomicAndU32((uint32_t volatile *)&(pVCpu)->fLocalForcedActions, ~(uint32_t)(fFlags)); \ + else ASMAtomicAndU64(&(pVCpu)->fLocalForcedActions, ~(fFlags)); \ + } while (0) +# endif +#else +# define VMCPU_FF_CLEAR_MASK(pVCpu, fFlags) \ + do { ASMAtomicAndU32(&(pVCpu)->fLocalForcedActions, ~(fFlags)); } while (0) +#endif + +/** @def VM_FF_IS_SET + * Checks if single a force action flag is set. + * + * @param pVM The cross context VM structure. + * @param fFlag The flag to check. + * @sa VM_FF_IS_ANY_SET + */ +#if !defined(VBOX_STRICT) || !defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define VM_FF_IS_SET(pVM, fFlag) RT_BOOL((pVM)->fGlobalForcedActions & (fFlag)) +#else +# define VM_FF_IS_SET(pVM, fFlag) \ + ([](PVM a_pVM) -> bool \ + { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_32(fFlag##_BIT)); \ + return RT_BOOL(a_pVM->fGlobalForcedActions & (fFlag)); \ + }(pVM)) +#endif + +/** @def VMCPU_FF_IS_SET + * Checks if a single force action flag is set for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlag The flag to check. + * @sa VMCPU_FF_IS_ANY_SET + */ +#if !defined(VBOX_STRICT) || !defined(RT_COMPILER_SUPPORTS_LAMBDA) +# define VMCPU_FF_IS_SET(pVCpu, fFlag) RT_BOOL((pVCpu)->fLocalForcedActions & (fFlag)) +#else +# define VMCPU_FF_IS_SET(pVCpu, fFlag) \ + ([](PCVMCPU a_pVCpu) -> bool \ + { \ + AssertCompile(RT_IS_POWER_OF_TWO(fFlag)); \ + AssertCompile((fFlag) == RT_BIT_64(fFlag##_BIT)); \ + return RT_BOOL(a_pVCpu->fLocalForcedActions & (fFlag)); \ + }(pVCpu)) +#endif + +/** @def VM_FF_IS_ANY_SET + * Checks if one or more force action in the specified set is pending. + * + * @param pVM The cross context VM structure. + * @param fFlags The flags to check for. + * @sa VM_FF_IS_SET + */ +#define VM_FF_IS_ANY_SET(pVM, fFlags) RT_BOOL((pVM)->fGlobalForcedActions & (fFlags)) + +/** @def VMCPU_FF_IS_ANY_SET + * Checks if two or more force action flags in the specified set is set for the given VCPU. + * + * @param pVCpu The cross context virtual CPU structure. + * @param fFlags The flags to check for. + * @sa VMCPU_FF_IS_SET + */ +#define VMCPU_FF_IS_ANY_SET(pVCpu, fFlags) RT_BOOL((pVCpu)->fLocalForcedActions & (fFlags)) + +/** @def VM_FF_TEST_AND_CLEAR + * Checks if one (!) force action in the specified set is pending and clears it atomically + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * @param pVM The cross context VM structure. + * @param fFlag Flag constant to check and clear (_BIT is appended). + */ +#define VM_FF_TEST_AND_CLEAR(pVM, fFlag) (ASMAtomicBitTestAndClear(&(pVM)->fGlobalForcedActions, fFlag##_BIT)) + +/** @def VMCPU_FF_TEST_AND_CLEAR + * Checks if one (!) force action in the specified set is pending and clears it atomically + * + * @returns true if the bit was set. + * @returns false if the bit was clear. + * @param pVCpu The cross context virtual CPU structure. + * @param fFlag Flag constant to check and clear (_BIT is appended). + */ +#define VMCPU_FF_TEST_AND_CLEAR(pVCpu, fFlag) (ASMAtomicBitTestAndClear(&(pVCpu)->fLocalForcedActions, fFlag##_BIT)) + +/** @def VM_FF_IS_PENDING_EXCEPT + * Checks if one or more force action in the specified set is pending while one + * or more other ones are not. + * + * @param pVM The cross context VM structure. + * @param fFlags The flags to check for. + * @param fExcpt The flags that should not be set. + */ +#define VM_FF_IS_PENDING_EXCEPT(pVM, fFlags, fExcpt) \ + ( ((pVM)->fGlobalForcedActions & (fFlags)) && !((pVM)->fGlobalForcedActions & (fExcpt)) ) + +/** @def VM_IS_EMT + * Checks if the current thread is the emulation thread (EMT). + * + * @remark The ring-0 variation will need attention if we expand the ring-0 + * code to let threads other than EMT mess around with the VM. + */ +#ifdef IN_RC +# define VM_IS_EMT(pVM) true +#else +# define VM_IS_EMT(pVM) (VMMGetCpu(pVM) != NULL) +#endif + +/** @def VMCPU_IS_EMT + * Checks if the current thread is the emulation thread (EMT) for the specified + * virtual CPU. + */ +#ifdef IN_RC +# define VMCPU_IS_EMT(pVCpu) true +#else +# define VMCPU_IS_EMT(pVCpu) ((pVCpu) && ((pVCpu) == VMMGetCpu((pVCpu)->CTX_SUFF(pVM)))) +#endif + +/** @def VM_ASSERT_EMT + * Asserts that the current thread IS the emulation thread (EMT). + */ +#ifdef IN_RC +# define VM_ASSERT_EMT(pVM) Assert(VM_IS_EMT(pVM)) +#elif defined(IN_RING0) +# define VM_ASSERT_EMT(pVM) Assert(VM_IS_EMT(pVM)) +#else +# define VM_ASSERT_EMT(pVM) \ + AssertMsg(VM_IS_EMT(pVM), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd\n", RTThreadNativeSelf(), VMR3GetVMCPUNativeThread(pVM))) +#endif + +/** @def VMCPU_ASSERT_EMT + * Asserts that the current thread IS the emulation thread (EMT) of the + * specified virtual CPU. + */ +#ifdef IN_RC +# define VMCPU_ASSERT_EMT(pVCpu) Assert(VMCPU_IS_EMT(pVCpu)) +#elif defined(IN_RING0) +# define VMCPU_ASSERT_EMT(pVCpu) AssertMsg(VMCPU_IS_EMT(pVCpu), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%u\n", \ + RTThreadNativeSelf(), (pVCpu) ? (pVCpu)->hNativeThreadR0 : 0, \ + (pVCpu) ? (pVCpu)->idCpu : 0)) +#else +# define VMCPU_ASSERT_EMT(pVCpu) AssertMsg(VMCPU_IS_EMT(pVCpu), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%#x\n", \ + RTThreadNativeSelf(), (pVCpu)->hNativeThread, (pVCpu)->idCpu)) +#endif + +/** @def VM_ASSERT_EMT_RETURN + * Asserts that the current thread IS the emulation thread (EMT) and returns if it isn't. + */ +#ifdef IN_RC +# define VM_ASSERT_EMT_RETURN(pVM, rc) AssertReturn(VM_IS_EMT(pVM), (rc)) +#elif defined(IN_RING0) +# define VM_ASSERT_EMT_RETURN(pVM, rc) AssertReturn(VM_IS_EMT(pVM), (rc)) +#else +# define VM_ASSERT_EMT_RETURN(pVM, rc) \ + AssertMsgReturn(VM_IS_EMT(pVM), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd\n", RTThreadNativeSelf(), VMR3GetVMCPUNativeThread(pVM)), \ + (rc)) +#endif + +/** @def VMCPU_ASSERT_EMT_RETURN + * Asserts that the current thread IS the emulation thread (EMT) and returns if it isn't. + */ +#ifdef IN_RC +# define VMCPU_ASSERT_EMT_RETURN(pVCpu, rc) AssertReturn(VMCPU_IS_EMT(pVCpu), (rc)) +#elif defined(IN_RING0) +# define VMCPU_ASSERT_EMT_RETURN(pVCpu, rc) AssertReturn(VMCPU_IS_EMT(pVCpu), (rc)) +#else +# define VMCPU_ASSERT_EMT_RETURN(pVCpu, rc) \ + AssertMsgReturn(VMCPU_IS_EMT(pVCpu), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%#x\n", \ + RTThreadNativeSelf(), (pVCpu)->hNativeThread, (pVCpu)->idCpu), \ + (rc)) +#endif + +/** @def VMCPU_ASSERT_EMT_OR_GURU + * Asserts that the current thread IS the emulation thread (EMT) of the + * specified virtual CPU. + */ +#if defined(IN_RC) || defined(IN_RING0) +# define VMCPU_ASSERT_EMT_OR_GURU(pVCpu) Assert( VMCPU_IS_EMT(pVCpu) \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_GURU_MEDITATION \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_GURU_MEDITATION_LS ) +#else +# define VMCPU_ASSERT_EMT_OR_GURU(pVCpu) \ + AssertMsg( VMCPU_IS_EMT(pVCpu) \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_GURU_MEDITATION \ + || pVCpu->CTX_SUFF(pVM)->enmVMState == VMSTATE_GURU_MEDITATION_LS, \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%#x\n", \ + RTThreadNativeSelf(), (pVCpu)->hNativeThread, (pVCpu)->idCpu)) +#endif + +/** @def VMCPU_ASSERT_EMT_OR_NOT_RUNNING + * Asserts that the current thread IS the emulation thread (EMT) of the + * specified virtual CPU or the VM is not running. + */ +#if defined(IN_RC) || defined(IN_RING0) +# define VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu) \ + Assert( VMCPU_IS_EMT(pVCpu) \ + || !VM_IS_RUNNING_FOR_ASSERTIONS_ONLY((pVCpu)->CTX_SUFF(pVM)) ) +#else +# define VMCPU_ASSERT_EMT_OR_NOT_RUNNING(pVCpu) \ + AssertMsg( VMCPU_IS_EMT(pVCpu) \ + || !VM_IS_RUNNING_FOR_ASSERTIONS_ONLY((pVCpu)->CTX_SUFF(pVM)), \ + ("Not emulation thread! Thread=%RTnthrd ThreadEMT=%RTnthrd idCpu=%#x\n", \ + RTThreadNativeSelf(), (pVCpu)->hNativeThread, (pVCpu)->idCpu)) +#endif + +/** @def VMSTATE_IS_RUNNING + * Checks if the given state indicates a running VM. + */ +#define VMSTATE_IS_RUNNING(a_enmVMState) \ + ( (enmVMState) == VMSTATE_RUNNING \ + || (enmVMState) == VMSTATE_RUNNING_LS ) + +/** @def VM_IS_RUNNING_FOR_ASSERTIONS_ONLY + * Checks if the VM is running. + * @note This is only for pure debug assertions. No AssertReturn or similar! + * @sa VMSTATE_IS_RUNNING + */ +#define VM_IS_RUNNING_FOR_ASSERTIONS_ONLY(pVM) \ + ( (pVM)->enmVMState == VMSTATE_RUNNING \ + || (pVM)->enmVMState == VMSTATE_RUNNING_LS ) + +/** @def VM_ASSERT_IS_NOT_RUNNING + * Asserts that the VM is not running. + */ +#if defined(IN_RC) || defined(IN_RING0) +#define VM_ASSERT_IS_NOT_RUNNING(pVM) Assert(!VM_IS_RUNNING_FOR_ASSERTIONS_ONLY(pVM)) +#else +#define VM_ASSERT_IS_NOT_RUNNING(pVM) AssertMsg(!VM_IS_RUNNING_FOR_ASSERTIONS_ONLY(pVM), \ + ("VM is running. enmVMState=%d\n", (pVM)->enmVMState)) +#endif + +/** @def VM_ASSERT_EMT0 + * Asserts that the current thread IS emulation thread \#0 (EMT0). + */ +#ifdef IN_RING3 +# define VM_ASSERT_EMT0(a_pVM) VMCPU_ASSERT_EMT((a_pVM)->apCpusR3[0]) +#else +# define VM_ASSERT_EMT0(a_pVM) VMCPU_ASSERT_EMT(&(a_pVM)->aCpus[0]) +#endif + +/** @def VM_ASSERT_EMT0_RETURN + * Asserts that the current thread IS emulation thread \#0 (EMT0) and returns if + * it isn't. + */ +#ifdef IN_RING3 +# define VM_ASSERT_EMT0_RETURN(pVM, rc) VMCPU_ASSERT_EMT_RETURN((pVM)->apCpusR3[0], (rc)) +#else +# define VM_ASSERT_EMT0_RETURN(pVM, rc) VMCPU_ASSERT_EMT_RETURN(&(pVM)->aCpus[0], (rc)) +#endif + + +/** + * Asserts that the current thread is NOT the emulation thread. + */ +#define VM_ASSERT_OTHER_THREAD(pVM) \ + AssertMsg(!VM_IS_EMT(pVM), ("Not other thread!!\n")) + + +/** @def VM_ASSERT_STATE + * Asserts a certain VM state. + */ +#define VM_ASSERT_STATE(pVM, _enmState) \ + AssertMsg((pVM)->enmVMState == (_enmState), \ + ("state %s, expected %s\n", VMGetStateName((pVM)->enmVMState), VMGetStateName(_enmState))) + +/** @def VM_ASSERT_STATE_RETURN + * Asserts a certain VM state and returns if it doesn't match. + */ +#define VM_ASSERT_STATE_RETURN(pVM, _enmState, rc) \ + AssertMsgReturn((pVM)->enmVMState == (_enmState), \ + ("state %s, expected %s\n", VMGetStateName((pVM)->enmVMState), VMGetStateName(_enmState)), \ + (rc)) + +/** @def VM_IS_VALID_EXT + * Asserts a the VM handle is valid for external access, i.e. not being destroy + * or terminated. */ +#define VM_IS_VALID_EXT(pVM) \ + ( RT_VALID_ALIGNED_PTR(pVM, PAGE_SIZE) \ + && ( (unsigned)(pVM)->enmVMState < (unsigned)VMSTATE_DESTROYING \ + || ( (unsigned)(pVM)->enmVMState == (unsigned)VMSTATE_DESTROYING \ + && VM_IS_EMT(pVM))) ) + +/** @def VM_ASSERT_VALID_EXT_RETURN + * Asserts a the VM handle is valid for external access, i.e. not being + * destroy or terminated. + */ +#define VM_ASSERT_VALID_EXT_RETURN(pVM, rc) \ + AssertMsgReturn(VM_IS_VALID_EXT(pVM), \ + ("pVM=%p state %s\n", (pVM), RT_VALID_ALIGNED_PTR(pVM, PAGE_SIZE) \ + ? VMGetStateName(pVM->enmVMState) : ""), \ + (rc)) + +/** @def VMCPU_ASSERT_VALID_EXT_RETURN + * Asserts a the VMCPU handle is valid for external access, i.e. not being + * destroy or terminated. + */ +#define VMCPU_ASSERT_VALID_EXT_RETURN(pVCpu, rc) \ + AssertMsgReturn( RT_VALID_ALIGNED_PTR(pVCpu, 64) \ + && RT_VALID_ALIGNED_PTR((pVCpu)->CTX_SUFF(pVM), PAGE_SIZE) \ + && (unsigned)(pVCpu)->CTX_SUFF(pVM)->enmVMState < (unsigned)VMSTATE_DESTROYING, \ + ("pVCpu=%p pVM=%p state %s\n", (pVCpu), RT_VALID_ALIGNED_PTR(pVCpu, 64) ? (pVCpu)->CTX_SUFF(pVM) : NULL, \ + RT_VALID_ALIGNED_PTR(pVCpu, 64) && RT_VALID_ALIGNED_PTR((pVCpu)->CTX_SUFF(pVM), PAGE_SIZE) \ + ? VMGetStateName((pVCpu)->pVMR3->enmVMState) : ""), \ + (rc)) + +#endif /* !VBOX_FOR_DTRACE_LIB */ + + +/** + * Helper that HM and NEM uses for safely modifying VM::bMainExecutionEngine. + * + * ONLY HM and NEM MAY USE THIS! + * + * @param a_pVM The cross context VM structure. + * @param a_bValue The new value. + * @internal + */ +#define VM_SET_MAIN_EXECUTION_ENGINE(a_pVM, a_bValue) \ + do { \ + *const_cast(&(a_pVM)->bMainExecutionEngine) = (a_bValue); \ + ASMCompilerBarrier(); /* just to be on the safe side */ \ + } while (0) + +/** + * Checks whether iem-executes-all-mode is used. + * + * @retval true if IEM is used. + * @retval false if not. + * + * @param a_pVM The cross context VM structure. + * @sa VM_IS_HM_OR_NEM_ENABLED, VM_IS_HM_ENABLED, VM_IS_NEM_ENABLED. + * @internal + */ +#define VM_IS_EXEC_ENGINE_IEM(a_pVM) ((a_pVM)->bMainExecutionEngine == VM_EXEC_ENGINE_IEM) + +/** + * Checks whether HM (VT-x/AMD-V) or NEM is being used by this VM. + * + * @retval true if either is used. + * @retval false if software virtualization (raw-mode) is used. + * + * @param a_pVM The cross context VM structure. + * @sa VM_IS_EXEC_ENGINE_IEM, VM_IS_HM_ENABLED, VM_IS_NEM_ENABLED. + * @internal + */ +#define VM_IS_HM_OR_NEM_ENABLED(a_pVM) ((a_pVM)->bMainExecutionEngine != VM_EXEC_ENGINE_IEM) + +/** + * Checks whether HM is being used by this VM. + * + * @retval true if HM (VT-x/AMD-v) is used. + * @retval false if not. + * + * @param a_pVM The cross context VM structure. + * @sa VM_IS_NEM_ENABLED, VM_IS_EXEC_ENGINE_IEM, VM_IS_HM_OR_NEM_ENABLED. + * @internal + */ +#define VM_IS_HM_ENABLED(a_pVM) ((a_pVM)->bMainExecutionEngine == VM_EXEC_ENGINE_HW_VIRT) + +/** + * Checks whether NEM is being used by this VM. + * + * @retval true if a native hypervisor API is used. + * @retval false if not. + * + * @param a_pVM The cross context VM structure. + * @sa VM_IS_HM_ENABLED, VM_IS_EXEC_ENGINE_IEM, VM_IS_HM_OR_NEM_ENABLED. + * @internal + */ +#define VM_IS_NEM_ENABLED(a_pVM) ((a_pVM)->bMainExecutionEngine == VM_EXEC_ENGINE_NATIVE_API) + + +/** + * The cross context VM structure. + * + * It contains all the VM data which have to be available in all contexts. + * Even if it contains all the data the idea is to use APIs not to modify all + * the members all around the place. Therefore we make use of unions to hide + * everything which isn't local to the current source module. This means we'll + * have to pay a little bit of attention when adding new members to structures + * in the unions and make sure to keep the padding sizes up to date. + * + * Run 'kmk run-struct-tests' (from src/VBox/VMM if you like) after updating! + */ +typedef struct VM +{ + /** The state of the VM. + * This field is read only to everyone except the VM and EM. */ + VMSTATE volatile enmVMState; + /** Forced action flags. + * See the VM_FF_* \#defines. Updated atomically. + */ + volatile uint32_t fGlobalForcedActions; + /** Pointer to the array of page descriptors for the VM structure allocation. */ + R3PTRTYPE(PSUPPAGE) paVMPagesR3; + /** Session handle. For use when calling SUPR0 APIs. */ +#ifdef IN_RING0 + PSUPDRVSESSION pSessionUnsafe; +#else + PSUPDRVSESSION pSession; +#endif + /** Pointer to the ring-3 VM structure. */ + PUVM pUVM; + /** Ring-3 Host Context VM Pointer. */ +#ifdef IN_RING0 + R3PTRTYPE(struct VM *) pVMR3Unsafe; +#else + R3PTRTYPE(struct VM *) pVMR3; +#endif + /** Ring-0 Host Context VM pointer for making ring-0 calls. */ + R0PTRTYPE(struct VM *) pVMR0ForCall; + /** Raw-mode Context VM Pointer. */ + uint32_t pVMRC; + /** Padding for new raw-mode (long mode). */ + uint32_t pVMRCPadding; + + /** The GVM VM handle. Only the GVM should modify this field. */ +#ifdef IN_RING0 + uint32_t hSelfUnsafe; +#else + uint32_t hSelf; +#endif + /** Number of virtual CPUs. */ +#ifdef IN_RING0 + uint32_t cCpusUnsafe; +#else + uint32_t cCpus; +#endif + /** CPU excution cap (1-100) */ + uint32_t uCpuExecutionCap; + + /** Size of the VM structure. */ + uint32_t cbSelf; + /** Size of the VMCPU structure. */ + uint32_t cbVCpu; + /** Structure version number (TBD). */ + uint32_t uStructVersion; + + /** @name Various items that are frequently accessed. + * @{ */ + /** The main execution engine, VM_EXEC_ENGINE_XXX. + * This is set early during vmR3InitRing3 by HM or NEM. */ + uint8_t const bMainExecutionEngine; + + /** Hardware VM support is available and enabled. + * Determined very early during init. + * This is placed here for performance reasons. + * @todo obsoleted by bMainExecutionEngine, eliminate. */ + bool fHMEnabled; + /** @} */ + + /** Alignment padding. */ + uint8_t uPadding1[6]; + + /** @name Debugging + * @{ */ + /** Ring-3 Host Context VM Pointer. */ + R3PTRTYPE(RTTRACEBUF) hTraceBufR3; + /** Ring-0 Host Context VM Pointer. */ + R0PTRTYPE(RTTRACEBUF) hTraceBufR0; + /** @} */ + + /** Max EMT hash lookup collisions (in GVMM). */ + uint8_t cMaxEmtHashCollisions; + + /** Padding - the unions must be aligned on a 64 bytes boundary. */ + uint8_t abAlignment3[HC_ARCH_BITS == 64 ? 23 : 51]; + + /** CPUM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_CPUMInternal_h + struct CPUM s; +#endif +#ifdef VBOX_INCLUDED_vmm_cpum_h + /** Read only info exposed about the host and guest CPUs. */ + struct + { + /** Padding for hidden fields. */ + uint8_t abHidden0[64 + 48]; + /** Guest CPU feature information. */ + CPUMFEATURES GuestFeatures; + } const ro; +#endif + /** @todo this is rather bloated because of static MSR range allocation. + * Probably a good idea to move it to a separate R0 allocation... */ + uint8_t padding[8832 + 128*8192 + 0x1d00]; /* multiple of 64 */ + } cpum; + + /** PGM part. + * @note 16384 aligned for zero and mmio page storage. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_PGMInternal_h + struct PGM s; +#endif + uint8_t padding[53888]; /* multiple of 64 */ + } pgm; + + /** VMM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_VMMInternal_h + struct VMM s; +#endif + uint8_t padding[1600]; /* multiple of 64 */ + } vmm; + + /** HM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_HMInternal_h + struct HM s; +#endif + uint8_t padding[5504]; /* multiple of 64 */ + } hm; + + /** TRPM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_TRPMInternal_h + struct TRPM s; +#endif + uint8_t padding[2048]; /* multiple of 64 */ + } trpm; + + /** SELM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_SELMInternal_h + struct SELM s; +#endif + uint8_t padding[768]; /* multiple of 64 */ + } selm; + + /** MM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_MMInternal_h + struct MM s; +#endif + uint8_t padding[192]; /* multiple of 64 */ + } mm; + + /** PDM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_PDMInternal_h + struct PDM s; +#endif + uint8_t padding[22400]; /* multiple of 64 */ + } pdm; + + /** IOM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_IOMInternal_h + struct IOM s; +#endif + uint8_t padding[1152]; /* multiple of 64 */ + } iom; + + /** EM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_EMInternal_h + struct EM s; +#endif + uint8_t padding[256]; /* multiple of 64 */ + } em; + + /** NEM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_NEMInternal_h + struct NEM s; +#endif + uint8_t padding[4608]; /* multiple of 64 */ + } nem; + + /** TM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_TMInternal_h + struct TM s; +#endif + uint8_t padding[10112]; /* multiple of 64 */ + } tm; + + /** DBGF part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_DBGFInternal_h + struct DBGF s; +#endif +#ifdef VBOX_INCLUDED_vmm_dbgf_h + /** Read only info exposed about interrupt breakpoints and selected events. */ + struct + { + /** Bitmap of enabled hardware interrupt breakpoints. */ + uint32_t bmHardIntBreakpoints[256 / 32]; + /** Bitmap of enabled software interrupt breakpoints. */ + uint32_t bmSoftIntBreakpoints[256 / 32]; + /** Bitmap of selected events. + * This includes non-selectable events too for simplicity, we maintain the + * state for some of these, as it may come in handy. */ + uint64_t bmSelectedEvents[(DBGFEVENT_END + 63) / 64]; + /** Enabled hardware interrupt breakpoints. */ + uint32_t cHardIntBreakpoints; + /** Enabled software interrupt breakpoints. */ + uint32_t cSoftIntBreakpoints; + /** The number of selected events. */ + uint32_t cSelectedEvents; + /** The number of enabled hardware breakpoints. */ + uint8_t cEnabledHwBreakpoints; + /** The number of enabled hardware I/O breakpoints. */ + uint8_t cEnabledHwIoBreakpoints; + uint8_t au8Alignment1[2]; /**< Alignment padding. */ + /** The number of enabled INT3 breakpoints. */ + uint32_t volatile cEnabledInt3Breakpoints; + } const ro; +#endif + uint8_t padding[2432]; /* multiple of 64 */ + } dbgf; + + /** SSM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_SSMInternal_h + struct SSM s; +#endif + uint8_t padding[128]; /* multiple of 64 */ + } ssm; + + union + { +#ifdef VMM_INCLUDED_SRC_include_GIMInternal_h + struct GIM s; +#endif + uint8_t padding[448]; /* multiple of 64 */ + } gim; + + union + { +#ifdef VMM_INCLUDED_SRC_include_APICInternal_h + struct APIC s; +#endif + uint8_t padding[128]; /* multiple of 8 */ + } apic; + + /* ---- begin small stuff ---- */ + + /** VM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_VMInternal_h + struct VMINT s; +#endif + uint8_t padding[32]; /* multiple of 8 */ + } vm; + + /** CFGM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_CFGMInternal_h + struct CFGM s; +#endif + uint8_t padding[8]; /* multiple of 8 */ + } cfgm; + + /** IEM part. */ + union + { +#ifdef VMM_INCLUDED_SRC_include_IEMInternal_h + struct IEM s; +#endif + uint8_t padding[16]; /* multiple of 8 */ + } iem; + + /** Statistics for ring-0 only components. */ + struct + { + /** GMMR0 stats. */ + struct + { + /** Chunk TLB hits. */ + uint64_t cChunkTlbHits; + /** Chunk TLB misses. */ + uint64_t cChunkTlbMisses; + } gmm; + uint64_t au64Padding[6]; /* probably more comming here... */ + } R0Stats; + + union + { +#ifdef VMM_INCLUDED_SRC_include_GCMInternal_h + struct GCM s; +#endif + uint8_t padding[32]; /* multiple of 8 */ + } gcm; + + /** Padding for aligning the structure size on a page boundrary. */ + uint8_t abAlignment2[8872 - sizeof(PVMCPUR3) * VMM_MAX_CPU_COUNT]; + + /* ---- end small stuff ---- */ + + /** Array of VMCPU ring-3 pointers. */ + PVMCPUR3 apCpusR3[VMM_MAX_CPU_COUNT]; + + /* This point is aligned on a 16384 boundrary (for arm64 purposes). */ +} VM; +#ifndef VBOX_FOR_DTRACE_LIB +//AssertCompileSizeAlignment(VM, 16384); +#endif + + +#ifdef IN_RC +RT_C_DECLS_BEGIN + +/** The VM structure. + * This is imported from the VMMRCBuiltin module, i.e. it's a one of those magic + * globals which we should avoid using. + */ +extern DECLIMPORT(VM) g_VM; + +/** The VMCPU structure for virtual CPU \#0. + * This is imported from the VMMRCBuiltin module, i.e. it's a one of those magic + * globals which we should avoid using. + */ +extern DECLIMPORT(VMCPU) g_VCpu0; + +RT_C_DECLS_END +#endif + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_vm_h */ + diff --git a/include/VBox/vmm/vm.mac b/include/VBox/vmm/vm.mac new file mode 100644 index 00000000..2aa4b515 --- /dev/null +++ b/include/VBox/vmm/vm.mac @@ -0,0 +1,187 @@ +;; @file +; VM - The Virtual Machine. +; + +; +; Copyright (C) 2006-2022 Oracle and/or its affiliates. +; +; This file is part of VirtualBox base platform packages, as +; available from https://www.virtualbox.org. +; +; This program is free software; you can redistribute it and/or +; modify it under the terms of the GNU General Public License +; as published by the Free Software Foundation, in version 3 of the +; License. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +; General Public License for more details. +; +; You should have received a copy of the GNU General Public License +; along with this program; if not, see . +; +; The contents of this file may alternatively be used under the terms +; of the Common Development and Distribution License Version 1.0 +; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included +; in the VirtualBox distribution, in which case the provisions of the +; CDDL are applicable instead of those of the GPL. +; +; You may elect to license modified versions of this file under the +; terms and conditions of either the GPL or the CDDL or both. +; +; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 +; + +%ifndef ___VBox_vmm_vm_mac +%define ___VBox_vmm_vm_mac + +%include "VBox/vmm/stam.mac" +%include "VBox/param.mac" + +;/** This action forces the VM to service check and pending interrups on the APIC. */ +%define VMCPU_FF_INTERRUPT_APIC (1 << 0) +;/** This action forces the VM to service check and pending interrups on the PIC. */ +%define VMCPU_FF_INTERRUPT_PIC (1 << 1) +;/** This action forces the VM to schedule and run pending timer (TM). */ +%define VMCPU_FF_TIMER (1 << 2) +;/** This action forces the VM to service pending requests from other +; * thread or requests which must be executed in another context. */ +%define VMCPU_FF_REQUEST (1 << 9) + +;; +; This is part of the VMCPU structure. +struc VMCPU + .fLocalForcedActions resd 1 + alignb 8 + .enmState resd 1 + + alignb 64 + .iem resb 32832 + + alignb 64 + .pVMR3 RTR3PTR_RES 1 + .pVCpuR0ForVtg RTR0PTR_RES 1 + .pVMRC resq 1 + .pUVCpu RTR3PTR_RES 1 + .hNativeThread RTR3PTR_RES 1 + .hNativeThreadR0 RTR0PTR_RES 1 + .hThread RTR3PTR_RES 1 + .idCpu resd 1 + + alignb 64 + .hm resb 9984 + alignb 64 + .nem resb 4608 + alignb 64 + .trpm resb 128 + alignb 64 + .tm resb 5760 + alignb 64 + .vmm resb 9536 + alignb 64 + .pdm resb 256 + alignb 64 + .iom resb 512 + alignb 64 + .dbgf resb 512 + alignb 64 + .gim resb 512 + alignb 64 + .apic resb 3840 + + alignb 64 + .fTraceGroups resd 1 + .cEmtHashCollisions resb 1 + .abAdHoc resb 3 + alignb 8 + .aStatAdHoc resb STAMPROFILEADV_size * 8 + + alignb 4096 + .pgm resb 4096+28672 + alignb 4096 + .cpum resb 102400 +%define VMCPU.cpum.GstCtx VMCPU.cpum + alignb 4096 + .em resb 40960 + alignb 16384 +endstruc + +;; +; This is part of the VM structure. +struc VM + .enmVMState resd 1 + .fGlobalForcedActions resd 1 + .paVMPagesR3 RTR3PTR_RES 1 + .pSession RTR0PTR_RES 1 + .pUVM RTR3PTR_RES 1 + .pVMR3 RTR3PTR_RES 1 + .pVMR0ForCall RTR0PTR_RES 1 + .pVMRC resq 1 +%ifdef IN_RING0 + .hSelfUnsafe resd 1 + .cCpusUnsafe resd 1 +%else + .hSelf resd 1 + .cCpus resd 1 +%endif + .uCpuExecutionCap resd 1 + .cbSelf resd 1 + .cbVCpu resd 1 + .uStructVersion resd 1 + .bMainExecutionEngine resb 1 + .fHMEnabled resb 1 + + .uPadding1 resb 6 + + .hTraceBufR3 RTR3PTR_RES 1 + .hTraceBufR0 RTR0PTR_RES 1 + + alignb 64 + .cpum resb 8832 + 128*8192 + alignb 16384 + .pgm resb 53888 + alignb 64 + .vmm resb 1600 + alignb 64 + .hm resb 5504 + alignb 64 + .trpm resb 2048 + alignb 64 + .selm resb 768 + alignb 64 + .mm resb 192 + alignb 64 + .pdm resb 22400 + alignb 64 + .iom resb 1152 + alignb 64 + .em resb 256 + alignb 64 + .nem resb 4608 + alignb 64 + .tm resb 10112 + alignb 64 + .dbgf resb 2432 + alignb 64 + .ssm resb 128 + alignb 64 + .gim resb 448 + alignb 64 + .apic resb 128 + alignb 64 + .vm resb 32 + .cfgm resb 8 + .iem resb 16 + .R0Stats resb 64 + .gcm resb 32 + + times ((($ + VMM_MAX_CPU_COUNT * RTR0PTR_CB + 16383) & ~16383) - ($ + VMM_MAX_CPU_COUNT * RTR0PTR_CB)) resb 1 + .apCpusR3 RTR3PTR_RES VMM_MAX_CPU_COUNT + alignb 16384 + +endstruc + + +%endif + diff --git a/include/VBox/vmm/vmapi.h b/include/VBox/vmm/vmapi.h new file mode 100644 index 00000000..0a1cc09b --- /dev/null +++ b/include/VBox/vmm/vmapi.h @@ -0,0 +1,485 @@ +/** @file + * VM - The Virtual Machine, API. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmapi_h +#define VBOX_INCLUDED_vmm_vmapi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_vm_apis VM All Contexts API + * @ingroup grp_vm + * @{ */ + +/** @name VM_EXEC_ENGINE_XXX - VM::bMainExecutionEngine values. + * @sa EMR3QueryMainExecutionEngine, VM_IS_RAW_MODE_ENABLED, VM_IS_HM_ENABLED, + * VM_IS_HM_OR_NEM_ENABLED, VM_IS_NEM_ENABLED, VM_SET_MAIN_EXECUTION_ENGINE + * @{ */ +/** Has not yet been set. */ +#define VM_EXEC_ENGINE_NOT_SET UINT8_C(0) +/** The interpreter (IEM). */ +#define VM_EXEC_ENGINE_IEM UINT8_C(1) +/** Hardware assisted virtualization thru HM. */ +#define VM_EXEC_ENGINE_HW_VIRT UINT8_C(2) +/** Hardware assisted virtualization thru native API (NEM). */ +#define VM_EXEC_ENGINE_NATIVE_API UINT8_C(3) +/** @} */ + + +/** + * VM error callback function. + * + * @param pUVM The user mode VM handle. Can be NULL if an error + * occurred before successfully creating a VM. + * @param pvUser The user argument. + * @param rc VBox status code. + * @param SRC_POS The source position arguments. See RT_SRC_POS and RT_SRC_POS_ARGS. + * @param pszFormat Error message format string. + * @param args Error message arguments. + */ +typedef DECLCALLBACKTYPE(void, FNVMATERROR,(PUVM pUVM, void *pvUser, int rc, RT_SRC_POS_DECL, + const char *pszFormat, va_list args)); +/** Pointer to a VM error callback. */ +typedef FNVMATERROR *PFNVMATERROR; + +#ifdef IN_RING3 +VMMDECL(int) VMSetError(PVMCC pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMDECL(int) VMSetErrorV(PVMCC pVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(6, 7); +#endif + +/** @def VM_SET_ERROR + * Macro for setting a simple VM error message. + * Don't use '%' in the message! + * + * @returns rc. Meaning you can do: + * @code + * return VM_SET_ERROR(pVM, VERR_OF_YOUR_CHOICE, "descriptive message"); + * @endcode + * @param pVM The cross context VM structure. + * @param rc VBox status code. + * @param pszMessage Error message string. + * @thread Any + */ +#define VM_SET_ERROR(pVM, rc, pszMessage) (VMSetError(pVM, rc, RT_SRC_POS, pszMessage)) + +/** @def VM_SET_ERROR + * Macro for setting a simple VM error message. + * Don't use '%' in the message! + * + * @returns rc. Meaning you can do: + * @code + * return VM_SET_ERROR(pVM, VERR_OF_YOUR_CHOICE, "descriptive message"); + * @endcode + * @param pVM The cross context VM structure. + * @param rc VBox status code. + * @param pszMessage Error message string. + * @thread Any + */ +#define VM_SET_ERROR_U(a_pUVM, a_rc, a_pszMessage) (VMR3SetError(a_pUVM, a_rc, RT_SRC_POS, a_pszMessage)) + + +/** + * VM runtime error callback function. + * + * See VMSetRuntimeError for the detailed description of parameters. + * + * @param pUVM The user mode VM handle. + * @param pvUser The user argument. + * @param fFlags The error flags. + * @param pszErrorId Error ID string. + * @param pszFormat Error message format string. + * @param va Error message arguments. + */ +typedef DECLCALLBACKTYPE(void, FNVMATRUNTIMEERROR,(PUVM pUVM, void *pvUser, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, va_list va)) RT_IPRT_FORMAT_ATTR(5, 0); +/** Pointer to a VM runtime error callback. */ +typedef FNVMATRUNTIMEERROR *PFNVMATRUNTIMEERROR; + +#ifdef IN_RING3 +VMMDECL(int) VMSetRuntimeError(PVMCC pVM, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(4, 5); +VMMDECL(int) VMSetRuntimeErrorV(PVMCC pVM, uint32_t fFlags, const char *pszErrorId, + const char *pszFormat, va_list args) RT_IPRT_FORMAT_ATTR(4, 0); +#endif + +/** @name VMSetRuntimeError fFlags + * When no flags are given the VM will continue running and it's up to the front + * end to take action on the error condition. + * + * @{ */ +/** The error is fatal. + * The VM is not in a state where it can be saved and will enter a state + * where it can no longer execute code. The caller must propagate status + * codes. */ +#define VMSETRTERR_FLAGS_FATAL RT_BIT_32(0) +/** Suspend the VM after, or if possible before, raising the error on EMT. The + * caller must propagate status codes. */ +#define VMSETRTERR_FLAGS_SUSPEND RT_BIT_32(1) +/** Don't wait for the EMT to handle the request. + * Only valid when on a worker thread and there is a high risk of a dead + * lock. Be careful not to flood the user with errors. */ +#define VMSETRTERR_FLAGS_NO_WAIT RT_BIT_32(2) +/** @} */ + +/** + * VM state change callback function. + * + * You are not allowed to call any function which changes the VM state from a + * state callback, except VMR3Destroy(). + * + * @param pUVM The user mode VM handle. + * @param pVMM The VMM ring-3 vtable. + * @param enmState The new state. + * @param enmOldState The old state. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(void, FNVMATSTATE,(PUVM pUVM, PCVMMR3VTABLE pVMM, VMSTATE enmState, VMSTATE enmOldState, void *pvUser)); +/** Pointer to a VM state callback. */ +typedef FNVMATSTATE *PFNVMATSTATE; + +VMMDECL(const char *) VMGetStateName(VMSTATE enmState); + +VMMDECL(uint32_t) VMGetResetCount(PVMCC pVM); +VMMDECL(uint32_t) VMGetSoftResetCount(PVMCC pVM); +VMMDECL(uint32_t) VMGetHardResetCount(PVMCC pVM); + + +/** + * Request type. + */ +typedef enum VMREQTYPE +{ + /** Invalid request. */ + VMREQTYPE_INVALID = 0, + /** VM: Internal. */ + VMREQTYPE_INTERNAL, + /** Maximum request type (exclusive). Used for validation. */ + VMREQTYPE_MAX +} VMREQTYPE; + +/** + * Request state. + */ +typedef enum VMREQSTATE +{ + /** The state is invalid. */ + VMREQSTATE_INVALID = 0, + /** The request have been allocated and is in the process of being filed. */ + VMREQSTATE_ALLOCATED, + /** The request is queued by the requester. */ + VMREQSTATE_QUEUED, + /** The request is begin processed. */ + VMREQSTATE_PROCESSING, + /** The request is completed, the requester is begin notified. */ + VMREQSTATE_COMPLETED, + /** The request packet is in the free chain. (The requester */ + VMREQSTATE_FREE +} VMREQSTATE; + +/** + * Request flags. + */ +typedef enum VMREQFLAGS +{ + /** The request returns a VBox status code. */ + VMREQFLAGS_VBOX_STATUS = 0, + /** The request is a void request and have no status code. */ + VMREQFLAGS_VOID = 1, + /** Return type mask. */ + VMREQFLAGS_RETURN_MASK = 1, + /** Caller does not wait on the packet, EMT will free it. */ + VMREQFLAGS_NO_WAIT = 2, + /** Poke the destination EMT(s) if executing guest code. Use with care. */ + VMREQFLAGS_POKE = 4, + /** Priority request that can safely be processed while doing async + * suspend and power off. */ + VMREQFLAGS_PRIORITY = 8 +} VMREQFLAGS; + + +/** + * VM Request packet. + * + * This is used to request an action in the EMT. Usually the requester is + * another thread, but EMT can also end up being the requester in which case + * it's carried out synchronously. + */ +typedef struct VMREQ +{ + /** Pointer to the next request in the chain. */ + struct VMREQ * volatile pNext; + /** Pointer to ring-3 VM structure which this request belongs to. */ + PUVM pUVM; + /** Request state. */ + volatile VMREQSTATE enmState; + /** VBox status code for the completed request. */ + volatile int32_t iStatus; + /** Requester event sem. + * The request can use this event semaphore to wait/poll for completion + * of the request. + */ + RTSEMEVENT EventSem; + /** Set if the event semaphore is clear. */ + volatile bool fEventSemClear; + /** Flags, VMR3REQ_FLAGS_*. */ + unsigned fFlags; + /** Request type. */ + VMREQTYPE enmType; + /** Request destination. */ + VMCPUID idDstCpu; + /** Request specific data. */ + union VMREQ_U + { + /** VMREQTYPE_INTERNAL. */ + struct + { + /** Pointer to the function to be called. */ + PFNRT pfn; + /** Number of arguments. */ + unsigned cArgs; + /** Array of arguments. */ + uintptr_t aArgs[64]; + } Internal; + } u; +} VMREQ; +/** Pointer to a VM request packet. */ +typedef VMREQ *PVMREQ; + + +#ifndef IN_RC +/** @defgroup grp_vmm_apis_hc VM Host Context API + * @ingroup grp_vm + * @{ */ + +/** @} */ +#endif + + +#ifdef IN_RING3 +/** @defgroup grp_vmm_apis_r3 VM Host Context Ring 3 API + * @ingroup grp_vm + * @{ */ + +/** + * Completion notification codes. + */ +typedef enum VMINITCOMPLETED +{ + /** The ring-3 init is completed. */ + VMINITCOMPLETED_RING3 = 1, + /** The ring-0 init is completed. */ + VMINITCOMPLETED_RING0, + /** The hardware accelerated virtualization init is completed. + * Used to make decisision depending on HM* bits being completely + * initialized. */ + VMINITCOMPLETED_HM +} VMINITCOMPLETED; + + +/** Reason for VM resume. */ +typedef enum VMRESUMEREASON +{ + VMRESUMEREASON_INVALID = 0, + /** User decided to do so. */ + VMRESUMEREASON_USER, + /** VM reconfiguration (like changing DVD). */ + VMRESUMEREASON_RECONFIG, + /** The host resumed. */ + VMRESUMEREASON_HOST_RESUME, + /** Restored state. */ + VMRESUMEREASON_STATE_RESTORED, + /** Snapshot / saved state. */ + VMRESUMEREASON_STATE_SAVED, + /** Teleported to a new box / instance. */ + VMRESUMEREASON_TELEPORTED, + /** Teleportation failed. */ + VMRESUMEREASON_TELEPORT_FAILED, + /** FTM temporarily suspended the VM. */ + VMRESUMEREASON_FTM_SYNC, + /** End of valid reasons. */ + VMRESUMEREASON_END, + /** Blow the type up to 32-bits. */ + VMRESUMEREASON_32BIT_HACK = 0x7fffffff +} VMRESUMEREASON; + +/** Reason for VM suspend. */ +typedef enum VMSUSPENDREASON +{ + VMSUSPENDREASON_INVALID = 0, + /** User decided to do so. */ + VMSUSPENDREASON_USER, + /** VM reconfiguration (like changing DVD). */ + VMSUSPENDREASON_RECONFIG, + /** The VM is suspending itself. */ + VMSUSPENDREASON_VM, + /** The Vm is suspending because of a runtime error. */ + VMSUSPENDREASON_RUNTIME_ERROR, + /** The host was suspended. */ + VMSUSPENDREASON_HOST_SUSPEND, + /** The host is running low on battery power. */ + VMSUSPENDREASON_HOST_BATTERY_LOW, + /** FTM is temporarily suspending the VM. */ + VMSUSPENDREASON_FTM_SYNC, + /** End of valid reasons. */ + VMSUSPENDREASON_END, + /** Blow the type up to 32-bits. */ + VMSUSPENDREASON_32BIT_HACK = 0x7fffffff +} VMSUSPENDREASON; + + +/** + * Progress callback. + * + * This will report the completion percentage of an operation. + * + * @returns VINF_SUCCESS. + * @returns Error code to cancel the operation with. + * @param pUVM The user mode VM handle. + * @param uPercent Completion percentage (0-100). + * @param pvUser User specified argument. + */ +typedef DECLCALLBACKTYPE(int, FNVMPROGRESS,(PUVM pUVM, unsigned uPercent, void *pvUser)); +/** Pointer to a FNVMPROGRESS function. */ +typedef FNVMPROGRESS *PFNVMPROGRESS; + + +VMMR3DECL(int) VMR3Create(uint32_t cCpus, PCVMM2USERMETHODS pVm2UserCbs, + PFNVMATERROR pfnVMAtError, void *pvUserVM, + PFNCFGMCONSTRUCTOR pfnCFGMConstructor, void *pvUserCFGM, + PVM *ppVM, PUVM *ppUVM); +VMMR3DECL(int) VMR3PowerOn(PUVM pUVM); +VMMR3DECL(int) VMR3Suspend(PUVM pUVM, VMSUSPENDREASON enmReason); +VMMR3DECL(VMSUSPENDREASON) VMR3GetSuspendReason(PUVM); +VMMR3DECL(int) VMR3Resume(PUVM pUVM, VMRESUMEREASON enmReason); +VMMR3DECL(VMRESUMEREASON) VMR3GetResumeReason(PUVM); +VMMR3DECL(int) VMR3Reset(PUVM pUVM); +VMMR3_INT_DECL(VBOXSTRICTRC) VMR3ResetFF(PVM pVM); +VMMR3_INT_DECL(VBOXSTRICTRC) VMR3ResetTripleFault(PVM pVM); +VMMR3DECL(int) VMR3Save(PUVM pUVM, const char *pszFilename, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, bool fContinueAfterwards, PFNVMPROGRESS pfnProgress, void *pvUser, bool *pfSuspended); +VMMR3DECL(int) VMR3Teleport(PUVM pUVM, uint32_t cMsDowntime, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, PFNVMPROGRESS pfnProgress, void *pvProgressUser, bool *pfSuspended); +VMMR3DECL(int) VMR3LoadFromFile(PUVM pUVM, const char *pszFilename, PFNVMPROGRESS pfnProgress, void *pvUser); +VMMR3DECL(int) VMR3LoadFromStream(PUVM pUVM, PCSSMSTRMOPS pStreamOps, void *pvStreamOpsUser, + PFNVMPROGRESS pfnProgress, void *pvProgressUser, bool fTeleporting); + +VMMR3DECL(int) VMR3PowerOff(PUVM pUVM); +VMMR3DECL(int) VMR3Destroy(PUVM pUVM); +VMMR3_INT_DECL(void) VMR3Relocate(PVM pVM, RTGCINTPTR offDelta); + +VMMR3DECL(PVM) VMR3GetVM(PUVM pUVM); +VMMR3DECL(PUVM) VMR3GetUVM(PVM pVM); +VMMR3DECL(uint32_t) VMR3RetainUVM(PUVM pUVM); +VMMR3DECL(uint32_t) VMR3ReleaseUVM(PUVM pUVM); +VMMR3DECL(const char *) VMR3GetName(PUVM pUVM); +VMMR3DECL(PRTUUID) VMR3GetUuid(PUVM pUVM, PRTUUID pUuid); +VMMR3DECL(VMSTATE) VMR3GetState(PVM pVM); +VMMR3DECL(VMSTATE) VMR3GetStateU(PUVM pUVM); +VMMR3DECL(const char *) VMR3GetStateName(VMSTATE enmState); +VMMR3DECL(int) VMR3AtStateRegister(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser); +VMMR3DECL(int) VMR3AtStateDeregister(PUVM pUVM, PFNVMATSTATE pfnAtState, void *pvUser); +VMMR3_INT_DECL(bool) VMR3SetGuruMeditation(PVM pVM); +VMMR3_INT_DECL(bool) VMR3TeleportedAndNotFullyResumedYet(PVM pVM); +VMMR3DECL(int) VMR3AtErrorRegister(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser); +VMMR3DECL(int) VMR3AtErrorDeregister(PUVM pUVM, PFNVMATERROR pfnAtError, void *pvUser); +VMMR3DECL(int) VMR3SetError(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, ...) RT_IPRT_FORMAT_ATTR(6, 7); +VMMR3DECL(int) VMR3SetErrorV(PUVM pUVM, int rc, RT_SRC_POS_DECL, const char *pszFormat, va_list va) RT_IPRT_FORMAT_ATTR(6, 0); +VMMR3_INT_DECL(void) VMR3SetErrorWorker(PVM pVM); +VMMR3_INT_DECL(uint32_t) VMR3GetErrorCount(PUVM pUVM); +VMMR3DECL(int) VMR3AtRuntimeErrorRegister(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser); +VMMR3DECL(int) VMR3AtRuntimeErrorDeregister(PUVM pUVM, PFNVMATRUNTIMEERROR pfnAtRuntimeError, void *pvUser); +VMMR3_INT_DECL(int) VMR3SetRuntimeErrorWorker(PVM pVM); +VMMR3_INT_DECL(uint32_t) VMR3GetRuntimeErrorCount(PUVM pUVM); + +VMMR3DECL(int) VMR3ReqCallU(PUVM pUVM, VMCPUID idDstCpu, PVMREQ *ppReq, RTMSINTERVAL cMillies, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallVU(PUVM pUVM, VMCPUID idDstCpu, PVMREQ *ppReq, RTMSINTERVAL cMillies, uint32_t fFlags, PFNRT pfnFunction, unsigned cArgs, va_list Args); +VMMR3_INT_DECL(int) VMR3ReqCallWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallNoWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallNoWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3_INT_DECL(int) VMR3ReqCallVoidWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallVoidWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqCallVoidNoWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqPriorityCallWait(PVM pVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqPriorityCallWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqPriorityCallVoidWaitU(PUVM pUVM, VMCPUID idDstCpu, PFNRT pfnFunction, unsigned cArgs, ...); +VMMR3DECL(int) VMR3ReqAlloc(PUVM pUVM, PVMREQ *ppReq, VMREQTYPE enmType, VMCPUID idDstCpu); +VMMR3DECL(int) VMR3ReqFree(PVMREQ pReq); +VMMR3DECL(int) VMR3ReqQueue(PVMREQ pReq, RTMSINTERVAL cMillies); +VMMR3DECL(int) VMR3ReqWait(PVMREQ pReq, RTMSINTERVAL cMillies); +VMMR3_INT_DECL(int) VMR3ReqProcessU(PUVM pUVM, VMCPUID idDstCpu, bool fPriorityOnly); + +/** @name Flags for VMR3NotifyCpuFFU and VMR3NotifyGlobalFFU. + * @{ */ +/** Whether we've done REM or not. */ +#define VMNOTIFYFF_FLAGS_DONE_REM RT_BIT_32(0) +/** Whether we should poke the CPU if it's executing guest code. */ +#define VMNOTIFYFF_FLAGS_POKE RT_BIT_32(1) +/** @} */ +VMMR3_INT_DECL(void) VMR3NotifyGlobalFFU(PUVM pUVM, uint32_t fFlags); +VMMR3_INT_DECL(void) VMR3NotifyCpuFFU(PUVMCPU pUVMCpu, uint32_t fFlags); +VMMR3DECL(int) VMR3NotifyCpuDeviceReady(PVM pVM, VMCPUID idCpu); +VMMR3_INT_DECL(int) VMR3WaitHalted(PVM pVM, PVMCPU pVCpu, bool fIgnoreInterrupts); +VMMR3_INT_DECL(int) VMR3WaitU(PUVMCPU pUVMCpu); +VMMR3DECL(int) VMR3WaitForDeviceReady(PVM pVM, VMCPUID idCpu); +VMMR3_INT_DECL(int) VMR3AsyncPdmNotificationWaitU(PUVMCPU pUVCpu); +VMMR3_INT_DECL(void) VMR3AsyncPdmNotificationWakeupU(PUVM pUVM); +VMMR3_INT_DECL(RTCPUID) VMR3GetVMCPUId(PVM pVM); +VMMR3_INT_DECL(bool) VMR3IsLongModeAllowed(PVM pVM); +VMMR3_INT_DECL(RTTHREAD) VMR3GetThreadHandle(PUVMCPU pUVCpu); +VMMR3DECL(RTTHREAD) VMR3GetVMCPUThread(PUVM pUVM); +VMMR3DECL(RTNATIVETHREAD) VMR3GetVMCPUNativeThread(PVM pVM); +VMMR3DECL(RTNATIVETHREAD) VMR3GetVMCPUNativeThreadU(PUVM pUVM); +VMMR3DECL(int) VMR3GetCpuCoreAndPackageIdFromCpuId(PUVM pUVM, VMCPUID idCpu, uint32_t *pidCpuCore, uint32_t *pidCpuPackage); +VMMR3_INT_DECL(uint32_t) VMR3GetActiveEmts(PUVM pUVM); +VMMR3DECL(int) VMR3HotUnplugCpu(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) VMR3HotPlugCpu(PUVM pUVM, VMCPUID idCpu); +VMMR3DECL(int) VMR3SetCpuExecutionCap(PUVM pUVM, uint32_t uCpuExecutionCap); +VMMR3DECL(int) VMR3SetPowerOffInsteadOfReset(PUVM pUVM, bool fPowerOffInsteadOfReset); +/** @} */ +#endif /* IN_RING3 */ + +RT_C_DECLS_END + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_vmapi_h */ + diff --git a/include/VBox/vmm/vmcc.h b/include/VBox/vmm/vmcc.h new file mode 100644 index 00000000..3a143fae --- /dev/null +++ b/include/VBox/vmm/vmcc.h @@ -0,0 +1,148 @@ +/** @file + * VM - The Virtual Machine, GVM/GVMCPU or VM/VMCPU depending on context. + */ + +/* + * Copyright (C) 2019-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmcc_h +#define VBOX_INCLUDED_vmm_vmcc_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + + +#include +#ifdef IN_RING0 +# include +#else +# include +#endif + +/** @typedef VMCC + * Context specific VM derived structure. + * This is plain VM in ring-3 and GVM (inherits from VM) in ring-0. */ +/** @typedef VMCPUCC + * Context specific VMCPU derived structure. + * This is plain VM in ring-3 and GVMCPU (inherits from VMCPU) in ring-0. */ +#ifdef IN_RING0 +typedef GVM VMCC; +typedef GVMCPU VMCPUCC; +#else +typedef VM VMCC; +typedef VMCPU VMCPUCC; +#endif + +/** @def VMCC_GET_CPU_0 + * Gets the context specfic pointer to virtual CPU \#0. + * @param a_pVM The context specfic VM structure. + */ +#ifdef IN_RING0 +# define VMCC_GET_CPU_0(a_pVM) (&(a_pVM)->aCpus[0]) +#else +# define VMCC_GET_CPU_0(a_pVM) ((a_pVM)->CTX_SUFF(apCpus)[0]) +#endif + +/** @def VMCC_GET_CPU + * Gets the context specfic pointer to a virtual CPU by index (ID). + * @param a_pVM The context specfic VM structure. + * @param a_idCpu The CPU number to get (caller ensures validity). + */ +#ifdef IN_RING0 +# define VMCC_GET_CPU(a_pVM, a_idCpu) (&(a_pVM)->aCpus[(a_idCpu)]) +#else +# define VMCC_GET_CPU(a_pVM, a_idCpu) ((a_pVM)->CTX_SUFF(apCpus)[(a_idCpu)]) +#endif + +/** @def VMCC_FOR_EACH_VMCPU + * For enumerating VCpus in ascending order, avoiding unnecessary apCpusR0 + * access in ring-0, caching the CPU count and not checking for CPU \#0. + * + * Defines local variables @c idCpu, @c pVCpu and @c cCpus. + * + * @param a_pVM The VM handle. + * + * @note Close loop with VMCC_FOR_EACH_VMCPU_END. + */ +#define VMCC_FOR_EACH_VMCPU(a_pVM) \ + do { \ + VMCPUID idCpu = 0; \ + VMCPUID const cCpus = (a_pVM)->cCpus; \ + PVMCPUCC pVCpu = VMCC_GET_CPU_0(a_pVM); \ + for (;;) \ + { + +/** @def VMCC_FOR_EACH_VMCPU_END + * Ends a VMCC_FOR_EACH_VMCPU loop. + * @param a_pVM The VM handle. + */ +#define VMCC_FOR_EACH_VMCPU_END(a_pVM) \ + /* advance */ \ + if (++idCpu >= cCpus) \ + break; \ + pVCpu = VMCC_GET_CPU(pVM, idCpu); \ + } \ + } while (0) + +/** + * Execute the given statement for each virtual CPU in an environment with + * @c pVCpu and @c idCpu variables. + * + * @param a_pVM The VM handle. + * @param a_Stmt The statement to execute. + */ +#define VMCC_FOR_EACH_VMCPU_STMT(a_pVM, a_Stmt) VMCC_FOR_EACH_VMCPU(pVM) { a_Stmt; } VMCC_FOR_EACH_VMCPU_END(pVM) + +/** @def VMCC_GET_VMR0_FOR_CALL(pVM) */ +#if defined(IN_RING3) +# define VMCC_GET_VMR0_FOR_CALL(a_pVM) ((a_pVM)->pVMR0ForCall) +#elif defined(IN_RING3) +# define VMCC_GET_VMR0_FOR_CALL(a_pVM) ((a_pVM)->pVMR0) +#else +# define VMCC_GET_VMR0_FOR_CALL(a_pVM) ((a_pVM)->ring3_only_macro) +#endif + + +/** + * Used to pick ring-0 or ring-3 VM component data. + * + * @code{.cpp} + * pVM->VMCC_CTX(pdm).s.pfnWorker + * @endcode + */ +#ifdef IN_RING0 +# define VMCC_CTX(a_Name) a_Name ## r0 +#else +# define VMCC_CTX(a_Name) a_Name +#endif + +#endif /* !VBOX_INCLUDED_vmm_vmcc_h */ + diff --git a/include/VBox/vmm/vmcpuset.h b/include/VBox/vmm/vmcpuset.h new file mode 100644 index 00000000..496721de --- /dev/null +++ b/include/VBox/vmm/vmcpuset.h @@ -0,0 +1,124 @@ +/** @file + * VirtualBox - VMCPUSET Operation. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmcpuset_h +#define VBOX_INCLUDED_vmm_vmcpuset_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +/** @defgroup grp_vmcpuset VMCPUSET Operations + * @ingroup grp_types_both + * @sa VMCPUSET + * @{ + */ + +/** Tests if a valid CPU ID is present in the set. */ +#define VMCPUSET_IS_PRESENT(pSet, idCpu) ASMBitTest( &(pSet)->au32Bitmap[0], (idCpu)) +/** Adds a CPU to the set. */ +#define VMCPUSET_ADD(pSet, idCpu) ASMBitSet( &(pSet)->au32Bitmap[0], (idCpu)) +/** Deletes a CPU from the set. */ +#define VMCPUSET_DEL(pSet, idCpu) ASMBitClear(&(pSet)->au32Bitmap[0], (idCpu)) +/** Adds a CPU to the set, atomically. */ +#define VMCPUSET_ATOMIC_ADD(pSet, idCpu) ASMAtomicBitSet( &(pSet)->au32Bitmap[0], (idCpu)) +/** Deletes a CPU from the set, atomically. */ +#define VMCPUSET_ATOMIC_DEL(pSet, idCpu) ASMAtomicBitClear(&(pSet)->au32Bitmap[0], (idCpu)) +/** Empties the set. */ +#define VMCPUSET_EMPTY(pSet) memset(&(pSet)->au32Bitmap[0], '\0', sizeof((pSet)->au32Bitmap)) +/** Fills the set. */ +#define VMCPUSET_FILL(pSet) memset(&(pSet)->au32Bitmap[0], 0xff, sizeof((pSet)->au32Bitmap)) +/** Checks if two sets are equal to one another. */ +#define VMCPUSET_IS_EQUAL(pSet1, pSet2) (memcmp(&(pSet1)->au32Bitmap[0], &(pSet2)->au32Bitmap[0], sizeof((pSet1)->au32Bitmap)) == 0) +/** Checks if the set is empty. */ +#define VMCPUSET_IS_EMPTY(a_pSet) ( (a_pSet)->au32Bitmap[0] == 0 \ + && (a_pSet)->au32Bitmap[1] == 0 \ + && (a_pSet)->au32Bitmap[2] == 0 \ + && (a_pSet)->au32Bitmap[3] == 0 \ + && (a_pSet)->au32Bitmap[4] == 0 \ + && (a_pSet)->au32Bitmap[5] == 0 \ + && (a_pSet)->au32Bitmap[6] == 0 \ + && (a_pSet)->au32Bitmap[7] == 0 \ + ) +/** Finds the first CPU present in the SET. + * @returns CPU index if found, NIL_VMCPUID if not. */ +#define VMCPUSET_FIND_FIRST_PRESENT(a_pSet) VMCpuSetFindFirstPresentInternal(a_pSet) + +/** Implements VMCPUSET_FIND_FIRST_PRESENT. + * + * @returns CPU index of the first CPU present in the set, NIL_VMCPUID if none + * are present. + * @param pSet The set to scan. + */ +DECLINLINE(int32_t) VMCpuSetFindFirstPresentInternal(PCVMCPUSET pSet) +{ + int i = ASMBitFirstSet(&pSet->au32Bitmap[0], RT_ELEMENTS(pSet->au32Bitmap) * 32); + return i >= 0 ? (VMCPUID)i : NIL_VMCPUID; +} + +/** Finds the first CPU present in the SET. + * @returns CPU index if found, NIL_VMCPUID if not. */ +#define VMCPUSET_FIND_LAST_PRESENT(a_pSet) VMCpuSetFindLastPresentInternal(a_pSet) + +/** Implements VMCPUSET_FIND_LAST_PRESENT. + * + * @returns CPU index of the last CPU present in the set, NIL_VMCPUID if none + * are present. + * @param pSet The set to scan. + */ +DECLINLINE(int32_t) VMCpuSetFindLastPresentInternal(PCVMCPUSET pSet) +{ + uint32_t i = RT_ELEMENTS(pSet->au32Bitmap); + while (i-- > 0) + { + uint32_t u = pSet->au32Bitmap[i]; + if (u) + { + u = ASMBitLastSetU32(u); + u--; + u |= i << 5; + return u; + } + } + return NIL_VMCPUID; +} + +/** @} */ + +#endif /* !VBOX_INCLUDED_vmm_vmcpuset_h */ + diff --git a/include/VBox/vmm/vmm.h b/include/VBox/vmm/vmm.h new file mode 100644 index 00000000..85df7e4c --- /dev/null +++ b/include/VBox/vmm/vmm.h @@ -0,0 +1,639 @@ +/** @file + * VMM - The Virtual Machine Monitor. + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmm_h +#define VBOX_INCLUDED_vmm_vmm_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_vmm The Virtual Machine Monitor + * @{ + */ + +/** @defgroup grp_vmm_api The Virtual Machine Monitor API + * @{ + */ + + +/** + * Ring-0 assertion notification callback. + * + * @returns VBox status code. + * @param pVCpu The cross context virtual CPU structure. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(int, FNVMMR0ASSERTIONNOTIFICATION,(PVMCPUCC pVCpu, void *pvUser)); +/** Pointer to a FNVMMR0ASSERTIONNOTIFICATION(). */ +typedef FNVMMR0ASSERTIONNOTIFICATION *PFNVMMR0ASSERTIONNOTIFICATION; + +/** + * Rendezvous callback. + * + * @returns VBox strict status code - EM scheduling. Do not return + * informational status code other than the ones used by EM for + * scheduling. + * + * @param pVM The cross context VM structure. + * @param pVCpu The cross context virtual CPU structure of the calling EMT. + * @param pvUser The user argument. + */ +typedef DECLCALLBACKTYPE(VBOXSTRICTRC, FNVMMEMTRENDEZVOUS,(PVM pVM, PVMCPU pVCpu, void *pvUser)); +/** Pointer to a rendezvous callback function. */ +typedef FNVMMEMTRENDEZVOUS *PFNVMMEMTRENDEZVOUS; + +/** + * Method table that the VMM uses to call back the user of the VMM. + */ +typedef struct VMM2USERMETHODS +{ + /** Magic value (VMM2USERMETHODS_MAGIC). */ + uint32_t u32Magic; + /** Structure version (VMM2USERMETHODS_VERSION). */ + uint32_t u32Version; + + /** + * Save the VM state. + * + * @returns VBox status code. + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * + * @remarks This member shall be set to NULL if the operation is not + * supported. + */ + DECLR3CALLBACKMEMBER(int, pfnSaveState,(PCVMM2USERMETHODS pThis, PUVM pUVM)); + /** @todo Move pfnVMAtError and pfnCFGMConstructor here? */ + + /** + * EMT initialization notification callback. + * + * This is intended for doing per-thread initialization for EMTs (like COM + * init). + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * @param pUVCpu The user mode virtual CPU handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyEmtInit,(PCVMM2USERMETHODS pThis, PUVM pUVM, PUVMCPU pUVCpu)); + + /** + * EMT termination notification callback. + * + * This is intended for doing per-thread cleanups for EMTs (like COM). + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * @param pUVCpu The user mode virtual CPU handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyEmtTerm,(PCVMM2USERMETHODS pThis, PUVM pUVM, PUVMCPU pUVCpu)); + + /** + * PDM thread initialization notification callback. + * + * This is intended for doing per-thread initialization (like COM init). + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyPdmtInit,(PCVMM2USERMETHODS pThis, PUVM pUVM)); + + /** + * EMT termination notification callback. + * + * This is intended for doing per-thread cleanups for EMTs (like COM). + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyPdmtTerm,(PCVMM2USERMETHODS pThis, PUVM pUVM)); + + /** + * Notification callback that that a VM reset will be turned into a power off. + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void, pfnNotifyResetTurnedIntoPowerOff,(PCVMM2USERMETHODS pThis, PUVM pUVM)); + + /** + * Generic object query by UUID. + * + * @returns pointer to queried the object on success, NULL if not found. + * + * @param pThis Pointer to the callback method table. + * @param pUVM The user mode VM handle. + * @param pUuid The UUID of what's being queried. The UUIDs and the + * usage conventions are defined by the user. + * + * @remarks This is optional and shall be set to NULL if not wanted. + */ + DECLR3CALLBACKMEMBER(void *, pfnQueryGenericObject,(PCVMM2USERMETHODS pThis, PUVM pUVM, PCRTUUID pUuid)); + + /** Magic value (VMM2USERMETHODS_MAGIC) marking the end of the structure. */ + uint32_t u32EndMagic; +} VMM2USERMETHODS; + +/** Magic value of the VMM2USERMETHODS (Franz Kafka). */ +#define VMM2USERMETHODS_MAGIC UINT32_C(0x18830703) +/** The VMM2USERMETHODS structure version. */ +#define VMM2USERMETHODS_VERSION UINT32_C(0x00030000) + + +/** + * Checks whether we've armed the ring-0 long jump machinery. + * + * @returns @c true / @c false + * @param a_pVCpu The caller's cross context virtual CPU structure. + * @thread EMT + * @sa VMMR0IsLongJumpArmed + */ +#ifdef IN_RING0 +# define VMMIsLongJumpArmed(a_pVCpu) VMMR0IsLongJumpArmed(a_pVCpu) +#else +# define VMMIsLongJumpArmed(a_pVCpu) (false) +#endif + + +VMMDECL(VMCPUID) VMMGetCpuId(PVMCC pVM); +VMMDECL(PVMCPUCC) VMMGetCpu(PVMCC pVM); +VMMDECL(PVMCPUCC) VMMGetCpu0(PVMCC pVM); +VMMDECL(PVMCPUCC) VMMGetCpuById(PVMCC pVM, VMCPUID idCpu); +VMMR3DECL(PVMCPUCC) VMMR3GetCpuByIdU(PUVM pVM, VMCPUID idCpu); +VMM_INT_DECL(uint32_t) VMMGetSvnRev(void); +VMM_INT_DECL(void) VMMTrashVolatileXMMRegs(void); + + +/** @defgroup grp_vmm_api_r0 The VMM Host Context Ring 0 API + * @{ + */ + +/** + * The VMMR0Entry() codes. + */ +typedef enum VMMR0OPERATION +{ + /** Run guest code using the available hardware acceleration technology. */ + VMMR0_DO_HM_RUN = SUP_VMMR0_DO_HM_RUN, + /** Official NOP that we use for profiling. */ + VMMR0_DO_NEM_RUN = SUP_VMMR0_DO_NEM_RUN, + /** Official NOP that we use for profiling. */ + VMMR0_DO_NOP = SUP_VMMR0_DO_NOP, + /** Official slow iocl NOP that we use for profiling. */ + VMMR0_DO_SLOW_NOP, + + /** Ask the GVMM to create a new VM. */ + VMMR0_DO_GVMM_CREATE_VM = 32, + /** Ask the GVMM to destroy the VM. */ + VMMR0_DO_GVMM_DESTROY_VM, + /** Call GVMMR0RegisterVCpu(). */ + VMMR0_DO_GVMM_REGISTER_VMCPU, + /** Call GVMMR0DeregisterVCpu(). */ + VMMR0_DO_GVMM_DEREGISTER_VMCPU, + /** Call GVMMR0RegisterWorkerThread(). */ + VMMR0_DO_GVMM_REGISTER_WORKER_THREAD, + /** Call GVMMR0DeregisterWorkerThread(). */ + VMMR0_DO_GVMM_DEREGISTER_WORKER_THREAD, + /** Call GVMMR0SchedHalt(). */ + VMMR0_DO_GVMM_SCHED_HALT, + /** Call GVMMR0SchedWakeUp(). */ + VMMR0_DO_GVMM_SCHED_WAKE_UP, + /** Call GVMMR0SchedPoke(). */ + VMMR0_DO_GVMM_SCHED_POKE, + /** Call GVMMR0SchedWakeUpAndPokeCpus(). */ + VMMR0_DO_GVMM_SCHED_WAKE_UP_AND_POKE_CPUS, + /** Call GVMMR0SchedPoll(). */ + VMMR0_DO_GVMM_SCHED_POLL, + /** Call GVMMR0QueryStatistics(). */ + VMMR0_DO_GVMM_QUERY_STATISTICS, + /** Call GVMMR0ResetStatistics(). */ + VMMR0_DO_GVMM_RESET_STATISTICS, + + /** Call VMMR0 Per VM Init. */ + VMMR0_DO_VMMR0_INIT = 64, + /** Call VMMR0 Per VM EMT Init */ + VMMR0_DO_VMMR0_INIT_EMT, + /** Call VMMR0 Per VM Termination. */ + VMMR0_DO_VMMR0_TERM, + /** Copy logger settings from userland, VMMR0UpdateLoggersReq(). */ + VMMR0_DO_VMMR0_UPDATE_LOGGERS, + /** Used by the log flusher, VMMR0LogFlusher. */ + VMMR0_DO_VMMR0_LOG_FLUSHER, + /** Used by EMTs to wait for the log flusher to finish, VMMR0LogWaitFlushed. */ + VMMR0_DO_VMMR0_LOG_WAIT_FLUSHED, + + /** Setup hardware-assisted VM session. */ + VMMR0_DO_HM_SETUP_VM = 128, + /** Attempt to enable or disable hardware-assisted mode. */ + VMMR0_DO_HM_ENABLE, + + /** Call PGMR0PhysAllocateHandyPages(). */ + VMMR0_DO_PGM_ALLOCATE_HANDY_PAGES = 192, + /** Call PGMR0PhysFlushHandyPages(). */ + VMMR0_DO_PGM_FLUSH_HANDY_PAGES, + /** Call PGMR0AllocateLargePage(). */ + VMMR0_DO_PGM_ALLOCATE_LARGE_PAGE, + /** Call PGMR0PhysSetupIommu(). */ + VMMR0_DO_PGM_PHYS_SETUP_IOMMU, + /** Call PGMR0PoolGrow(). */ + VMMR0_DO_PGM_POOL_GROW, + /** Call PGMR0PhysHandlerInitReqHandler(). */ + VMMR0_DO_PGM_PHYS_HANDLER_INIT, + + /** Call GMMR0InitialReservation(). */ + VMMR0_DO_GMM_INITIAL_RESERVATION = 256, + /** Call GMMR0UpdateReservation(). */ + VMMR0_DO_GMM_UPDATE_RESERVATION, + /** Call GMMR0AllocatePages(). */ + VMMR0_DO_GMM_ALLOCATE_PAGES, + /** Call GMMR0FreePages(). */ + VMMR0_DO_GMM_FREE_PAGES, + /** Call GMMR0FreeLargePage(). */ + VMMR0_DO_GMM_FREE_LARGE_PAGE, + /** Call GMMR0QueryHypervisorMemoryStatsReq(). */ + VMMR0_DO_GMM_QUERY_HYPERVISOR_MEM_STATS, + /** Call GMMR0QueryMemoryStatsReq(). */ + VMMR0_DO_GMM_QUERY_MEM_STATS, + /** Call GMMR0BalloonedPages(). */ + VMMR0_DO_GMM_BALLOONED_PAGES, + /** Call GMMR0MapUnmapChunk(). */ + VMMR0_DO_GMM_MAP_UNMAP_CHUNK, + /** Call GMMR0RegisterSharedModule. */ + VMMR0_DO_GMM_REGISTER_SHARED_MODULE, + /** Call GMMR0UnregisterSharedModule. */ + VMMR0_DO_GMM_UNREGISTER_SHARED_MODULE, + /** Call GMMR0ResetSharedModules. */ + VMMR0_DO_GMM_RESET_SHARED_MODULES, + /** Call GMMR0CheckSharedModules. */ + VMMR0_DO_GMM_CHECK_SHARED_MODULES, + /** Call GMMR0FindDuplicatePage. */ + VMMR0_DO_GMM_FIND_DUPLICATE_PAGE, + /** Call GMMR0QueryStatistics(). */ + VMMR0_DO_GMM_QUERY_STATISTICS, + /** Call GMMR0ResetStatistics(). */ + VMMR0_DO_GMM_RESET_STATISTICS, + + /** Call PDMR0DriverCallReqHandler. */ + VMMR0_DO_PDM_DRIVER_CALL_REQ_HANDLER = 320, + /** Call PDMR0DeviceCreateReqHandler. */ + VMMR0_DO_PDM_DEVICE_CREATE, + /** Call PDMR0DeviceGenCallReqHandler. */ + VMMR0_DO_PDM_DEVICE_GEN_CALL, + /** Old style device compat: Set ring-0 critical section. */ + VMMR0_DO_PDM_DEVICE_COMPAT_SET_CRITSECT, + /** Call PDMR0QueueCreateReqHandler. */ + VMMR0_DO_PDM_QUEUE_CREATE, + + /** Set a GVMM or GMM configuration value. */ + VMMR0_DO_GCFGM_SET_VALUE = 400, + /** Query a GVMM or GMM configuration value. */ + VMMR0_DO_GCFGM_QUERY_VALUE, + + /** The start of the R0 service operations. */ + VMMR0_DO_SRV_START = 448, + /** Call IntNetR0Open(). */ + VMMR0_DO_INTNET_OPEN, + /** Call IntNetR0IfClose(). */ + VMMR0_DO_INTNET_IF_CLOSE, + /** Call IntNetR0IfGetBufferPtrs(). */ + VMMR0_DO_INTNET_IF_GET_BUFFER_PTRS, + /** Call IntNetR0IfSetPromiscuousMode(). */ + VMMR0_DO_INTNET_IF_SET_PROMISCUOUS_MODE, + /** Call IntNetR0IfSetMacAddress(). */ + VMMR0_DO_INTNET_IF_SET_MAC_ADDRESS, + /** Call IntNetR0IfSetActive(). */ + VMMR0_DO_INTNET_IF_SET_ACTIVE, + /** Call IntNetR0IfSend(). */ + VMMR0_DO_INTNET_IF_SEND, + /** Call IntNetR0IfWait(). */ + VMMR0_DO_INTNET_IF_WAIT, + /** Call IntNetR0IfAbortWait(). */ + VMMR0_DO_INTNET_IF_ABORT_WAIT, + +#if 0 + /** Forward call to the PCI driver */ + VMMR0_DO_PCIRAW_REQ = 512, +#endif + + /** The end of the R0 service operations. */ + VMMR0_DO_SRV_END, + + /** Call NEMR0InitVM() (host specific). */ + VMMR0_DO_NEM_INIT_VM = 576, + /** Call NEMR0InitVMPart2() (host specific). */ + VMMR0_DO_NEM_INIT_VM_PART_2, + /** Call NEMR0MapPages() (host specific). */ + VMMR0_DO_NEM_MAP_PAGES, + /** Call NEMR0UnmapPages() (host specific). */ + VMMR0_DO_NEM_UNMAP_PAGES, + /** Call NEMR0ExportState() (host specific). */ + VMMR0_DO_NEM_EXPORT_STATE, + /** Call NEMR0ImportState() (host specific). */ + VMMR0_DO_NEM_IMPORT_STATE, + /** Call NEMR0QueryCpuTick() (host specific). */ + VMMR0_DO_NEM_QUERY_CPU_TICK, + /** Call NEMR0ResumeCpuTickOnAll() (host specific). */ + VMMR0_DO_NEM_RESUME_CPU_TICK_ON_ALL, + /** Call NEMR0UpdateStatistics() (host specific). */ + VMMR0_DO_NEM_UPDATE_STATISTICS, + /** Call NEMR0DoExperiment() (host specific, experimental, debug only). */ + VMMR0_DO_NEM_EXPERIMENT, + + /** Grow the I/O port registration tables. */ + VMMR0_DO_IOM_GROW_IO_PORTS = 640, + /** Grow the I/O port statistics tables. */ + VMMR0_DO_IOM_GROW_IO_PORT_STATS, + /** Grow the MMIO registration tables. */ + VMMR0_DO_IOM_GROW_MMIO_REGS, + /** Grow the MMIO statistics tables. */ + VMMR0_DO_IOM_GROW_MMIO_STATS, + /** Synchronize statistics indices for I/O ports and MMIO regions. */ + VMMR0_DO_IOM_SYNC_STATS_INDICES, + + /** Call DBGFR0TraceCreateReqHandler. */ + VMMR0_DO_DBGF_TRACER_CREATE = 704, + /** Call DBGFR0TraceCallReqHandler. */ + VMMR0_DO_DBGF_TRACER_CALL_REQ_HANDLER, + /** Call DBGFR0BpInitReqHandler(). */ + VMMR0_DO_DBGF_BP_INIT, + /** Call DBGFR0BpChunkAllocReqHandler(). */ + VMMR0_DO_DBGF_BP_CHUNK_ALLOC, + /** Call DBGFR0BpL2TblChunkAllocReqHandler(). */ + VMMR0_DO_DBGF_BP_L2_TBL_CHUNK_ALLOC, + /** Call DBGFR0BpOwnerInitReqHandler(). */ + VMMR0_DO_DBGF_BP_OWNER_INIT, + /** Call DBGFR0BpPortIoInitReqHandler(). */ + VMMR0_DO_DBGF_BP_PORTIO_INIT, + + /** Grow a timer queue. */ + VMMR0_DO_TM_GROW_TIMER_QUEUE = 768, + + /** Official call we use for testing Ring-0 APIs. */ + VMMR0_DO_TESTS = 2048, + + /** The usual 32-bit type blow up. */ + VMMR0_DO_32BIT_HACK = 0x7fffffff +} VMMR0OPERATION; + + +/** + * Request buffer for VMMR0_DO_GCFGM_SET_VALUE and VMMR0_DO_GCFGM_QUERY_VALUE. + * @todo Move got GCFGM.h when it's implemented. + */ +typedef struct GCFGMVALUEREQ +{ + /** The request header.*/ + SUPVMMR0REQHDR Hdr; + /** The support driver session handle. */ + PSUPDRVSESSION pSession; + /** The value. + * This is input for the set request and output for the query. */ + uint64_t u64Value; + /** The variable name. + * This is fixed sized just to make things simple for the mock-up. */ + char szName[48]; +} GCFGMVALUEREQ; +/** Pointer to a VMMR0_DO_GCFGM_SET_VALUE and VMMR0_DO_GCFGM_QUERY_VALUE request buffer. + * @todo Move got GCFGM.h when it's implemented. + */ +typedef GCFGMVALUEREQ *PGCFGMVALUEREQ; + + +/** + * Request package for VMMR0_DO_VMMR0_UPDATE_LOGGERS. + * + * In addition the u64Arg is selects the logger and indicates whether we're only + * outputting to the parent VMM. See VMMR0UPDATELOGGER_F_XXX. + */ +typedef struct VMMR0UPDATELOGGERSREQ +{ + /** The request header. */ + SUPVMMR0REQHDR Hdr; + /** The current logger flags (RTLOGFLAGS). */ + uint64_t fFlags; + /** Groups, assuming same group layout as ring-3. */ + uint32_t cGroups; + /** CRC32 of the group names. */ + uint32_t uGroupCrc32; + /** Per-group settings, variable size. */ + RT_FLEXIBLE_ARRAY_EXTENSION + uint32_t afGroups[RT_FLEXIBLE_ARRAY]; +} VMMR0UPDATELOGGERSREQ; +/** Pointer to a VMMR0_DO_VMMR0_UPDATE_LOGGERS request. */ +typedef VMMR0UPDATELOGGERSREQ *PVMMR0UPDATELOGGERSREQ; + +/** @name VMMR0UPDATELOGGER_F_XXX - u64Arg definitions for VMMR0_DO_VMMR0_UPDATE_LOGGERS. + * @{ */ +/** Logger index mask. */ +#define VMMR0UPDATELOGGER_F_LOGGER_MASK UINT64_C(0x0001) +/** Only flush to the parent VMM's debug log, don't return to ring-3. */ +#define VMMR0UPDATELOGGER_F_TO_PARENT_VMM_DBG UINT64_C(0x0002) +/** Only flush to the parent VMM's debug log, don't return to ring-3. */ +#define VMMR0UPDATELOGGER_F_TO_PARENT_VMM_REL UINT64_C(0x0004) +/** Valid flag mask. */ +#define VMMR0UPDATELOGGER_F_VALID_MASK UINT64_C(0x0007) +/** @} */ + +#if defined(IN_RING0) || defined(DOXYGEN_RUNNING) + +/** + * Structure VMMR0EmtPrepareToBlock uses to pass info to + * VMMR0EmtResumeAfterBlocking. + */ +typedef struct VMMR0EMTBLOCKCTX +{ + /** Magic value (VMMR0EMTBLOCKCTX_MAGIC). */ + uint32_t uMagic; + /** Set if we were in HM context, clear if not. */ + bool fWasInHmContext; +} VMMR0EMTBLOCKCTX; +/** Pointer to a VMMR0EmtPrepareToBlock context structure. */ +typedef VMMR0EMTBLOCKCTX *PVMMR0EMTBLOCKCTX; +/** Magic value for VMMR0EMTBLOCKCTX::uMagic (Paul Desmond). */ +#define VMMR0EMTBLOCKCTX_MAGIC UINT32_C(0x19261125) +/** Magic value for VMMR0EMTBLOCKCTX::uMagic when its out of context. */ +#define VMMR0EMTBLOCKCTX_MAGIC_DEAD UINT32_C(0x19770530) + +VMMR0DECL(void) VMMR0EntryFast(PGVM pGVM, PVMCC pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation); +VMMR0DECL(int) VMMR0EntryEx(PGVM pGVM, PVMCC pVM, VMCPUID idCpu, VMMR0OPERATION enmOperation, + PSUPVMMR0REQHDR pReq, uint64_t u64Arg, PSUPDRVSESSION); +VMMR0_INT_DECL(int) VMMR0InitPerVMData(PGVM pGVM); +VMMR0_INT_DECL(int) VMMR0TermVM(PGVM pGVM, VMCPUID idCpu); +VMMR0_INT_DECL(void) VMMR0CleanupVM(PGVM pGVM); +VMMR0_INT_DECL(bool) VMMR0IsLongJumpArmed(PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) VMMR0ThreadCtxHookCreateForEmt(PVMCPUCC pVCpu); +VMMR0_INT_DECL(void) VMMR0ThreadCtxHookDestroyForEmt(PVMCPUCC pVCpu); +VMMR0_INT_DECL(void) VMMR0ThreadCtxHookDisable(PVMCPUCC pVCpu); +VMMR0_INT_DECL(bool) VMMR0ThreadCtxHookIsEnabled(PVMCPUCC pVCpu); +VMMR0_INT_DECL(int) VMMR0EmtPrepareToBlock(PVMCPUCC pVCpu, int rcBusy, const char *pszCaller, void *pvLock, + PVMMR0EMTBLOCKCTX pCtx); +VMMR0_INT_DECL(void) VMMR0EmtResumeAfterBlocking(PVMCPUCC pVCpu, PVMMR0EMTBLOCKCTX pCtx); +VMMR0_INT_DECL(int) VMMR0EmtWaitEventInner(PGVMCPU pGVCpu, uint32_t fFlags, RTSEMEVENT hEvent, RTMSINTERVAL cMsTimeout); +VMMR0_INT_DECL(int) VMMR0EmtSignalSupEvent(PGVM pGVM, PGVMCPU pGVCpu, SUPSEMEVENT hEvent); +VMMR0_INT_DECL(int) VMMR0EmtSignalSupEventByGVM(PGVM pGVM, SUPSEMEVENT hEvent); +VMMR0_INT_DECL(int) VMMR0AssertionSetNotification(PVMCPUCC pVCpu, PFNVMMR0ASSERTIONNOTIFICATION pfnCallback, RTR0PTR pvUser); +VMMR0_INT_DECL(void) VMMR0AssertionRemoveNotification(PVMCPUCC pVCpu); +VMMR0_INT_DECL(bool) VMMR0AssertionIsNotificationSet(PVMCPUCC pVCpu); + +/** @name VMMR0EMTWAIT_F_XXX - flags for VMMR0EmtWaitEventInner and friends. + * @{ */ +/** Try suppress VERR_INTERRUPTED for a little while (~10 sec). */ +#define VMMR0EMTWAIT_F_TRY_SUPPRESS_INTERRUPTED RT_BIT_32(0) +/** @} */ +#endif /* IN_RING0 */ + +VMMR0_INT_DECL(PRTLOGGER) VMMR0GetReleaseLogger(PVMCPUCC pVCpu); +/** @} */ + + +#if defined(IN_RING3) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_vmm_api_r3 The VMM Host Context Ring 3 API + * @{ + */ +VMMR3DECL(PCVMMR3VTABLE) VMMR3GetVTable(void); +VMMR3_INT_DECL(int) VMMR3Init(PVM pVM); +VMMR3_INT_DECL(int) VMMR3InitR0(PVM pVM); +VMMR3_INT_DECL(int) VMMR3InitCompleted(PVM pVM, VMINITCOMPLETED enmWhat); +VMMR3_INT_DECL(int) VMMR3Term(PVM pVM); +VMMR3_INT_DECL(void) VMMR3Relocate(PVM pVM, RTGCINTPTR offDelta); +VMMR3_INT_DECL(int) VMMR3UpdateLoggers(PVM pVM); +VMMR3DECL(const char *) VMMR3GetRZAssertMsg1(PVM pVM); +VMMR3DECL(const char *) VMMR3GetRZAssertMsg2(PVM pVM); +VMMR3_INT_DECL(int) VMMR3HmRunGC(PVM pVM, PVMCPU pVCpu); +VMMR3DECL(int) VMMR3CallR0(PVM pVM, uint32_t uOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr); +VMMR3_INT_DECL(int) VMMR3CallR0Emt(PVM pVM, PVMCPU pVCpu, VMMR0OPERATION enmOperation, uint64_t u64Arg, PSUPVMMR0REQHDR pReqHdr); +VMMR3_INT_DECL(VBOXSTRICTRC) VMMR3CallR0EmtFast(PVM pVM, PVMCPU pVCpu, VMMR0OPERATION enmOperation); +VMMR3DECL(void) VMMR3FatalDump(PVM pVM, PVMCPU pVCpu, int rcErr); +VMMR3_INT_DECL(void) VMMR3YieldSuspend(PVM pVM); +VMMR3_INT_DECL(void) VMMR3YieldStop(PVM pVM); +VMMR3_INT_DECL(void) VMMR3YieldResume(PVM pVM); +VMMR3_INT_DECL(void) VMMR3SendStartupIpi(PVM pVM, VMCPUID idCpu, uint32_t uVector); +VMMR3_INT_DECL(void) VMMR3SendInitIpi(PVM pVM, VMCPUID idCpu); +VMMR3DECL(int) VMMR3RegisterPatchMemory(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3DECL(int) VMMR3DeregisterPatchMemory(PVM pVM, RTGCPTR pPatchMem, unsigned cbPatchMem); +VMMR3DECL(int) VMMR3EmtRendezvous(PVM pVM, uint32_t fFlags, PFNVMMEMTRENDEZVOUS pfnRendezvous, void *pvUser); +/** @defgroup grp_VMMR3EmtRendezvous_fFlags VMMR3EmtRendezvous flags + * @{ */ +/** Execution type mask. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_MASK UINT32_C(0x00000007) +/** Invalid execution type. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_INVALID UINT32_C(0) +/** Let the EMTs execute the callback one by one (in no particular order). + * Recursion from within the callback possible. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ONE_BY_ONE UINT32_C(1) +/** Let all the EMTs execute the callback at the same time. + * Cannot recurse from the callback. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ALL_AT_ONCE UINT32_C(2) +/** Only execute the callback on one EMT (no particular one). + * Recursion from within the callback possible. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ONCE UINT32_C(3) +/** Let the EMTs execute the callback one by one in ascending order. + * Recursion from within the callback possible. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_ASCENDING UINT32_C(4) +/** Let the EMTs execute the callback one by one in descending order. + * Recursion from within the callback possible. */ +#define VMMEMTRENDEZVOUS_FLAGS_TYPE_DESCENDING UINT32_C(5) +/** Stop after the first error. + * This is not valid for any execution type where more than one EMT is active + * at a time. */ +#define VMMEMTRENDEZVOUS_FLAGS_STOP_ON_ERROR UINT32_C(0x00000008) +/** Use VMREQFLAGS_PRIORITY when contacting the EMTs. */ +#define VMMEMTRENDEZVOUS_FLAGS_PRIORITY UINT32_C(0x00000010) +/** The valid flags. */ +#define VMMEMTRENDEZVOUS_FLAGS_VALID_MASK UINT32_C(0x0000001f) +/** @} */ +VMMR3_INT_DECL(int) VMMR3EmtRendezvousFF(PVM pVM, PVMCPU pVCpu); +VMMR3_INT_DECL(void) VMMR3SetMayHaltInRing0(PVMCPU pVCpu, bool fMayHaltInRing0, uint32_t cNsSpinBlockThreshold); +VMMR3_INT_DECL(int) VMMR3ReadR0Stack(PVM pVM, VMCPUID idCpu, RTHCUINTPTR R0Addr, void *pvBuf, size_t cbRead); +VMMR3_INT_DECL(void) VMMR3InitR0StackUnwindState(PUVM pUVM, VMCPUID idCpu, PRTDBGUNWINDSTATE pState); +/** @} */ +#endif /* IN_RING3 */ + + +#if defined(IN_RC) || defined(IN_RING0) || defined(DOXYGEN_RUNNING) +/** @defgroup grp_vmm_api_rz The VMM Raw-Mode and Ring-0 Context API + * @{ + */ +VMMRZDECL(void) VMMRZCallRing3Disable(PVMCPUCC pVCpu); +VMMRZDECL(void) VMMRZCallRing3Enable(PVMCPUCC pVCpu); +VMMRZDECL(bool) VMMRZCallRing3IsEnabled(PVMCPUCC pVCpu); +/** @} */ +#endif + + +/** Wrapper around AssertReleaseMsgReturn that avoid tripping up in the + * kernel when we don't have a setjmp in place. */ +#ifdef IN_RING0 +# define VMM_ASSERT_RELEASE_MSG_RETURN(a_pVM, a_Expr, a_Msg, a_rc) do { \ + if (RT_LIKELY(a_Expr)) { /* likely */ } \ + else \ + { \ + PVMCPUCC pVCpuAssert = VMMGetCpu(a_pVM); \ + if (pVCpuAssert && VMMR0IsLongJumpArmed(pVCpuAssert)) \ + AssertReleaseMsg(a_Expr, a_Msg); \ + else \ + AssertLogRelMsg(a_Expr, a_Msg); \ + return (a_rc); \ + } \ + } while (0) +#else +# define VMM_ASSERT_RELEASE_MSG_RETURN(a_pVM, a_Expr, a_Msg, a_rc) AssertReleaseMsgReturn(a_Expr, a_Msg, a_rc) +#endif + +/** @} */ + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_vmm_h */ diff --git a/include/VBox/vmm/vmmr3vtable-def.h b/include/VBox/vmm/vmmr3vtable-def.h new file mode 100644 index 00000000..b95fdb47 --- /dev/null +++ b/include/VBox/vmm/vmmr3vtable-def.h @@ -0,0 +1,711 @@ +/** @file + * VM - The Virtual Machine Monitor, VTable ring-3 API, Definition Template. + * + * This is used by the vmmr3vtable.h header and the VMMR3VTable.cpp source file + * that implements it. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + + +/** @name VMM + * @{ */ +VTABLE_ENTRY(VMMGetSvnRev) +VTABLE_ENTRY(VMMGetCpu) + +VTABLE_RESERVED(pfnVMMR3Reserved1) +VTABLE_RESERVED(pfnVMMR3Reserved2) +VTABLE_RESERVED(pfnVMMR3Reserved3) +VTABLE_RESERVED(pfnVMMR3Reserved4) +VTABLE_RESERVED(pfnVMMR3Reserved5) +/** @} */ + +/** @name VM + * @{ + */ +VTABLE_ENTRY(VMR3Create) +VTABLE_ENTRY(VMR3PowerOn) +VTABLE_ENTRY(VMR3Suspend) +VTABLE_ENTRY(VMR3GetSuspendReason) +VTABLE_ENTRY(VMR3Resume) +VTABLE_ENTRY(VMR3GetResumeReason) +VTABLE_ENTRY(VMR3Reset) +VTABLE_ENTRY(VMR3Save) +VTABLE_ENTRY(VMR3Teleport) +VTABLE_ENTRY(VMR3LoadFromFile) +VTABLE_ENTRY(VMR3LoadFromStream) +VTABLE_ENTRY(VMR3PowerOff) +VTABLE_ENTRY(VMR3Destroy) + +VTABLE_ENTRY(VMR3GetVM) +VTABLE_ENTRY(VMR3GetUVM) +VTABLE_ENTRY(VMR3RetainUVM) +VTABLE_ENTRY(VMR3ReleaseUVM) +VTABLE_ENTRY(VMR3GetName) +VTABLE_ENTRY(VMR3GetUuid) +VTABLE_ENTRY(VMR3GetState) +VTABLE_ENTRY(VMR3GetStateU) +VTABLE_ENTRY(VMR3GetStateName) +VTABLE_ENTRY(VMR3AtStateRegister) +VTABLE_ENTRY(VMR3AtStateDeregister) +VTABLE_ENTRY(VMR3AtErrorRegister) +VTABLE_ENTRY(VMR3AtErrorDeregister) +VTABLE_ENTRY(VMR3SetError) +VTABLE_ENTRY(VMR3SetErrorV) +VTABLE_ENTRY(VMR3AtRuntimeErrorRegister) +VTABLE_ENTRY(VMR3AtRuntimeErrorDeregister) + +VTABLE_ENTRY(VMR3ReqCallU) +VTABLE_ENTRY(VMR3ReqCallVU) +VTABLE_ENTRY(VMR3ReqCallWaitU) +VTABLE_ENTRY(VMR3ReqCallNoWait) +VTABLE_ENTRY(VMR3ReqCallNoWaitU) +VTABLE_ENTRY(VMR3ReqCallVoidWaitU) +VTABLE_ENTRY(VMR3ReqCallVoidNoWait) +VTABLE_ENTRY(VMR3ReqPriorityCallWait) +VTABLE_ENTRY(VMR3ReqPriorityCallWaitU) +VTABLE_ENTRY(VMR3ReqPriorityCallVoidWaitU) +VTABLE_ENTRY(VMR3ReqAlloc) +VTABLE_ENTRY(VMR3ReqFree) +VTABLE_ENTRY(VMR3ReqQueue) +VTABLE_ENTRY(VMR3ReqWait) + +VTABLE_ENTRY(VMR3NotifyCpuDeviceReady) +VTABLE_ENTRY(VMR3WaitForDeviceReady) +VTABLE_ENTRY(VMR3GetVMCPUThread) +VTABLE_ENTRY(VMR3GetVMCPUNativeThread) +VTABLE_ENTRY(VMR3GetVMCPUNativeThreadU) +VTABLE_ENTRY(VMR3GetCpuCoreAndPackageIdFromCpuId) +VTABLE_ENTRY(VMR3HotUnplugCpu) +VTABLE_ENTRY(VMR3HotPlugCpu) +VTABLE_ENTRY(VMR3SetCpuExecutionCap) +VTABLE_ENTRY(VMR3SetPowerOffInsteadOfReset) + +VTABLE_RESERVED(pfnVMR3Reserved1) +VTABLE_RESERVED(pfnVMR3Reserved2) +VTABLE_RESERVED(pfnVMR3Reserved3) +VTABLE_RESERVED(pfnVMR3Reserved4) +VTABLE_RESERVED(pfnVMR3Reserved5) +/** @} */ + +/** @name CFGM + * @{ */ +VTABLE_ENTRY(CFGMR3Init) +VTABLE_ENTRY(CFGMR3Term) +VTABLE_ENTRY(CFGMR3ConstructDefaultTree) + +VTABLE_ENTRY(CFGMR3CreateTree) +VTABLE_ENTRY(CFGMR3DestroyTree) +VTABLE_ENTRY(CFGMR3Dump) +VTABLE_ENTRY(CFGMR3DuplicateSubTree) +VTABLE_ENTRY(CFGMR3ReplaceSubTree) +VTABLE_ENTRY(CFGMR3InsertSubTree) +VTABLE_ENTRY(CFGMR3InsertNode) +VTABLE_ENTRY(CFGMR3InsertNodeF) +VTABLE_ENTRY(CFGMR3InsertNodeFV) +VTABLE_ENTRY(CFGMR3SetRestrictedRoot) +VTABLE_ENTRY(CFGMR3RemoveNode) +VTABLE_ENTRY(CFGMR3InsertInteger) +VTABLE_ENTRY(CFGMR3InsertString) +VTABLE_ENTRY(CFGMR3InsertStringN) +VTABLE_ENTRY(CFGMR3InsertStringF) +VTABLE_ENTRY(CFGMR3InsertStringFV) +VTABLE_ENTRY(CFGMR3InsertStringW) +VTABLE_ENTRY(CFGMR3InsertBytes) +VTABLE_ENTRY(CFGMR3InsertPassword) +VTABLE_ENTRY(CFGMR3InsertPasswordN) +VTABLE_ENTRY(CFGMR3InsertValue) +VTABLE_ENTRY(CFGMR3RemoveValue) +VTABLE_ENTRY(CFGMR3CopyTree) + +VTABLE_ENTRY(CFGMR3Exists) +VTABLE_ENTRY(CFGMR3QueryType) +VTABLE_ENTRY(CFGMR3QuerySize) +VTABLE_ENTRY(CFGMR3QueryInteger) +VTABLE_ENTRY(CFGMR3QueryIntegerDef) +VTABLE_ENTRY(CFGMR3QueryString) +VTABLE_ENTRY(CFGMR3QueryStringDef) +VTABLE_ENTRY(CFGMR3QueryPassword) +VTABLE_ENTRY(CFGMR3QueryPasswordDef) +VTABLE_ENTRY(CFGMR3QueryBytes) + +VTABLE_ENTRY(CFGMR3QueryU64) +VTABLE_ENTRY(CFGMR3QueryU64Def) +VTABLE_ENTRY(CFGMR3QueryS64) +VTABLE_ENTRY(CFGMR3QueryS64Def) +VTABLE_ENTRY(CFGMR3QueryU32) +VTABLE_ENTRY(CFGMR3QueryU32Def) +VTABLE_ENTRY(CFGMR3QueryS32) +VTABLE_ENTRY(CFGMR3QueryS32Def) +VTABLE_ENTRY(CFGMR3QueryU16) +VTABLE_ENTRY(CFGMR3QueryU16Def) +VTABLE_ENTRY(CFGMR3QueryS16) +VTABLE_ENTRY(CFGMR3QueryS16Def) +VTABLE_ENTRY(CFGMR3QueryU8) +VTABLE_ENTRY(CFGMR3QueryU8Def) +VTABLE_ENTRY(CFGMR3QueryS8) +VTABLE_ENTRY(CFGMR3QueryS8Def) +VTABLE_ENTRY(CFGMR3QueryBool) +VTABLE_ENTRY(CFGMR3QueryBoolDef) +VTABLE_ENTRY(CFGMR3QueryPort) +VTABLE_ENTRY(CFGMR3QueryPortDef) +VTABLE_ENTRY(CFGMR3QueryUInt) +VTABLE_ENTRY(CFGMR3QueryUIntDef) +VTABLE_ENTRY(CFGMR3QuerySInt) +VTABLE_ENTRY(CFGMR3QuerySIntDef) +VTABLE_ENTRY(CFGMR3QueryGCPtr) +VTABLE_ENTRY(CFGMR3QueryGCPtrDef) +VTABLE_ENTRY(CFGMR3QueryGCPtrU) +VTABLE_ENTRY(CFGMR3QueryGCPtrUDef) +VTABLE_ENTRY(CFGMR3QueryGCPtrS) +VTABLE_ENTRY(CFGMR3QueryGCPtrSDef) +VTABLE_ENTRY(CFGMR3QueryStringAlloc) +VTABLE_ENTRY(CFGMR3QueryStringAllocDef) + +VTABLE_ENTRY(CFGMR3GetRoot) +VTABLE_ENTRY(CFGMR3GetRootU) +VTABLE_ENTRY(CFGMR3GetParent) +VTABLE_ENTRY(CFGMR3GetParentEx) +VTABLE_ENTRY(CFGMR3GetChild) +VTABLE_ENTRY(CFGMR3GetChildF) +VTABLE_ENTRY(CFGMR3GetChildFV) +VTABLE_ENTRY(CFGMR3GetFirstChild) +VTABLE_ENTRY(CFGMR3GetNextChild) +VTABLE_ENTRY(CFGMR3GetName) +VTABLE_ENTRY(CFGMR3GetNameLen) +VTABLE_ENTRY(CFGMR3AreChildrenValid) +VTABLE_ENTRY(CFGMR3GetFirstValue) +VTABLE_ENTRY(CFGMR3GetNextValue) +VTABLE_ENTRY(CFGMR3GetValueName) +VTABLE_ENTRY(CFGMR3GetValueNameLen) +VTABLE_ENTRY(CFGMR3GetValueType) +VTABLE_ENTRY(CFGMR3AreValuesValid) +VTABLE_ENTRY(CFGMR3ValidateConfig) + +VTABLE_RESERVED(pfnCFMGR3Reserved1) +VTABLE_RESERVED(pfnCFMGR3Reserved2) +VTABLE_RESERVED(pfnCFMGR3Reserved3) +VTABLE_RESERVED(pfnCFMGR3Reserved4) +VTABLE_RESERVED(pfnCFMGR3Reserved5) +/** @} */ + +/** @name SSM + * @{ */ +VTABLE_ENTRY(SSMR3Term) +VTABLE_ENTRY(SSMR3RegisterInternal) +VTABLE_ENTRY(SSMR3RegisterExternal) +VTABLE_ENTRY(SSMR3RegisterStub) +VTABLE_ENTRY(SSMR3DeregisterInternal) +VTABLE_ENTRY(SSMR3DeregisterExternal) +VTABLE_ENTRY(SSMR3Save) +VTABLE_ENTRY(SSMR3Load) +VTABLE_ENTRY(SSMR3ValidateFile) +VTABLE_ENTRY(SSMR3Open) +VTABLE_ENTRY(SSMR3Close) +VTABLE_ENTRY(SSMR3Seek) +VTABLE_ENTRY(SSMR3HandleGetStatus) +VTABLE_ENTRY(SSMR3HandleSetStatus) +VTABLE_ENTRY(SSMR3HandleGetAfter) +VTABLE_ENTRY(SSMR3HandleIsLiveSave) +VTABLE_ENTRY(SSMR3HandleMaxDowntime) +VTABLE_ENTRY(SSMR3HandleHostBits) +VTABLE_ENTRY(SSMR3HandleRevision) +VTABLE_ENTRY(SSMR3HandleVersion) +VTABLE_ENTRY(SSMR3HandleHostOSAndArch) +VTABLE_ENTRY(SSMR3HandleReportLivePercent) +VTABLE_ENTRY(SSMR3Cancel) + +VTABLE_ENTRY(SSMR3PutStruct) +VTABLE_ENTRY(SSMR3PutStructEx) +VTABLE_ENTRY(SSMR3PutBool) +VTABLE_ENTRY(SSMR3PutU8) +VTABLE_ENTRY(SSMR3PutS8) +VTABLE_ENTRY(SSMR3PutU16) +VTABLE_ENTRY(SSMR3PutS16) +VTABLE_ENTRY(SSMR3PutU32) +VTABLE_ENTRY(SSMR3PutS32) +VTABLE_ENTRY(SSMR3PutU64) +VTABLE_ENTRY(SSMR3PutS64) +VTABLE_ENTRY(SSMR3PutU128) +VTABLE_ENTRY(SSMR3PutS128) +VTABLE_ENTRY(SSMR3PutUInt) +VTABLE_ENTRY(SSMR3PutSInt) +VTABLE_ENTRY(SSMR3PutGCUInt) +VTABLE_ENTRY(SSMR3PutGCUIntReg) +VTABLE_ENTRY(SSMR3PutGCPhys32) +VTABLE_ENTRY(SSMR3PutGCPhys64) +VTABLE_ENTRY(SSMR3PutGCPhys) +VTABLE_ENTRY(SSMR3PutGCPtr) +VTABLE_ENTRY(SSMR3PutGCUIntPtr) +VTABLE_ENTRY(SSMR3PutRCPtr) +VTABLE_ENTRY(SSMR3PutIOPort) +VTABLE_ENTRY(SSMR3PutSel) +VTABLE_ENTRY(SSMR3PutMem) +VTABLE_ENTRY(SSMR3PutStrZ) + +VTABLE_ENTRY(SSMR3GetStruct) +VTABLE_ENTRY(SSMR3GetStructEx) +VTABLE_ENTRY(SSMR3GetBool) +VTABLE_ENTRY(SSMR3GetBoolV) +VTABLE_ENTRY(SSMR3GetU8) +VTABLE_ENTRY(SSMR3GetU8V) +VTABLE_ENTRY(SSMR3GetS8) +VTABLE_ENTRY(SSMR3GetS8V) +VTABLE_ENTRY(SSMR3GetU16) +VTABLE_ENTRY(SSMR3GetU16V) +VTABLE_ENTRY(SSMR3GetS16) +VTABLE_ENTRY(SSMR3GetS16V) +VTABLE_ENTRY(SSMR3GetU32) +VTABLE_ENTRY(SSMR3GetU32V) +VTABLE_ENTRY(SSMR3GetS32) +VTABLE_ENTRY(SSMR3GetS32V) +VTABLE_ENTRY(SSMR3GetU64) +VTABLE_ENTRY(SSMR3GetU64V) +VTABLE_ENTRY(SSMR3GetS64) +VTABLE_ENTRY(SSMR3GetS64V) +VTABLE_ENTRY(SSMR3GetU128) +VTABLE_ENTRY(SSMR3GetU128V) +VTABLE_ENTRY(SSMR3GetS128) +VTABLE_ENTRY(SSMR3GetS128V) +VTABLE_ENTRY(SSMR3GetGCPhys32) +VTABLE_ENTRY(SSMR3GetGCPhys32V) +VTABLE_ENTRY(SSMR3GetGCPhys64) +VTABLE_ENTRY(SSMR3GetGCPhys64V) +VTABLE_ENTRY(SSMR3GetGCPhys) +VTABLE_ENTRY(SSMR3GetGCPhysV) +VTABLE_ENTRY(SSMR3GetUInt) +VTABLE_ENTRY(SSMR3GetSInt) +VTABLE_ENTRY(SSMR3GetGCUInt) +VTABLE_ENTRY(SSMR3GetGCUIntReg) +VTABLE_ENTRY(SSMR3GetGCPtr) +VTABLE_ENTRY(SSMR3GetGCUIntPtr) +VTABLE_ENTRY(SSMR3GetRCPtr) +VTABLE_ENTRY(SSMR3GetIOPort) +VTABLE_ENTRY(SSMR3GetSel) +VTABLE_ENTRY(SSMR3GetMem) +VTABLE_ENTRY(SSMR3GetStrZ) +VTABLE_ENTRY(SSMR3GetStrZEx) +VTABLE_ENTRY(SSMR3Skip) +VTABLE_ENTRY(SSMR3SkipToEndOfUnit) +VTABLE_ENTRY(SSMR3SetLoadError) +VTABLE_ENTRY(SSMR3SetLoadErrorV) +VTABLE_ENTRY(SSMR3SetCfgError) +VTABLE_ENTRY(SSMR3SetCfgErrorV) + +VTABLE_RESERVED(pfnSSMR3Reserved1) +VTABLE_RESERVED(pfnSSMR3Reserved2) +VTABLE_RESERVED(pfnSSMR3Reserved3) +VTABLE_RESERVED(pfnSSMR3Reserved4) +VTABLE_RESERVED(pfnSSMR3Reserved5) +/** @} */ + +/** @name STAM + * @{ */ +VTABLE_ENTRY(STAMR3InitUVM) +VTABLE_ENTRY(STAMR3TermUVM) +VTABLE_ENTRY(STAMR3RegisterU) +VTABLE_ENTRY(STAMR3Register) +VTABLE_ENTRY(STAMR3RegisterFU) +VTABLE_ENTRY(STAMR3RegisterF) +VTABLE_ENTRY(STAMR3RegisterVU) +VTABLE_ENTRY(STAMR3RegisterV) +VTABLE_ENTRY(STAMR3RegisterCallback) +VTABLE_ENTRY(STAMR3RegisterCallbackV) +VTABLE_ENTRY(STAMR3RegisterRefresh) +VTABLE_ENTRY(STAMR3RegisterRefreshV) +VTABLE_ENTRY(STAMR3Deregister) +VTABLE_ENTRY(STAMR3DeregisterF) +VTABLE_ENTRY(STAMR3DeregisterV) +VTABLE_ENTRY(STAMR3DeregisterByPrefix) +VTABLE_ENTRY(STAMR3DeregisterByAddr) +VTABLE_ENTRY(STAMR3Reset) +VTABLE_ENTRY(STAMR3Snapshot) +VTABLE_ENTRY(STAMR3SnapshotFree) +VTABLE_ENTRY(STAMR3Dump) +VTABLE_ENTRY(STAMR3DumpToReleaseLog) +VTABLE_ENTRY(STAMR3Print) +VTABLE_ENTRY(STAMR3Enum) +VTABLE_ENTRY(STAMR3GetUnit) +VTABLE_ENTRY(STAMR3GetUnit1) +VTABLE_ENTRY(STAMR3GetUnit2) + +VTABLE_RESERVED(pfnSTAMR3Reserved1) +VTABLE_RESERVED(pfnSTAMR3Reserved2) +VTABLE_RESERVED(pfnSTAMR3Reserved3) +VTABLE_RESERVED(pfnSTAMR3Reserved4) +VTABLE_RESERVED(pfnSTAMR3Reserved5) +/** @} */ + +/** @name CPUM + * @{ */ +VTABLE_ENTRY(CPUMGetHostCpuVendor) +VTABLE_ENTRY(CPUMGetHostMicroarch) + +VTABLE_RESERVED(pfnCPUMR3Reserved1) +VTABLE_RESERVED(pfnCPUMR3Reserved2) +VTABLE_RESERVED(pfnCPUMR3Reserved3) +VTABLE_RESERVED(pfnCPUMR3Reserved4) +VTABLE_RESERVED(pfnCPUMR3Reserved5) +/** @} */ + +/** @name DBGC + * @{ */ +VTABLE_ENTRY(DBGCCreate) + +VTABLE_RESERVED(pfnDBGCR3Reserved1) +VTABLE_RESERVED(pfnDBGCR3Reserved2) +VTABLE_RESERVED(pfnDBGCR3Reserved3) +VTABLE_RESERVED(pfnDBGCR3Reserved4) +VTABLE_RESERVED(pfnDBGCR3Reserved5) +/** @} */ + +/** @name DBGF + * @{ */ +VTABLE_ENTRY(DBGFR3BpClear) +VTABLE_ENTRY(DBGFR3BpDisable) +VTABLE_ENTRY(DBGFR3BpEnable) +VTABLE_ENTRY(DBGFR3BpOwnerCreate) +VTABLE_ENTRY(DBGFR3BpOwnerDestroy) +VTABLE_ENTRY(DBGFR3BpSetInt3) +VTABLE_ENTRY(DBGFR3BpSetInt3Ex) +VTABLE_ENTRY(DBGFR3BpSetMmio) +VTABLE_ENTRY(DBGFR3BpSetMmioEx) +VTABLE_ENTRY(DBGFR3BpSetPortIo) +VTABLE_ENTRY(DBGFR3BpSetPortIoEx) +VTABLE_ENTRY(DBGFR3BpSetReg) +VTABLE_ENTRY(DBGFR3BpSetRegEx) +VTABLE_ENTRY(DBGFR3BpSetREM) +VTABLE_ENTRY(DBGFR3CoreWrite) +VTABLE_ENTRY(DBGFR3Info) +VTABLE_ENTRY(DBGFR3InfoRegisterExternal) +VTABLE_ENTRY(DBGFR3InfoDeregisterExternal) +VTABLE_ENTRY(DBGFR3InfoGenericGetOptError) +VTABLE_ENTRY(DBGFR3InjectNMI) +VTABLE_ENTRY(DBGFR3LogModifyDestinations) +VTABLE_ENTRY(DBGFR3LogModifyFlags) +VTABLE_ENTRY(DBGFR3LogModifyGroups) +VTABLE_ENTRY(DBGFR3OSDetect) +VTABLE_ENTRY(DBGFR3OSQueryNameAndVersion) +VTABLE_ENTRY(DBGFR3RegCpuQueryU8) +VTABLE_ENTRY(DBGFR3RegCpuQueryU16) +VTABLE_ENTRY(DBGFR3RegCpuQueryU32) +VTABLE_ENTRY(DBGFR3RegCpuQueryU64) +VTABLE_ENTRY(DBGFR3RegCpuQueryXdtr) +VTABLE_ENTRY(DBGFR3RegFormatValue) +VTABLE_ENTRY(DBGFR3RegNmQuery) +VTABLE_ENTRY(DBGFR3RegNmQueryAll) +VTABLE_ENTRY(DBGFR3RegNmQueryAllCount) +VTABLE_ENTRY(DBGFR3RegNmSetBatch) +VTABLE_ENTRY(DBGFR3OSDeregister) +VTABLE_ENTRY(DBGFR3OSRegister) +VTABLE_ENTRY(DBGFR3OSQueryInterface) +VTABLE_ENTRY(DBGFR3MemReadString) +VTABLE_ENTRY(DBGFR3MemRead) +VTABLE_ENTRY(DBGFR3MemScan) +VTABLE_ENTRY(DBGFR3ModInMem) +VTABLE_ENTRY(DBGFR3AddrFromFlat) +VTABLE_ENTRY(DBGFR3AsSymbolByName) +VTABLE_ENTRY(DBGFR3AsResolveAndRetain) +VTABLE_ENTRY(DBGFR3AsSetAlias) +VTABLE_ENTRY(DBGFR3AddrAdd) +VTABLE_ENTRY(DBGFR3AddrSub) +VTABLE_ENTRY(DBGFR3AsGetConfig) +VTABLE_ENTRY(DBGFR3CpuGetCount) +VTABLE_ENTRY(DBGFR3CpuGetMode) +VTABLE_ENTRY(DBGFR3CpuGetState) +VTABLE_ENTRY(DBGFR3AddrFromSelOff) +VTABLE_ENTRY(DBGFR3FlowCreate) +VTABLE_ENTRY(DBGFR3FlowRetain) +VTABLE_ENTRY(DBGFR3FlowRelease) +VTABLE_ENTRY(DBGFR3FlowQueryStartBb) +VTABLE_ENTRY(DBGFR3FlowQueryBbByAddress) +VTABLE_ENTRY(DBGFR3FlowQueryBranchTblByAddress) +VTABLE_ENTRY(DBGFR3FlowGetBbCount) +VTABLE_ENTRY(DBGFR3FlowGetBranchTblCount) +VTABLE_ENTRY(DBGFR3FlowGetCallInsnCount) +VTABLE_ENTRY(DBGFR3FlowBbRetain) +VTABLE_ENTRY(DBGFR3FlowBbRelease) +VTABLE_ENTRY(DBGFR3FlowBbGetStartAddress) +VTABLE_ENTRY(DBGFR3FlowBbGetEndAddress) +VTABLE_ENTRY(DBGFR3FlowBbGetBranchAddress) +VTABLE_ENTRY(DBGFR3FlowBbGetFollowingAddress) +VTABLE_ENTRY(DBGFR3FlowBbGetType) +VTABLE_ENTRY(DBGFR3FlowBbGetInstrCount) +VTABLE_ENTRY(DBGFR3FlowBbGetFlags) +VTABLE_ENTRY(DBGFR3FlowBbQueryBranchTbl) +VTABLE_ENTRY(DBGFR3FlowBbQueryError) +VTABLE_ENTRY(DBGFR3FlowBbQueryInstr) +VTABLE_ENTRY(DBGFR3FlowBbQuerySuccessors) +VTABLE_ENTRY(DBGFR3FlowBbGetRefBbCount) +VTABLE_ENTRY(DBGFR3FlowBbGetRefBb) +VTABLE_ENTRY(DBGFR3FlowBranchTblRetain) +VTABLE_ENTRY(DBGFR3FlowBranchTblRelease) +VTABLE_ENTRY(DBGFR3FlowBranchTblGetSlots) +VTABLE_ENTRY(DBGFR3FlowBranchTblGetStartAddress) +VTABLE_ENTRY(DBGFR3FlowBranchTblGetAddrAtSlot) +VTABLE_ENTRY(DBGFR3FlowBranchTblQueryAddresses) +VTABLE_ENTRY(DBGFR3FlowItCreate) +VTABLE_ENTRY(DBGFR3FlowItDestroy) +VTABLE_ENTRY(DBGFR3FlowItNext) +VTABLE_ENTRY(DBGFR3FlowItReset) +VTABLE_ENTRY(DBGFR3FlowBranchTblItCreate) +VTABLE_ENTRY(DBGFR3FlowBranchTblItDestroy) +VTABLE_ENTRY(DBGFR3FlowBranchTblItNext) +VTABLE_ENTRY(DBGFR3FlowBranchTblItReset) +VTABLE_ENTRY(DBGFR3FlowTraceModCreate) +VTABLE_ENTRY(DBGFR3FlowTraceModCreateFromFlowGraph) +VTABLE_ENTRY(DBGFR3FlowTraceModRetain) +VTABLE_ENTRY(DBGFR3FlowTraceModRelease) +VTABLE_ENTRY(DBGFR3FlowTraceModEnable) +VTABLE_ENTRY(DBGFR3FlowTraceModDisable) +VTABLE_ENTRY(DBGFR3FlowTraceModQueryReport) +VTABLE_ENTRY(DBGFR3FlowTraceModClear) +VTABLE_ENTRY(DBGFR3FlowTraceModAddProbe) +VTABLE_ENTRY(DBGFR3FlowTraceProbeCreate) +VTABLE_ENTRY(DBGFR3FlowTraceProbeRetain) +VTABLE_ENTRY(DBGFR3FlowTraceProbeRelease) +VTABLE_ENTRY(DBGFR3FlowTraceProbeEntriesAdd) +VTABLE_ENTRY(DBGFR3FlowTraceReportRetain) +VTABLE_ENTRY(DBGFR3FlowTraceReportRelease) +VTABLE_ENTRY(DBGFR3FlowTraceReportGetRecordCount) +VTABLE_ENTRY(DBGFR3FlowTraceReportQueryRecord) +VTABLE_ENTRY(DBGFR3FlowTraceReportQueryFiltered) +VTABLE_ENTRY(DBGFR3FlowTraceReportEnumRecords) +VTABLE_ENTRY(DBGFR3FlowTraceRecordRetain) +VTABLE_ENTRY(DBGFR3FlowTraceRecordRelease) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetSeqNo) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetTimestamp) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetAddr) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetProbe) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetValCount) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetVals) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetValsCommon) +VTABLE_ENTRY(DBGFR3FlowTraceRecordGetCpuId) +VTABLE_ENTRY(DBGFR3PlugInLoad) +VTABLE_ENTRY(DBGFR3PlugInUnload) +VTABLE_ENTRY(DBGFR3PlugInLoadAll) +VTABLE_ENTRY(DBGFR3PlugInUnloadAll) +VTABLE_ENTRY(DBGFR3SampleReportCreate) +VTABLE_ENTRY(DBGFR3SampleReportRetain) +VTABLE_ENTRY(DBGFR3SampleReportRelease) +VTABLE_ENTRY(DBGFR3SampleReportStart) +VTABLE_ENTRY(DBGFR3SampleReportStop) +VTABLE_ENTRY(DBGFR3SampleReportDumpToFile) +VTABLE_ENTRY(DBGFR3SelQueryInfo) +VTABLE_ENTRY(DBGFR3StackWalkBegin) +VTABLE_ENTRY(DBGFR3StackWalkNext) +VTABLE_ENTRY(DBGFR3StackWalkEnd) +VTABLE_ENTRY(DBGFR3TypeDeregister) +VTABLE_ENTRY(DBGFR3TypeDumpEx) +VTABLE_ENTRY(DBGFR3TypeQueryReg) +VTABLE_ENTRY(DBGFR3TypeQuerySize) +VTABLE_ENTRY(DBGFR3TypeQueryValByType) +VTABLE_ENTRY(DBGFR3TypeRegister) +VTABLE_ENTRY(DBGFR3TypeSetSize) +VTABLE_ENTRY(DBGFR3TypeValFree) +VTABLE_ENTRY(DBGFR3TypeValDumpEx) + +VTABLE_RESERVED(pfnDBGFR3Reserved1) +VTABLE_RESERVED(pfnDBGFR3Reserved2) +VTABLE_RESERVED(pfnDBGFR3Reserved3) +VTABLE_RESERVED(pfnDBGFR3Reserved4) +VTABLE_RESERVED(pfnDBGFR3Reserved5) +/** @} */ + +/** @name EM + * @{ */ +VTABLE_ENTRY(EMR3QueryExecutionPolicy) +VTABLE_ENTRY(EMR3QueryMainExecutionEngine) +VTABLE_ENTRY(EMR3SetExecutionPolicy) + +VTABLE_RESERVED(pfnEMR3Reserved1) +VTABLE_RESERVED(pfnEMR3Reserved2) +VTABLE_RESERVED(pfnEMR3Reserved3) +VTABLE_RESERVED(pfnEMR3Reserved4) +VTABLE_RESERVED(pfnEMR3Reserved5) +/** @} */ + +/** @name HM + * @{ */ +VTABLE_ENTRY(HMR3IsEnabled) +VTABLE_ENTRY(HMR3IsNestedPagingActive) +VTABLE_ENTRY(HMR3IsUXActive) +VTABLE_ENTRY(HMR3IsVpidActive) + +VTABLE_RESERVED(pfnHMR3Reserved1) +VTABLE_RESERVED(pfnHMR3Reserved2) +VTABLE_RESERVED(pfnHMR3Reserved3) +VTABLE_RESERVED(pfnHMR3Reserved4) +VTABLE_RESERVED(pfnHMR3Reserved5) +/** @} */ + +/** @name MM + * @{ */ +VTABLE_ENTRY(MMR3HeapAllocU) +VTABLE_ENTRY(MMR3HeapAllocExU) +VTABLE_ENTRY(MMR3HeapAllocZU) +VTABLE_ENTRY(MMR3HeapAllocZExU) +VTABLE_ENTRY(MMR3HeapRealloc) +VTABLE_ENTRY(MMR3HeapStrDupU) +VTABLE_ENTRY(MMR3HeapAPrintfU) +VTABLE_ENTRY(MMR3HeapAPrintfVU) +VTABLE_ENTRY(MMR3HeapFree) + +VTABLE_RESERVED(pfnMMR3Reserved1) +VTABLE_RESERVED(pfnMMR3Reserved2) +VTABLE_RESERVED(pfnMMR3Reserved3) +VTABLE_RESERVED(pfnMMR3Reserved4) +VTABLE_RESERVED(pfnMMR3Reserved5) +/** @} */ + +/** @name PDM + * @{ */ +VTABLE_ENTRY(PDMR3AsyncCompletionBwMgrSetMaxForFile) +VTABLE_ENTRY(PDMR3DeviceAttach) +VTABLE_ENTRY(PDMR3DeviceDetach) +VTABLE_ENTRY(PDMR3DriverAttach) +VTABLE_ENTRY(PDMR3DriverDetach) +VTABLE_ENTRY(PDMR3NsBwGroupSetLimit) +VTABLE_ENTRY(PDMR3QueryDeviceLun) +VTABLE_ENTRY(PDMR3QueryDriverOnLun) +VTABLE_ENTRY(PDMR3QueryLun) + +VTABLE_ENTRY(PDMCritSectEnter) +VTABLE_ENTRY(PDMCritSectEnterDebug) +VTABLE_ENTRY(PDMCritSectTryEnter) +VTABLE_ENTRY(PDMCritSectTryEnterDebug) +VTABLE_ENTRY(PDMR3CritSectEnterEx) +VTABLE_ENTRY(PDMCritSectLeave) +VTABLE_ENTRY(PDMCritSectIsOwner) +VTABLE_ENTRY(PDMCritSectIsOwnerEx) +VTABLE_ENTRY(PDMCritSectIsInitialized) +VTABLE_ENTRY(PDMCritSectHasWaiters) +VTABLE_ENTRY(PDMCritSectGetRecursion) +VTABLE_ENTRY(PDMR3CritSectYield) +VTABLE_ENTRY(PDMR3CritSectName) +VTABLE_ENTRY(PDMR3CritSectDelete) + +VTABLE_ENTRY(PDMQueueAlloc) +VTABLE_ENTRY(PDMQueueInsert) +VTABLE_RESERVED(pfnPDMR3Reserved11) + +VTABLE_ENTRY(PDMR3ThreadDestroy) +VTABLE_ENTRY(PDMR3ThreadIAmRunning) +VTABLE_ENTRY(PDMR3ThreadIAmSuspending) +VTABLE_ENTRY(PDMR3ThreadResume) +VTABLE_ENTRY(PDMR3ThreadSleep) +VTABLE_ENTRY(PDMR3ThreadSuspend) + +VTABLE_ENTRY(PDMR3UsbCreateEmulatedDevice) +VTABLE_ENTRY(PDMR3UsbCreateProxyDevice) +VTABLE_ENTRY(PDMR3UsbDetachDevice) +VTABLE_ENTRY(PDMR3UsbHasHub) +VTABLE_ENTRY(PDMR3UsbDriverAttach) +VTABLE_ENTRY(PDMR3UsbDriverDetach) +VTABLE_ENTRY(PDMR3UsbQueryLun) +VTABLE_ENTRY(PDMR3UsbQueryDriverOnLun) + +VTABLE_RESERVED(pfnPDMR3Reserved1) +VTABLE_RESERVED(pfnPDMR3Reserved2) +VTABLE_RESERVED(pfnPDMR3Reserved3) +VTABLE_RESERVED(pfnPDMR3Reserved4) +VTABLE_RESERVED(pfnPDMR3Reserved5) +VTABLE_RESERVED(pfnPDMR3Reserved6) +VTABLE_RESERVED(pfnPDMR3Reserved7) +VTABLE_RESERVED(pfnPDMR3Reserved8) +VTABLE_RESERVED(pfnPDMR3Reserved9) +VTABLE_RESERVED(pfnPDMR3Reserved10) +/** @} */ + +/** @name PGM + * @{ */ +VTABLE_ENTRY(PGMHandlerPhysicalPageTempOff) +VTABLE_ENTRY(PGMPhysReadGCPtr) +VTABLE_ENTRY(PGMPhysSimpleDirtyWriteGCPtr) +VTABLE_ENTRY(PGMPhysSimpleReadGCPtr) +VTABLE_ENTRY(PGMPhysSimpleWriteGCPhys) +VTABLE_ENTRY(PGMPhysSimpleWriteGCPtr) +VTABLE_ENTRY(PGMPhysWriteGCPtr) +VTABLE_ENTRY(PGMShwMakePageWritable) +VTABLE_ENTRY(PGMR3QueryGlobalMemoryStats) +VTABLE_ENTRY(PGMR3QueryMemoryStats) + +VTABLE_RESERVED(pfnPGMR3Reserved1) +VTABLE_RESERVED(pfnPGMR3Reserved2) +VTABLE_RESERVED(pfnPGMR3Reserved3) +VTABLE_RESERVED(pfnPGMR3Reserved4) +VTABLE_RESERVED(pfnPGMR3Reserved5) +/** @} */ + +/** @name TM + * @{ */ +VTABLE_ENTRY(TMR3GetCpuLoadPercents) +VTABLE_ENTRY(TMR3TimerSetCritSect) +VTABLE_ENTRY(TMR3TimerLoad) +VTABLE_ENTRY(TMR3TimerSave) +VTABLE_ENTRY(TMR3TimerSkip) +VTABLE_ENTRY(TMR3TimerDestroy) +VTABLE_ENTRY(TMTimerFromMicro) +VTABLE_ENTRY(TMTimerFromMilli) +VTABLE_ENTRY(TMTimerFromNano) +VTABLE_ENTRY(TMTimerGet) +VTABLE_ENTRY(TMTimerGetFreq) +VTABLE_ENTRY(TMTimerGetMicro) +VTABLE_ENTRY(TMTimerGetMilli) +VTABLE_ENTRY(TMTimerGetNano) +VTABLE_ENTRY(TMTimerIsActive) +VTABLE_ENTRY(TMTimerIsLockOwner) +VTABLE_ENTRY(TMTimerLock) +VTABLE_ENTRY(TMTimerSet) +VTABLE_ENTRY(TMTimerSetFrequencyHint) +VTABLE_ENTRY(TMTimerSetMicro) +VTABLE_ENTRY(TMTimerSetMillies) +VTABLE_ENTRY(TMTimerSetNano) +VTABLE_ENTRY(TMTimerSetRelative) +VTABLE_ENTRY(TMTimerStop) +VTABLE_ENTRY(TMTimerToMicro) +VTABLE_ENTRY(TMTimerToMilli) +VTABLE_ENTRY(TMTimerToNano) +VTABLE_ENTRY(TMTimerUnlock) +VTABLE_ENTRY(TMR3GetWarpDrive) +VTABLE_ENTRY(TMR3SetWarpDrive) +VTABLE_ENTRY(TMR3TimeVirtGet) +VTABLE_ENTRY(TMR3TimeVirtGetMicro) +VTABLE_ENTRY(TMR3TimeVirtGetMilli) +VTABLE_ENTRY(TMR3TimeVirtGetNano) + +VTABLE_RESERVED(pfnTMR3Reserved1) +VTABLE_RESERVED(pfnTMR3Reserved2) +VTABLE_RESERVED(pfnTMR3Reserved3) +VTABLE_RESERVED(pfnTMR3Reserved4) +VTABLE_RESERVED(pfnTMR3Reserved5) +/** @} */ diff --git a/include/VBox/vmm/vmmr3vtable.h b/include/VBox/vmm/vmmr3vtable.h new file mode 100644 index 00000000..96d88636 --- /dev/null +++ b/include/VBox/vmm/vmmr3vtable.h @@ -0,0 +1,140 @@ +/** @file + * VM - The Virtual Machine Monitor, VTable ring-3 API. + */ + +/* + * Copyright (C) 2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vmm_vmmr3vtable_h +#define VBOX_INCLUDED_vmm_vmmr3vtable_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +RT_C_DECLS_BEGIN + +/** @defgroup grp_vmm_vtable VMM Function Table + * @ingroup grp_vmm + * @{ */ + + +/** Magic and version for the VMM vtable. (Magic: Emmet Cohen) */ +#define VMMR3VTABLE_MAGIC_VERSION RT_MAKE_U64(0x19900525, 0x00030000) +/** Compatibility mask: These bits must match - magic and major version. */ +#define VMMR3VTABLE_MAGIC_VERSION_MASK RT_MAKE_U64(0xffffffff, 0xffff0000) + +/** Checks if @a a_uTableMagicVersion can be used by code compiled + * against @a a_CompiledMagicVersion */ +#define VMMR3VTABLE_IS_COMPATIBLE_EX(a_uTableMagicVersion, a_CompiledMagicVersion) \ + ( (a_uTableMagicVersion) >= (a_CompiledMagicVersion) /* table must be same or later version */ \ + && ((a_uTableMagicVersion) & VMMR3VTABLE_MAGIC_VERSION_MASK) == ((a_CompiledMagicVersion) & VMMR3VTABLE_MAGIC_VERSION_MASK) ) + +/** Checks if @a a_uTableMagicVersion can be used by this us. */ +#define VMMR3VTABLE_IS_COMPATIBLE(a_uTableMagicVersion) \ + VMMR3VTABLE_IS_COMPATIBLE_EX(a_uTableMagicVersion, VMMR3VTABLE_MAGIC_VERSION) + + +/** + * Function for getting the vtable of a VMM DLL/SO/DyLib. + * + * @returns the pointer to the vtable. + */ +typedef DECLCALLBACKTYPE(PCVMMR3VTABLE, FNVMMGETVTABLE,(void)); +/** Pointer to VMM vtable getter. */ +typedef FNVMMGETVTABLE *PFNVMMGETVTABLE; +/** The name of the FNVMMGETVTABLE function. */ +#define VMMR3VTABLE_GETTER_NAME "VMMR3GetVTable" + + +/** + * VTable for the ring-3 VMM API. + */ +typedef struct VMMR3VTABLE +{ + /** VMMR3VTABLE_MAGIC_VERSION. */ + uint64_t uMagicVersion; + /** Flags (TBD). */ + uint64_t fFlags; + /** The description of this VMM. */ + const char *pszDescription; + +/** @def VTABLE_ENTRY + * Define a VTable entry for the given function. */ +#if defined(DOXYGEN_RUNNING) \ + || (defined(__cplusplus) && (defined(__clang_major__) || RT_GNUC_PREREQ_EX(4, 8, /*non-gcc: */1) /* For 4.8+ we enable c++11 */)) +# define VTABLE_ENTRY(a_Api) /** @copydoc a_Api */ decltype(a_Api) *pfn ## a_Api; +#elif defined(__GNUC__) +# define VTABLE_ENTRY(a_Api) /** @copydoc a_Api */ typeof(a_Api) *pfn ## a_Api; +#else +# error "Unsupported compiler" +#endif +/** @def VTABLE_RESERVED + * Define a reserved VTable entry with the given name. */ +#define VTABLE_RESERVED(a_Name) DECLCALLBACKMEMBER(int, a_Name,(void)); + +#include "vmmr3vtable-def.h" + +#undef VTABLE_ENTRY +#undef VTABLE_RESERVED + + /** VMMR3VTABLE_MAGIC_VERSION. */ + uint64_t uMagicVersionEnd; +} VMMR3VTABLE; + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vmm_vmmr3vtable_h */ + diff --git a/include/VBox/vrdpusb.h b/include/VBox/vrdpusb.h new file mode 100644 index 00000000..54da45a6 --- /dev/null +++ b/include/VBox/vrdpusb.h @@ -0,0 +1,135 @@ +/** @file + * VBox Remote Desktop Protocol - Remote USB backend interface. (VRDP) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vrdpusb_h +#define VBOX_INCLUDED_vrdpusb_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +#ifdef IN_RING0 +# error "There are no VRDP APIs available in Ring-0 Host Context!" +#endif +#ifdef IN_RC +# error "There are no VRDP APIs available Guest Context!" +#endif + + +/** @defgroup grp_vrdpusb Remote USB over VURP + * @ingroup grp_vusb + * @{ + */ + +#define REMOTE_USB_BACKEND_PREFIX_S "REMOTEUSB" +#define REMOTE_USB_BACKEND_PREFIX_LEN 9 + +/* Forward declaration. */ +struct _REMOTEUSBDEVICE; +typedef struct _REMOTEUSBDEVICE *PREMOTEUSBDEVICE; + +/* Forward declaration. */ +struct _REMOTEUSBQURB; +typedef struct _REMOTEUSBQURB *PREMOTEUSBQURB; + +/* Forward declaration. Actually a class. */ +struct _REMOTEUSBBACKEND; +typedef struct _REMOTEUSBBACKEND *PREMOTEUSBBACKEND; + +/** + * Pointer to this structure is queried from USBREMOTEIF::pfnQueryRemoteUsbBackend. + */ +typedef struct REMOTEUSBCALLBACK +{ + PREMOTEUSBBACKEND pInstance; + + DECLCALLBACKMEMBER(int, pfnOpen,(PREMOTEUSBBACKEND pInstance, const char *pszAddress, size_t cbAddress, PREMOTEUSBDEVICE *ppDevice)); + DECLCALLBACKMEMBER(void, pfnClose,(PREMOTEUSBDEVICE pDevice)); + DECLCALLBACKMEMBER(int, pfnReset,(PREMOTEUSBDEVICE pDevice)); + DECLCALLBACKMEMBER(int, pfnSetConfig,(PREMOTEUSBDEVICE pDevice, uint8_t u8Cfg)); + DECLCALLBACKMEMBER(int, pfnClaimInterface,(PREMOTEUSBDEVICE pDevice, uint8_t u8Ifnum)); + DECLCALLBACKMEMBER(int, pfnReleaseInterface,(PREMOTEUSBDEVICE pDevice, uint8_t u8Ifnum)); + DECLCALLBACKMEMBER(int, pfnInterfaceSetting,(PREMOTEUSBDEVICE pDevice, uint8_t u8Ifnum, uint8_t u8Setting)); + DECLCALLBACKMEMBER(int, pfnQueueURB,(PREMOTEUSBDEVICE pDevice, uint8_t u8Type, uint8_t u8Ep, uint8_t u8Direction, uint32_t u32Len, void *pvData, void *pvURB, PREMOTEUSBQURB *ppRemoteURB)); + DECLCALLBACKMEMBER(int, pfnReapURB,(PREMOTEUSBDEVICE pDevice, uint32_t u32Millies, void **ppvURB, uint32_t *pu32Len, uint32_t *pu32Err)); + DECLCALLBACKMEMBER(int, pfnClearHaltedEP,(PREMOTEUSBDEVICE pDevice, uint8_t u8Ep)); + DECLCALLBACKMEMBER(void, pfnCancelURB,(PREMOTEUSBDEVICE pDevice, PREMOTEUSBQURB pRemoteURB)); + DECLCALLBACKMEMBER(int, pfnWakeup,(PREMOTEUSBDEVICE pDevice)); +} REMOTEUSBCALLBACK; +/** Pointer to a remote USB callback table. */ +typedef REMOTEUSBCALLBACK *PREMOTEUSBCALLBACK; + +/** + * Remote USB interface for querying the remote USB callback table for particular client. + * Returned from the *QueryGenericUserObject when passing REMOTEUSBIF_OID as the identifier. + */ +typedef struct REMOTEUSBIF +{ + /** Opaque user data to pass as the first parameter to the callbacks. */ + void *pvUser; + + /** + * Queries the remote USB interface callback table for a given UUID/client ID pair. + * + * @returns Pointer to the remote USB callback table or NULL if the client ID and or UUID is invalid. + * @param pvUser Opaque user data from this interface. + * @param pUuid The device UUID to query the interface for. + * @param idClient The client ID to query the interface for. + */ + DECLCALLBACKMEMBER(PREMOTEUSBCALLBACK, pfnQueryRemoteUsbBackend, (void *pvUser, PCRTUUID pUuid, uint32_t idClient)); +} REMOTEUSBIF; +/** Pointer to a remote USB interface. */ +typedef REMOTEUSBIF *PREMOTEUSBIF; + +/** The UUID to identify the remote USB interface. */ +#define REMOTEUSBIF_OID "87012f58-2ad6-4f89-b7b1-92f72c7ea8cc" + + +typedef struct EMULATEDUSBIF +{ + /** Opaque user data to pass as the first parameter to the callbacks. */ + void *pvUser; + + DECLCALLBACKMEMBER(int, pfnQueryEmulatedUsbDataById, (void *pvUser, const char *pszId, void **ppvEmUsbCb, void **ppvEmUsbCbData, void **ppvObject)); +} EMULATEDUSBIF; +typedef EMULATEDUSBIF *PEMULATEDUSBIF; + +#define EMULATEDUSBIF_OID "b7b4e194-ada0-4722-8e4e-1700ed9064f3" + +/** @} */ + +#endif /* !VBOX_INCLUDED_vrdpusb_h */ diff --git a/include/VBox/vscsi.h b/include/VBox/vscsi.h new file mode 100644 index 00000000..dea697e2 --- /dev/null +++ b/include/VBox/vscsi.h @@ -0,0 +1,488 @@ +/* $Id: vscsi.h $ */ +/** @file + * VBox storage drivers - Virtual SCSI driver + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vscsi_h +#define VBOX_INCLUDED_vscsi_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include +#include + +RT_C_DECLS_BEGIN + +#ifdef IN_RING0 +# error "There are no VBox VSCSI APIs available in Ring-0 Host Context!" +#endif + +/** @defgroup grp_drv_vscsi Virtual VSCSI Driver + * @ingroup grp_devdrv + * @{ + */ +/** @todo figure better grouping. */ + +/** A virtual SCSI device handle */ +typedef struct VSCSIDEVICEINT *VSCSIDEVICE; +/** A pointer to a virtual SCSI device handle. */ +typedef VSCSIDEVICE *PVSCSIDEVICE; +/** A virtual SCSI LUN handle. */ +typedef struct VSCSILUNINT *VSCSILUN; +/** A pointer to a virtual SCSI LUN handle. */ +typedef VSCSILUN *PVSCSILUN; +/** A virtual SCSI request handle. */ +typedef struct VSCSIREQINT *VSCSIREQ; +/** A pointer to a virtual SCSI request handle. */ +typedef VSCSIREQ *PVSCSIREQ; +/** A SCSI I/O request handle. */ +typedef struct VSCSIIOREQINT *VSCSIIOREQ; +/** A pointer to a SCSI I/O request handle. */ +typedef VSCSIIOREQ *PVSCSIIOREQ; + +/** + * Virtual SCSI I/O request transfer direction. + */ +typedef enum VSCSIIOREQTXDIR +{ + /** Invalid direction */ + VSCSIIOREQTXDIR_INVALID = 0, + /** Read */ + VSCSIIOREQTXDIR_READ, + /** Write */ + VSCSIIOREQTXDIR_WRITE, + /** Flush */ + VSCSIIOREQTXDIR_FLUSH, + /** Unmap */ + VSCSIIOREQTXDIR_UNMAP, + /** 32bit hack */ + VSCSIIOREQTXDIR_32BIT_HACK = 0x7fffffff +} VSCSIIOREQTXDIR; +/** Pointer to a SCSI LUN type */ +typedef VSCSIIOREQTXDIR *PVSCSIIOREQTXDIR; + +/** + * Virtual SCSI transfer direction as seen from the initiator. + */ +typedef enum VSCSIXFERDIR +{ + /** Invalid data direction. */ + PVSCSIXFERDIR_INVALID = 0, + /** Direction is unknown. */ + VSCSIXFERDIR_UNKNOWN, + /** Direction is from target to initiator (aka a read). */ + VSCSIXFERDIR_T2I, + /** Direction is from initiator to device (aka a write). */ + VSCSIXFERDIR_I2T, + /** No data transfer associated with this request. */ + VSCSIXFERDIR_NONE, + /** 32bit hack. */ + VSCSIXFERDIR_32BIT_HACK = 0x7fffffff +} VSCSIXFERDIR; + +/** + * LUN types we support + */ +typedef enum VSCSILUNTYPE +{ + /** Invalid type */ + VSCSILUNTYPE_INVALID = 0, + /** Hard disk (SBC) */ + VSCSILUNTYPE_SBC, + /** CD/DVD drive (MMC) */ + VSCSILUNTYPE_MMC, + /** Tape drive (SSC) */ + VSCSILUNTYPE_SSC, + /** Last value to indicate an invalid device */ + VSCSILUNTYPE_LAST, + /** 32bit hack */ + VSCSILUNTYPE_32BIT_HACK = 0x7fffffff +} VSCSILUNTYPE; +/** Pointer to a SCSI LUN type */ +typedef VSCSILUNTYPE *PVSCSILUNTYPE; + +/** The LUN can handle the UNMAP command. */ +#define VSCSI_LUN_FEATURE_UNMAP RT_BIT(0) +/** The LUN has a non rotational medium. */ +#define VSCSI_LUN_FEATURE_NON_ROTATIONAL RT_BIT(1) +/** The medium of the LUN is readonly. */ +#define VSCSI_LUN_FEATURE_READONLY RT_BIT(2) + +/** + * Virtual SCSI LUN I/O Callback table. + */ +typedef struct VSCSILUNIOCALLBACKS +{ + /** + * Sets the size of the allocator specific memory for a I/O request. + * + * @returns VBox status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param cbVScsiIoReqAlloc The size of the allocator specific memory in bytes. + * @thread EMT. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunReqAllocSizeSet, (VSCSILUN hVScsiLun, void *pvScsiLunUser, + size_t cbVScsiIoReqAlloc)); + + /** + * Allocates a new I/O request. + * + * @returns VBox status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param u64Tag A tag to assign to the request handle for identification later on. + * @param phVScsiIoReq Where to store the handle to the allocated I/O request on success. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunReqAlloc, (VSCSILUN hVScsiLun, void *pvScsiLunUser, + uint64_t u64Tag, PVSCSIIOREQ phVScsiIoReq)); + + /** + * Frees a given I/O request. + * + * @returns VBox status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param hVScsiIoReq The VSCSI I/O request to free. + * @thread Any thread. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunReqFree, (VSCSILUN hVScsiLun, void *pvScsiLunUser, VSCSIIOREQ hVScsiIoReq)); + + /** + * Returns the number of regions for the medium. + * + * @returns Number of regions. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnVScsiLunMediumGetRegionCount,(VSCSILUN hVScsiLun, void *pvScsiLunUser)); + + /** + * Queries the properties for the given region. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the region index is not known. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param uRegion The region index to query the properties of. + * @param pu64LbaStart Where to store the starting LBA for the region on success. + * @param pcBlocks Where to store the number of blocks for the region on success. + * @param pcbBlock Where to store the size of one block in bytes on success. + * @param penmDataForm WHere to store the data form for the region on success. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunMediumQueryRegionProperties,(VSCSILUN hVScsiLun, void *pvScsiLunUser, + uint32_t uRegion, uint64_t *pu64LbaStart, + uint64_t *pcBlocks, uint64_t *pcbBlock, + PVDREGIONDATAFORM penmDataForm)); + + /** + * Queries the properties for the region covering the given LBA. + * + * @returns VBox status code. + * @retval VERR_NOT_FOUND if the region index is not known. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param u64LbaStart Where to store the starting LBA for the region on success. + * @param puRegion Where to store the region number on success. + * @param pcBlocks Where to store the number of blocks left in this region starting from the given LBA. + * @param pcbBlock Where to store the size of one block in bytes on success. + * @param penmDataForm WHere to store the data form for the region on success. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunMediumQueryRegionPropertiesForLba,(VSCSILUN hVScsiLun, void *pvScsiLunUser, + uint64_t u64LbaStart, uint32_t *puRegion, + uint64_t *pcBlocks, uint64_t *pcbBlock, + PVDREGIONDATAFORM penmDataForm)); + + /** + * Set the lock state of the underlying medium. + * + * @returns VBox status status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param fLocked New lock state (locked/unlocked). + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunMediumSetLock,(VSCSILUN hVScsiLun, void *pvScsiLunUser, bool fLocked)); + + /** + * Eject the attached medium. + * + * @returns VBox status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunMediumEject, (VSCSILUN hVScsiLun, void *pvScsiLunUser)); + + /** + * Enqueue a read or write request from the medium. + * + * @returns VBox status status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param hVScsiIoReq Virtual SCSI I/O request handle. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunReqTransferEnqueue,(VSCSILUN hVScsiLun, void *pvScsiLunUser, VSCSIIOREQ hVScsiIoReq)); + + /** + * Returns flags of supported features. + * + * @returns VBox status status code. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param pfFeatures Where to return the queried features. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunGetFeatureFlags,(VSCSILUN hVScsiLun, void *pvScsiLunUser, uint64_t *pfFeatures)); + + /** + * Queries the vendor and product ID and revision to report for INQUIRY commands of the given LUN. + * + * @returns VBox status status code. + * @retval VERR_NOT_FOUND if the data is not available and some defaults should be sued instead. + * @param hVScsiLun Virtual SCSI LUN handle. + * @param pvScsiLunUser Opaque user data which may be used to identify the + * medium. + * @param ppszVendorId Where to store the pointer to the vendor ID string to report. + * @param ppszProductId Where to store the pointer to the product ID string to report. + * @param ppszProductLevel Where to store the pointer to the product level string to report. + */ + DECLR3CALLBACKMEMBER(int, pfnVScsiLunQueryInqStrings, (VSCSILUN hVScsiLun, void *pvScsiLunUser, const char **ppszVendorId, + const char **ppszProductId, const char **ppszProductLevel)); + +} VSCSILUNIOCALLBACKS; +/** Pointer to a virtual SCSI LUN I/O callback table. */ +typedef VSCSILUNIOCALLBACKS *PVSCSILUNIOCALLBACKS; + +/** + * The virtual SCSI request completed callback. + */ +typedef DECLCALLBACKTYPE(void, FNVSCSIREQCOMPLETED,(VSCSIDEVICE hVScsiDevice, + void *pvVScsiDeviceUser, + void *pvVScsiReqUser, + int rcScsiCode, + bool fRedoPossible, + int rcReq, + size_t cbXfer, + VSCSIXFERDIR enmXferDir, + size_t cbSense)); +/** Pointer to a virtual SCSI request completed callback. */ +typedef FNVSCSIREQCOMPLETED *PFNVSCSIREQCOMPLETED; + +/** + * Create a new empty SCSI device instance. + * + * @returns VBox status code. + * @param phVScsiDevice Where to store the SCSI device handle. + * @param pfnVScsiReqCompleted The method call after a request completed. + * @param pvVScsiDeviceUser Opaque user data given in the completion callback. + */ +VBOXDDU_DECL(int) VSCSIDeviceCreate(PVSCSIDEVICE phVScsiDevice, + PFNVSCSIREQCOMPLETED pfnVScsiReqCompleted, + void *pvVScsiDeviceUser); + +/** + * Destroy a SCSI device instance. + * + * @returns VBox status code. + * @param hVScsiDevice The SCSI device handle to destroy. + */ +VBOXDDU_DECL(int) VSCSIDeviceDestroy(VSCSIDEVICE hVScsiDevice); + +/** + * Attach a LUN to the SCSI device. + * + * @returns VBox status code. + * @param hVScsiDevice The SCSI device handle to add the LUN to. + * @param hVScsiLun The LUN handle to add. + * @param iLun The LUN number. + */ +VBOXDDU_DECL(int) VSCSIDeviceLunAttach(VSCSIDEVICE hVScsiDevice, VSCSILUN hVScsiLun, uint32_t iLun); + +/** + * Detach a LUN from the SCSI device. + * + * @returns VBox status code. + * @param hVScsiDevice The SCSI device handle to add the LUN to. + * @param iLun The LUN number to remove. + * @param phVScsiLun Where to store the detached LUN handle. + */ +VBOXDDU_DECL(int) VSCSIDeviceLunDetach(VSCSIDEVICE hVScsiDevice, uint32_t iLun, + PVSCSILUN phVScsiLun); + +/** + * Query the SCSI LUN type. + * + * @returns VBox status code. + * @param hVScsiDevice The SCSI device handle. + * @param iLun The LUN number to get. + * @param pEnmLunType Where to store the LUN type. + */ +VBOXDDU_DECL(int) VSCSIDeviceLunQueryType(VSCSIDEVICE hVScsiDevice, uint32_t iLun, + PVSCSILUNTYPE pEnmLunType); + +/** + * Enqueue a request to the SCSI device. + * + * @returns VBox status code. + * @param hVScsiDevice The SCSI device handle. + * @param hVScsiReq The SCSI request handle to enqueue. + */ +VBOXDDU_DECL(int) VSCSIDeviceReqEnqueue(VSCSIDEVICE hVScsiDevice, VSCSIREQ hVScsiReq); + +/** + * Allocate a new request handle. + * + * @returns VBox status code. + * @param hVScsiDevice The SCSI device handle. + * @param phVScsiReq Where to SCSI request handle. + * @param iLun The LUN the request is for. + * @param pbCDB The CDB for the request. + * @param cbCDB The size of the CDB in bytes. + * @param cbSGList Number of bytes the S/G list describes. + * @param cSGListEntries Number of S/G list entries. + * @param paSGList Pointer to the S/G list. + * @param pbSense Pointer to the sense buffer. + * @param cbSense Size of the sense buffer. + * @param pvVScsiReqUser Opqaue user data returned when the request completes. + */ +VBOXDDU_DECL(int) VSCSIDeviceReqCreate(VSCSIDEVICE hVScsiDevice, PVSCSIREQ phVScsiReq, + uint32_t iLun, uint8_t *pbCDB, size_t cbCDB, + size_t cbSGList, unsigned cSGListEntries, + PCRTSGSEG paSGList, uint8_t *pbSense, + size_t cbSense, void *pvVScsiReqUser); + +/** + * Create a new LUN. + * + * @returns VBox status code. + * @param phVScsiLun Where to store the SCSI LUN handle. + * @param enmLunType The Lun type. + * @param pVScsiLunIoCallbacks Pointer to the I/O callbacks to use for his LUN. + * @param pvVScsiLunUser Opaque user argument which + * is returned in the pvScsiLunUser parameter + * when the request completion callback is called. + */ +VBOXDDU_DECL(int) VSCSILunCreate(PVSCSILUN phVScsiLun, VSCSILUNTYPE enmLunType, + PVSCSILUNIOCALLBACKS pVScsiLunIoCallbacks, + void *pvVScsiLunUser); + +/** + * Destroy virtual SCSI LUN. + * + * @returns VBox status code. + * @param hVScsiLun The virtual SCSI LUN handle to destroy. + */ +VBOXDDU_DECL(int) VSCSILunDestroy(VSCSILUN hVScsiLun); + +/** + * Notify virtual SCSI LUN of medium being mounted. + * + * @returns VBox status code. + * @param hVScsiLun The virtual SCSI LUN handle to destroy. + */ +VBOXDDU_DECL(int) VSCSILunMountNotify(VSCSILUN hVScsiLun); + +/** + * Notify virtual SCSI LUN of medium being unmounted. + * + * @returns VBox status code. + * @param hVScsiLun The virtual SCSI LUN handle to destroy. + */ +VBOXDDU_DECL(int) VSCSILunUnmountNotify(VSCSILUN hVScsiLun); + +/** + * Notify a that a I/O request completed. + * + * @returns VBox status code. + * @param hVScsiIoReq The I/O request handle that completed. + * This is given when a I/O callback for + * the LUN is called by the virtual SCSI layer. + * @param rcIoReq The status code the I/O request completed with. + * @param fRedoPossible Flag whether it is possible to redo the request. + * If true setting any sense code will be omitted + * in case of an error to not alter the device state. + */ +VBOXDDU_DECL(int) VSCSIIoReqCompleted(VSCSIIOREQ hVScsiIoReq, int rcIoReq, bool fRedoPossible); + +/** + * Query the transfer direction of the I/O request. + * + * @returns Transfer direction.of the given I/O request + * @param hVScsiIoReq The SCSI I/O request handle. + */ +VBOXDDU_DECL(VSCSIIOREQTXDIR) VSCSIIoReqTxDirGet(VSCSIIOREQ hVScsiIoReq); + +/** + * Query I/O parameters. + * + * @returns VBox status code. + * @param hVScsiIoReq The SCSI I/O request handle. + * @param puOffset Where to store the start offset. + * @param pcbTransfer Where to store the amount of bytes to transfer. + * @param pcSeg Where to store the number of segments in the S/G list. + * @param pcbSeg Where to store the number of bytes the S/G list describes. + * @param ppaSeg Where to store the pointer to the S/G list. + */ +VBOXDDU_DECL(int) VSCSIIoReqParamsGet(VSCSIIOREQ hVScsiIoReq, uint64_t *puOffset, + size_t *pcbTransfer, unsigned *pcSeg, + size_t *pcbSeg, PCRTSGSEG *ppaSeg); + +/** + * Query unmap parameters. + * + * @returns VBox status code. + * @param hVScsiIoReq The SCSI I/O request handle. + * @param ppaRanges Where to store the pointer to the range array on success. + * @param pcRanges Where to store the number of ranges on success. + */ +VBOXDDU_DECL(int) VSCSIIoReqUnmapParamsGet(VSCSIIOREQ hVScsiIoReq, PCRTRANGE *ppaRanges, + unsigned *pcRanges); + +/** @} */ +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vscsi_h */ + diff --git a/include/VBox/vusb.h b/include/VBox/vusb.h new file mode 100644 index 00000000..95ae9b0a --- /dev/null +++ b/include/VBox/vusb.h @@ -0,0 +1,1472 @@ +/** @file + * VUSB - VirtualBox USB. (DEV,VMM) + */ + +/* + * Copyright (C) 2006-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_vusb_h +#define VBOX_INCLUDED_vusb_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include +#include + +struct PDMLED; + +RT_C_DECLS_BEGIN + +/** @defgroup grp_vusb VBox USB API + * @{ + */ + +/** @defgroup grp_vusb_std Standard Stuff + * @{ */ + +/** Frequency of USB bus (from spec). */ +#define VUSB_BUS_HZ 12000000 + + +/** @name USB Descriptor types (from spec) + * @{ */ +#define VUSB_DT_DEVICE 0x01 +#define VUSB_DT_CONFIG 0x02 +#define VUSB_DT_STRING 0x03 +#define VUSB_DT_INTERFACE 0x04 +#define VUSB_DT_ENDPOINT 0x05 +#define VUSB_DT_DEVICE_QUALIFIER 0x06 +#define VUSB_DT_OTHER_SPEED_CFG 0x07 +#define VUSB_DT_INTERFACE_POWER 0x08 +#define VUSB_DT_INTERFACE_ASSOCIATION 0x0B +#define VUSB_DT_BOS 0x0F +#define VUSB_DT_DEVICE_CAPABILITY 0x10 +#define VUSB_DT_SS_ENDPOINT_COMPANION 0x30 +/** @} */ + +/** @name USB Descriptor minimum sizes (from spec) + * @{ */ +#define VUSB_DT_DEVICE_MIN_LEN 18 +#define VUSB_DT_CONFIG_MIN_LEN 9 +#define VUSB_DT_CONFIG_STRING_MIN_LEN 2 +#define VUSB_DT_INTERFACE_MIN_LEN 9 +#define VUSB_DT_ENDPOINT_MIN_LEN 7 +#define VUSB_DT_SSEP_COMPANION_MIN_LEN 6 +/** @} */ + +/** @name USB Device Capability Type Codes (from spec) + * @{ */ +#define VUSB_DCT_WIRELESS_USB 0x01 +#define VUSB_DCT_USB_20_EXTENSION 0x02 +#define VUSB_DCT_SUPERSPEED_USB 0x03 +#define VUSB_DCT_CONTAINER_ID 0x04 +/** @} */ + + +#pragma pack(1) /* ensure byte packing of the descriptors. */ + +/** + * USB language id descriptor (from specs). + */ +typedef struct VUSBDESCLANGID +{ + uint8_t bLength; + uint8_t bDescriptorType; +} VUSBDESCLANGID; +/** Pointer to a USB language id descriptor. */ +typedef VUSBDESCLANGID *PVUSBDESCLANGID; +/** Pointer to a const USB language id descriptor. */ +typedef const VUSBDESCLANGID *PCVUSBDESCLANGID; + + +/** + * USB string descriptor (from specs). + */ +typedef struct VUSBDESCSTRING +{ + uint8_t bLength; + uint8_t bDescriptorType; +} VUSBDESCSTRING; +/** Pointer to a USB string descriptor. */ +typedef VUSBDESCSTRING *PVUSBDESCSTRING; +/** Pointer to a const USB string descriptor. */ +typedef const VUSBDESCSTRING *PCVUSBDESCSTRING; + + +/** + * USB device descriptor (from spec) + */ +typedef struct VUSBDESCDEVICE +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUSB; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint16_t idVendor; + uint16_t idProduct; + uint16_t bcdDevice; + uint8_t iManufacturer; + uint8_t iProduct; + uint8_t iSerialNumber; + uint8_t bNumConfigurations; +} VUSBDESCDEVICE; +/** Pointer to a USB device descriptor. */ +typedef VUSBDESCDEVICE *PVUSBDESCDEVICE; +/** Pointer to a const USB device descriptor. */ +typedef const VUSBDESCDEVICE *PCVUSBDESCDEVICE; + +/** + * USB device qualifier (from spec 9.6.2) + */ +struct VUSBDEVICEQUALIFIER +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t bcdUsb; + uint8_t bDeviceClass; + uint8_t bDeviceSubClass; + uint8_t bDeviceProtocol; + uint8_t bMaxPacketSize0; + uint8_t bNumConfigurations; + uint8_t bReserved; +}; + +typedef struct VUSBDEVICEQUALIFIER VUSBDEVICEQUALIFIER; +typedef VUSBDEVICEQUALIFIER *PVUSBDEVICEQUALIFIER; + + +/** + * USB configuration descriptor (from spec). + */ +typedef struct VUSBDESCCONFIG +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; /**< recalculated by VUSB when involved in URB. */ + uint8_t bNumInterfaces; + uint8_t bConfigurationValue; + uint8_t iConfiguration; + uint8_t bmAttributes; + uint8_t MaxPower; +} VUSBDESCCONFIG; +/** Pointer to a USB configuration descriptor. */ +typedef VUSBDESCCONFIG *PVUSBDESCCONFIG; +/** Pointer to a readonly USB configuration descriptor. */ +typedef const VUSBDESCCONFIG *PCVUSBDESCCONFIG; + + +/** + * USB interface association descriptor (from USB ECN Interface Association Descriptors) + */ +typedef struct VUSBDESCIAD +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bFirstInterface; + uint8_t bInterfaceCount; + uint8_t bFunctionClass; + uint8_t bFunctionSubClass; + uint8_t bFunctionProtocol; + uint8_t iFunction; +} VUSBDESCIAD; +/** Pointer to a USB interface association descriptor. */ +typedef VUSBDESCIAD *PVUSBDESCIAD; +/** Pointer to a readonly USB interface association descriptor. */ +typedef const VUSBDESCIAD *PCVUSBDESCIAD; + + +/** + * USB interface descriptor (from spec) + */ +typedef struct VUSBDESCINTERFACE +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bInterfaceNumber; + uint8_t bAlternateSetting; + uint8_t bNumEndpoints; + uint8_t bInterfaceClass; + uint8_t bInterfaceSubClass; + uint8_t bInterfaceProtocol; + uint8_t iInterface; +} VUSBDESCINTERFACE; +/** Pointer to a USB interface descriptor. */ +typedef VUSBDESCINTERFACE *PVUSBDESCINTERFACE; +/** Pointer to a const USB interface descriptor. */ +typedef const VUSBDESCINTERFACE *PCVUSBDESCINTERFACE; + + +/** + * USB endpoint descriptor (from spec) + */ +typedef struct VUSBDESCENDPOINT +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bEndpointAddress; + uint8_t bmAttributes; + uint16_t wMaxPacketSize; + uint8_t bInterval; +} VUSBDESCENDPOINT; +/** Pointer to a USB endpoint descriptor. */ +typedef VUSBDESCENDPOINT *PVUSBDESCENDPOINT; +/** Pointer to a const USB endpoint descriptor. */ +typedef const VUSBDESCENDPOINT *PCVUSBDESCENDPOINT; + + +/** + * USB SuperSpeed endpoint companion descriptor (from USB3 spec) + */ +typedef struct VUSBDESCSSEPCOMPANION +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bMaxBurst; + uint8_t bmAttributes; + uint16_t wBytesPerInterval; +} VUSBDESCSSEPCOMPANION; +/** Pointer to a USB endpoint companion descriptor. */ +typedef VUSBDESCSSEPCOMPANION *PVUSBDESCSSEPCOMPANION; +/** Pointer to a const USB endpoint companion descriptor. */ +typedef const VUSBDESCSSEPCOMPANION *PCVUSBDESCSSEPCOMPANION; + + +/** + * USB Binary Device Object Store, aka BOS (from USB3 spec) + */ +typedef struct VUSBDESCBOS +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint16_t wTotalLength; + uint8_t bNumDeviceCaps; +} VUSBDESCBOS; +/** Pointer to a USB BOS descriptor. */ +typedef VUSBDESCBOS *PVUSBDESCBOS; +/** Pointer to a const USB BOS descriptor. */ +typedef const VUSBDESCBOS *PCVUSBDESCBOS; + + +/** + * Generic USB Device Capability Descriptor within BOS (from USB3 spec) + */ +typedef struct VUSBDESCDEVICECAP +{ + uint8_t bLength; + uint8_t bDescriptorType; + uint8_t bDevCapabilityType; + uint8_t aCapSpecific[1]; +} VUSBDESCDEVICECAP; +/** Pointer to a USB device capability descriptor. */ +typedef VUSBDESCDEVICECAP *PVUSBDESCDEVICECAP; +/** Pointer to a const USB device capability descriptor. */ +typedef const VUSBDESCDEVICECAP *PCVUSBDESCDEVICECAP; + + +/** + * SuperSpeed USB Device Capability Descriptor within BOS + */ +typedef struct VUSBDESCSSDEVCAP +{ + uint8_t bLength; + uint8_t bDescriptorType; /* DEVICE CAPABILITY */ + uint8_t bDevCapabilityType; /* SUPERSPEED_USB */ + uint8_t bmAttributes; + uint16_t wSpeedsSupported; + uint8_t bFunctionalitySupport; + uint8_t bU1DevExitLat; + uint16_t wU2DevExitLat; +} VUSBDESCSSDEVCAP; +/** Pointer to an SS USB device capability descriptor. */ +typedef VUSBDESCSSDEVCAP *PVUSBDESCSSDEVCAP; +/** Pointer to a const SS USB device capability descriptor. */ +typedef const VUSBDESCSSDEVCAP *PCVUSBDESCSSDEVCAP; + + +/** + * USB 2.0 Extension Descriptor within BOS + */ +typedef struct VUSBDESCUSB2EXT +{ + uint8_t bLength; + uint8_t bDescriptorType; /* DEVICE CAPABILITY */ + uint8_t bDevCapabilityType; /* USB 2.0 EXTENSION */ + uint8_t bmAttributes; +} VUSBDESCUSB2EXT; +/** Pointer to a USB 2.0 extension capability descriptor. */ +typedef VUSBDESCUSB2EXT *PVUSBDESCUSB2EXT; +/** Pointer to a const USB 2.0 extension capability descriptor. */ +typedef const VUSBDESCUSB2EXT *PCVUSBDESCUSB2EXT; + + +#pragma pack() /* end of the byte packing. */ + + +/** + * USB configuration descriptor, the parsed variant used by VUSB. + */ +typedef struct VUSBDESCCONFIGEX +{ + /** The USB descriptor data. + * @remark The wTotalLength member is recalculated before the data is passed to the guest. */ + VUSBDESCCONFIG Core; + /** Pointer to additional descriptor bytes following what's covered by VUSBDESCCONFIG. */ + void *pvMore; + /** Pointer to additional class- or vendor-specific interface descriptors. */ + const void *pvClass; + /** Size of class- or vendor-specific descriptors. */ + uint16_t cbClass; + /** Pointer to an array of the interfaces referenced in the configuration. + * Core.bNumInterfaces in size. */ + const struct VUSBINTERFACE *paIfs; + /** Pointer to the original descriptor data read from the device. */ + const void *pvOriginal; +} VUSBDESCCONFIGEX; +/** Pointer to a parsed USB configuration descriptor. */ +typedef VUSBDESCCONFIGEX *PVUSBDESCCONFIGEX; +/** Pointer to a const parsed USB configuration descriptor. */ +typedef const VUSBDESCCONFIGEX *PCVUSBDESCCONFIGEX; + + +/** + * For tracking the alternate interface settings of a configuration. + */ +typedef struct VUSBINTERFACE +{ + /** Pointer to an array of interfaces. */ + const struct VUSBDESCINTERFACEEX *paSettings; + /** The number of entries in the array. */ + uint32_t cSettings; +} VUSBINTERFACE; +/** Pointer to a VUSBINTERFACE. */ +typedef VUSBINTERFACE *PVUSBINTERFACE; +/** Pointer to a const VUSBINTERFACE. */ +typedef const VUSBINTERFACE *PCVUSBINTERFACE; + + +/** + * USB interface descriptor, the parsed variant used by VUSB. + */ +typedef struct VUSBDESCINTERFACEEX +{ + /** The USB descriptor data. */ + VUSBDESCINTERFACE Core; + /** Pointer to additional descriptor bytes following what's covered by VUSBDESCINTERFACE. */ + const void *pvMore; + /** Pointer to additional class- or vendor-specific interface descriptors. */ + const void *pvClass; + /** Size of class- or vendor-specific descriptors. */ + uint16_t cbClass; + /** Pointer to an array of the endpoints referenced by the interface. + * Core.bNumEndpoints in size. */ + const struct VUSBDESCENDPOINTEX *paEndpoints; + /** Interface association descriptor, which prepends a group of interfaces, + * starting with this interface. */ + PCVUSBDESCIAD pIAD; + /** Size of interface association descriptor. */ + uint16_t cbIAD; +} VUSBDESCINTERFACEEX; +/** Pointer to an prased USB interface descriptor. */ +typedef VUSBDESCINTERFACEEX *PVUSBDESCINTERFACEEX; +/** Pointer to a const parsed USB interface descriptor. */ +typedef const VUSBDESCINTERFACEEX *PCVUSBDESCINTERFACEEX; + + +/** + * USB endpoint descriptor, the parsed variant used by VUSB. + */ +typedef struct VUSBDESCENDPOINTEX +{ + /** The USB descriptor data. + * @remark The wMaxPacketSize member is converted to native endian. */ + VUSBDESCENDPOINT Core; + /** Pointer to additional descriptor bytes following what's covered by VUSBDESCENDPOINT. */ + const void *pvMore; + /** Pointer to additional class- or vendor-specific endpoint descriptors. */ + const void *pvClass; + /** Size of class- or vendor-specific descriptors. */ + uint16_t cbClass; + /** Pointer to SuperSpeed endpoint companion descriptor (SS endpoints only). */ + const void *pvSsepc; + /** Size of SuperSpeed endpoint companion descriptor. + * @remark Must be non-zero for SuperSpeed endpoints. */ + uint16_t cbSsepc; +} VUSBDESCENDPOINTEX; +/** Pointer to a parsed USB endpoint descriptor. */ +typedef VUSBDESCENDPOINTEX *PVUSBDESCENDPOINTEX; +/** Pointer to a const parsed USB endpoint descriptor. */ +typedef const VUSBDESCENDPOINTEX *PCVUSBDESCENDPOINTEX; + + +/** @name USB Control message recipient codes (from spec) + * @{ */ +#define VUSB_TO_DEVICE 0x0 +#define VUSB_TO_INTERFACE 0x1 +#define VUSB_TO_ENDPOINT 0x2 +#define VUSB_TO_OTHER 0x3 +#define VUSB_RECIP_MASK 0x1f +/** @} */ + +/** @name USB control pipe setup packet structure (from spec) + * @{ */ +#define VUSB_REQ_SHIFT (5) +#define VUSB_REQ_STANDARD (0x0 << VUSB_REQ_SHIFT) +#define VUSB_REQ_CLASS (0x1 << VUSB_REQ_SHIFT) +#define VUSB_REQ_VENDOR (0x2 << VUSB_REQ_SHIFT) +#define VUSB_REQ_RESERVED (0x3 << VUSB_REQ_SHIFT) +#define VUSB_REQ_MASK (0x3 << VUSB_REQ_SHIFT) +/** @} */ + +#define VUSB_DIR_TO_DEVICE 0x00 +#define VUSB_DIR_TO_HOST 0x80 +#define VUSB_DIR_MASK 0x80 + +/** + * USB Setup request (from spec) + */ +typedef struct vusb_setup +{ + uint8_t bmRequestType; + uint8_t bRequest; + uint16_t wValue; + uint16_t wIndex; + uint16_t wLength; +} VUSBSETUP; +/** Pointer to a setup request. */ +typedef VUSBSETUP *PVUSBSETUP; +/** Pointer to a const setup request. */ +typedef const VUSBSETUP *PCVUSBSETUP; + +/** @name USB Standard device requests (from spec) + * @{ */ +#define VUSB_REQ_GET_STATUS 0x00 +#define VUSB_REQ_CLEAR_FEATURE 0x01 +#define VUSB_REQ_SET_FEATURE 0x03 +#define VUSB_REQ_SET_ADDRESS 0x05 +#define VUSB_REQ_GET_DESCRIPTOR 0x06 +#define VUSB_REQ_SET_DESCRIPTOR 0x07 +#define VUSB_REQ_GET_CONFIGURATION 0x08 +#define VUSB_REQ_SET_CONFIGURATION 0x09 +#define VUSB_REQ_GET_INTERFACE 0x0a +#define VUSB_REQ_SET_INTERFACE 0x0b +#define VUSB_REQ_SYNCH_FRAME 0x0c +#define VUSB_REQ_MAX 0x0d +/** @} */ + +/** @} */ /* end of grp_vusb_std */ + + + +/** @name USB Standard version flags. + * @{ */ +/** Indicates USB 1.1 support. */ +#define VUSB_STDVER_11 RT_BIT(1) +/** Indicates USB 2.0 support. */ +#define VUSB_STDVER_20 RT_BIT(2) +/** Indicates USB 3.0 support. */ +#define VUSB_STDVER_30 RT_BIT(3) +/** @} */ + +/** + * USB port/device speeds. + */ +typedef enum VUSBSPEED +{ + /** Undetermined/unknown speed. */ + VUSB_SPEED_UNKNOWN = 0, + /** Low-speed (LS), 1.5 Mbit/s, USB 1.0. */ + VUSB_SPEED_LOW, + /** Full-speed (FS), 12 Mbit/s, USB 1.1. */ + VUSB_SPEED_FULL, + /** High-speed (HS), 480 Mbit/s, USB 2.0. */ + VUSB_SPEED_HIGH, + /** Variable speed, wireless USB 2.5. */ + VUSB_SPEED_VARIABLE, + /** SuperSpeed (SS), 5.0 Gbit/s, USB 3.0. */ + VUSB_SPEED_SUPER, + /** SuperSpeed+ (SS+), 10.0 Gbit/s, USB 3.1. */ + VUSB_SPEED_SUPERPLUS, + /** The usual 32-bit hack. */ + VUSB_SPEED_32BIT_HACK = 0x7fffffff +} VUSBSPEED; + +/** + * VUSB transfer direction. + */ +typedef enum VUSBDIRECTION +{ + /** Setup */ + VUSBDIRECTION_SETUP = 0, +#define VUSB_DIRECTION_SETUP VUSBDIRECTION_SETUP + /** In - Device to host. */ + VUSBDIRECTION_IN = 1, +#define VUSB_DIRECTION_IN VUSBDIRECTION_IN + /** Out - Host to device. */ + VUSBDIRECTION_OUT = 2, +#define VUSB_DIRECTION_OUT VUSBDIRECTION_OUT + /** Invalid direction */ + VUSBDIRECTION_INVALID = 0x7f +} VUSBDIRECTION; + +/** + * VUSB Transfer types. + */ +typedef enum VUSBXFERTYPE +{ + /** Control message. Used to represent a single control transfer. */ + VUSBXFERTYPE_CTRL = 0, + /* Isochronous transfer. */ + VUSBXFERTYPE_ISOC, + /** Bulk transfer. */ + VUSBXFERTYPE_BULK, + /** Interrupt transfer. */ + VUSBXFERTYPE_INTR, + /** Complete control message. Used to represent an entire control message. */ + VUSBXFERTYPE_MSG, + /** Invalid transfer type. */ + VUSBXFERTYPE_INVALID = 0x7f +} VUSBXFERTYPE; + +/** Number of valid USB transfer types - KEEP in sync with VUSBXFERTYPE!. */ +#define VUSBXFERTYPE_ELEMENTS (5) + +/** Pointer to a VBox USB device interface. */ +typedef struct VUSBIDEVICE *PVUSBIDEVICE; + +/** Pointer to a VUSB RootHub port interface. */ +typedef struct VUSBIROOTHUBPORT *PVUSBIROOTHUBPORT; + +/** Pointer to an USB request descriptor. */ +typedef struct VUSBURB *PVUSBURB; + + +/** + * VUSB device reset completion callback function. + * This is called by the reset thread when the reset has been completed. + * + * @param pDevice Pointer to the virtual USB device core. + * @param uPort The port of the device which completed the reset. + * @param rc The VBox status code of the reset operation. + * @param pvUser User specific argument. + * + * @thread The reset thread or EMT. + */ +typedef DECLCALLBACKTYPE(void, FNVUSBRESETDONE,(PVUSBIDEVICE pDevice, uint32_t uPort, int rc, void *pvUser)); +/** Pointer to a device reset completion callback function (FNUSBRESETDONE). */ +typedef FNVUSBRESETDONE *PFNVUSBRESETDONE; + + +/** + * The state of a VUSB Device. + * + * @remark The order of these states is vital. + */ +typedef enum VUSBDEVICESTATE +{ + VUSB_DEVICE_STATE_INVALID = 0, + VUSB_DEVICE_STATE_DETACHED, + VUSB_DEVICE_STATE_ATTACHED, + VUSB_DEVICE_STATE_POWERED, + VUSB_DEVICE_STATE_DEFAULT, + VUSB_DEVICE_STATE_ADDRESS, + VUSB_DEVICE_STATE_CONFIGURED, + VUSB_DEVICE_STATE_SUSPENDED, + /** The device is being reset. Don't mess with it. + * Next states: VUSB_DEVICE_STATE_DEFAULT, VUSB_DEVICE_STATE_DESTROYED + */ + VUSB_DEVICE_STATE_RESET, + /** The device has been destroyed. */ + VUSB_DEVICE_STATE_DESTROYED, + /** The usual 32-bit hack. */ + VUSB_DEVICE_STATE_32BIT_HACK = 0x7fffffff +} VUSBDEVICESTATE; + + +/** Maximum number of USB devices supported. */ +#define VUSB_DEVICES_MAX 128 +/** An invalid device port. */ +#define VUSB_DEVICE_PORT_INVALID UINT32_MAX + +/** + * VBox USB port bitmap. + * + * Bit 0 == Port 0, ... , Bit 127 == Port 127. + */ +typedef struct VUSBPORTBITMAP +{ + /** 128 bits */ + char ach[VUSB_DEVICES_MAX / 8]; +} VUSBPORTBITMAP; +/** Pointer to a VBox USB port bitmap. */ +typedef VUSBPORTBITMAP *PVUSBPORTBITMAP; +AssertCompile(sizeof(VUSBPORTBITMAP) * 8 >= VUSB_DEVICES_MAX); + +#ifndef RDESKTOP + +/** + * The VUSB RootHub port interface provided by the HCI (down). + * Pair with VUSBIROOTCONNECTOR + */ +typedef struct VUSBIROOTHUBPORT +{ + /** + * Get the number of available ports in the hub. + * + * @returns The number of ports available. + * @param pInterface Pointer to this structure. + * @param pAvailable Bitmap indicating the available ports. Set bit == available port. + */ + DECLR3CALLBACKMEMBER(unsigned, pfnGetAvailablePorts,(PVUSBIROOTHUBPORT pInterface, PVUSBPORTBITMAP pAvailable)); + + /** + * Gets the supported USB versions. + * + * @returns The mask of supported USB versions. + * @param pInterface Pointer to this structure. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetUSBVersions,(PVUSBIROOTHUBPORT pInterface)); + + /** + * A device is being attached to a port in the roothub. + * + * @param pInterface Pointer to this structure. + * @param uPort The port number assigned to the device. + * @param enmSpeed The speed of the device being attached. + */ + DECLR3CALLBACKMEMBER(int, pfnAttach,(PVUSBIROOTHUBPORT pInterface, uint32_t uPort, VUSBSPEED enmSpeed)); + + /** + * A device is being detached from a port in the roothub. + * + * @param pInterface Pointer to this structure. + * @param uPort The port number assigned to the device. + */ + DECLR3CALLBACKMEMBER(void, pfnDetach,(PVUSBIROOTHUBPORT pInterface, uint32_t uPort)); + + /** + * Reset the root hub. + * + * @returns VBox status code. + * @param pInterface Pointer to this structure. + * @param fResetOnLinux Whether or not to do real reset on linux. + */ + DECLR3CALLBACKMEMBER(int, pfnReset,(PVUSBIROOTHUBPORT pInterface, bool fResetOnLinux)); + + /** + * Transfer completion callback routine. + * + * VUSB will call this when a transfer have been completed + * in a one or another way. + * + * @param pInterface Pointer to this structure. + * @param pUrb Pointer to the URB in question. + */ + DECLR3CALLBACKMEMBER(void, pfnXferCompletion,(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb)); + + /** + * Handle transfer errors. + * + * VUSB calls this when a transfer attempt failed. This function will respond + * indicating whether to retry or complete the URB with failure. + * + * @returns Retry indicator. + * @param pInterface Pointer to this structure. + * @param pUrb Pointer to the URB in question. + */ + DECLR3CALLBACKMEMBER(bool, pfnXferError,(PVUSBIROOTHUBPORT pInterface, PVUSBURB pUrb)); + + /** + * Processes a new frame if periodic frame processing is enabled. + * + * @returns Flag whether there was activity which influences the frame rate. + * @param pInterface Pointer to this structure. + * @param u32FrameNo The frame number. + */ + DECLR3CALLBACKMEMBER(bool, pfnStartFrame, (PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameNo)); + + /** + * Informs the callee about a change in the frame rate due to too many idle cycles or + * when seeing activity after some idle time. + * + * @returns nothing. + * @param pInterface Pointer to this structure. + * @param u32FrameRate The new frame rate. + */ + DECLR3CALLBACKMEMBER(void, pfnFrameRateChanged, (PVUSBIROOTHUBPORT pInterface, uint32_t u32FrameRate)); + + /** Alignment dummy. */ + RTR3PTR Alignment; + +} VUSBIROOTHUBPORT; +/** VUSBIROOTHUBPORT interface ID. */ +# define VUSBIROOTHUBPORT_IID "2ece01c2-4dbf-4bd5-96ca-09fc14164cd4" + +/** Pointer to a VUSB RootHub connector interface. */ +typedef struct VUSBIROOTHUBCONNECTOR *PVUSBIROOTHUBCONNECTOR; +/** + * The VUSB RootHub connector interface provided by the VBox USB RootHub driver + * (up). + * Pair with VUSBIROOTHUBPORT. + */ +typedef struct VUSBIROOTHUBCONNECTOR +{ + /** + * Sets the URB parameters for the caller. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param cbHci Size of the data private to the HCI for each URB when allocated. + * @param cbHciTd Size of one transfer descriptor. The number of transfer descriptors + * is given VUSBIROOTHUBCONNECTOR::pfnNewUrb for each URB to calculate the + * final amount of memory required for the TDs. + * + * @note This must be called before starting to allocate any URB or otherwise there will be no + * data available for the HCI. + */ + DECLR3CALLBACKMEMBER(int, pfnSetUrbParams, (PVUSBIROOTHUBCONNECTOR pInterface, size_t cbHci, size_t cbHciTd)); + + /** + * Resets the roothub. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param fResetOnLinux Whether or not to do real reset on linux. + */ + DECLR3CALLBACKMEMBER(int, pfnReset, (PVUSBIROOTHUBCONNECTOR pInterface, bool fResetOnLinux)); + + /** + * Powers on the roothub. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + */ + DECLR3CALLBACKMEMBER(int, pfnPowerOn, (PVUSBIROOTHUBCONNECTOR pInterface)); + + /** + * Power off the roothub. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + */ + DECLR3CALLBACKMEMBER(int, pfnPowerOff, (PVUSBIROOTHUBCONNECTOR pInterface)); + + /** + * Allocates a new URB for a transfer. + * + * Either submit using pfnSubmitUrb or free using VUSBUrbFree(). + * + * @returns Pointer to a new URB. + * @returns NULL on failure - try again later. + * This will not fail if the device wasn't found. We'll fail it + * at submit time, since that makes the usage of this api simpler. + * @param pInterface Pointer to this struct. + * @param DstAddress The destination address of the URB. + * @param uPort Optional port of the device the URB is for, use VUSB_DEVICE_PORT_INVALID to indicate to use the destination address. + * @param enmType Type of the URB. + * @param enmDir Data transfer direction. + * @param cbData The amount of data space required. + * @param cTds The amount of TD space. + * @param pszTag Custom URB tag assigned by the caller, only for + * logged builds and optional. + * + * @note pDev should be NULL in most cases. The only useful case is for USB3 where + * it is required for the SET_ADDRESS request because USB3 uses unicast traffic. + */ + DECLR3CALLBACKMEMBER(PVUSBURB, pfnNewUrb,(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, uint32_t uPort, + VUSBXFERTYPE enmType, VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag)); + + /** + * Free an URB not submitted yet. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param pUrb Pointer to the URB to free returned by VUSBIROOTHUBCONNECTOR::pfnNewUrb. + */ + DECLR3CALLBACKMEMBER(int, pfnFreeUrb, (PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb)); + + /** + * Submits a URB for transfer. + * The transfer will do asynchronously if possible. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param pUrb Pointer to the URB returned by pfnNewUrb. + * The URB will be freed in case of failure. + * @param pLed Pointer to USB Status LED + */ + DECLR3CALLBACKMEMBER(int, pfnSubmitUrb,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb, struct PDMLED *pLed)); + + /** + * Call to service asynchronous URB completions in a polling fashion. + * + * Reaped URBs will be finished by calling the completion callback, + * thus there is no return code or input or anything from this function + * except for potential state changes elsewhere. + * + * @returns VINF_SUCCESS if no URBs are pending upon return. + * @returns VERR_TIMEOUT if one or more URBs are still in flight upon returning. + * @returns Other VBox status code. + * + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to reap URBs on. + * @param cMillies Number of milliseconds to poll for completion. + */ + DECLR3CALLBACKMEMBER(void, pfnReapAsyncUrbs,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, RTMSINTERVAL cMillies)); + + /** + * Cancels and completes - with CRC failure - all URBs queued on an endpoint. + * This is done in response to guest URB cancellation. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param pUrb Pointer to a previously submitted URB. + */ + DECLR3CALLBACKMEMBER(int, pfnCancelUrbsEp,(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb)); + + /** + * Cancels and completes - with CRC failure - all in-flight async URBs. + * This is typically done before saving a state. + * + * @param pInterface Pointer to this struct. + */ + DECLR3CALLBACKMEMBER(void, pfnCancelAllUrbs,(PVUSBIROOTHUBCONNECTOR pInterface)); + + /** + * Cancels and completes - with CRC failure - all URBs queued on an endpoint. + * This is done in response to a guest endpoint/pipe abort. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device. + * @param EndPt Endpoint number. + * @param enmDir Endpoint direction. + */ + DECLR3CALLBACKMEMBER(int, pfnAbortEp,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, int EndPt, VUSBDIRECTION enmDir)); + + /** + * Attach the device to the root hub. + * The device must not be attached to any hub for this call to succeed. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to attach. + */ + DECLR3CALLBACKMEMBER(int, pfnAttachDevice,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + + /** + * Detach the device from the root hub. + * The device must already be attached for this call to succeed. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to detach. + */ + DECLR3CALLBACKMEMBER(int, pfnDetachDevice,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + + /** + * Sets periodic frame processing. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uFrameRate The target frame rate in Hertz, 0 disables periodic frame processing. + * The real frame rate might be lower if there is no activity for a certain period or + * higher if there is a need for catching up with where the guest expects the device to be. + */ + DECLR3CALLBACKMEMBER(int, pfnSetPeriodicFrameProcessing, (PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uFrameRate)); + + /** + * Returns the current frame rate for the periodic frame processing. + * + * @returns Frame rate for periodic frame processing. + * @retval 0 if disabled. + * @param pInterface Pointer to this struct. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnGetPeriodicFrameRate, (PVUSBIROOTHUBCONNECTOR pInterface)); + + /** + * Updates the internally stored isochronous scheduling frame for a given + * endpoint and returns the delta between the current and previous frame. + * + * @returns Delta between currently and previously scheduled frame. + * @retval 0 if no previous frame was set. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device. + * @param EndPt Endpoint number. + * @param enmDir Endpoint direction. + * @param uNewFrameID The frame ID of a new transfer. + * @param uBits The number of significant bits in frame ID. + */ + DECLR3CALLBACKMEMBER(uint32_t, pfnUpdateIsocFrameDelta, (PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, + int EndPt, VUSBDIRECTION enmDir, uint16_t uNewFrameID, uint8_t uBits)); + + /** + * Resets the device. + * + * Since a device reset shall take at least 10ms from the guest point of view, + * it must be performed asynchronously. We create a thread which performs this + * operation and ensures it will take at least 10ms. + * + * At times - like init - a synchronous reset is required, this can be done + * by passing NULL for pfnDone. + * + * -- internal stuff, move it -- + * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state. + * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful, + * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed. + * -- internal stuff, move it -- + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to reset. + * @param fResetOnLinux Set if we can permit a real reset and a potential logical + * device reconnect on linux hosts. + * @param pfnDone Pointer to the completion routine. If NULL a synchronous + * reset is performed not respecting the 10ms. + * @param pvUser User argument to the completion routine. + * @param pVM The cross context VM structure. Required if pfnDone + * is not NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnDevReset,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, bool fResetOnLinux, + PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)); + + /** + * Powers on the device. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to power on. + */ + DECLR3CALLBACKMEMBER(int, pfnDevPowerOn,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + + /** + * Powers off the device. + * + * @returns VBox status code. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to power off. + */ + DECLR3CALLBACKMEMBER(int, pfnDevPowerOff,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + + /** + * Get the state of the device. + * + * @returns Device state. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to get the state for. + */ + DECLR3CALLBACKMEMBER(VUSBDEVICESTATE, pfnDevGetState,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + + /** + * Returns whether the device implements the saved state handlers + * and doesn't need to get detached. + * + * @returns true if the device supports saving the state, false otherwise. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to query saved state support for. + */ + DECLR3CALLBACKMEMBER(bool, pfnDevIsSavedStateSupported,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + + /** + * Get the speed the device is operating at. + * + * @returns Device state. + * @param pInterface Pointer to this struct. + * @param uPort Port of the device to query the speed for. + */ + DECLR3CALLBACKMEMBER(VUSBSPEED, pfnDevGetSpeed,(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort)); + +} VUSBIROOTHUBCONNECTOR; +AssertCompileSizeAlignment(VUSBIROOTHUBCONNECTOR, 8); +/** VUSBIROOTHUBCONNECTOR interface ID. */ +# define VUSBIROOTHUBCONNECTOR_IID "662d7822-b9c6-43b5-88b6-5d59f0106e46" + + +# ifdef IN_RING3 +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnSetUrbParams */ +DECLINLINE(int) VUSBIRhSetUrbParams(PVUSBIROOTHUBCONNECTOR pInterface, size_t cbHci, size_t cbHciTd) +{ + return pInterface->pfnSetUrbParams(pInterface, cbHci, cbHciTd); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnNewUrb */ +DECLINLINE(PVUSBURB) VUSBIRhNewUrb(PVUSBIROOTHUBCONNECTOR pInterface, uint8_t DstAddress, uint32_t uPort, + VUSBXFERTYPE enmType, VUSBDIRECTION enmDir, uint32_t cbData, uint32_t cTds, const char *pszTag) +{ + return pInterface->pfnNewUrb(pInterface, DstAddress, uPort, enmType, enmDir, cbData, cTds, pszTag); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnFreeUrb */ +DECLINLINE(int) VUSBIRhFreeUrb(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb) +{ + return pInterface->pfnFreeUrb(pInterface, pUrb); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnSubmitUrb */ +DECLINLINE(int) VUSBIRhSubmitUrb(PVUSBIROOTHUBCONNECTOR pInterface, PVUSBURB pUrb, struct PDMLED *pLed) +{ + return pInterface->pfnSubmitUrb(pInterface, pUrb, pLed); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnReapAsyncUrbs */ +DECLINLINE(void) VUSBIRhReapAsyncUrbs(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, RTMSINTERVAL cMillies) +{ + pInterface->pfnReapAsyncUrbs(pInterface, uPort, cMillies); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnCancelAllUrbs */ +DECLINLINE(void) VUSBIRhCancelAllUrbs(PVUSBIROOTHUBCONNECTOR pInterface) +{ + pInterface->pfnCancelAllUrbs(pInterface); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnAttachDevice */ +DECLINLINE(int) VUSBIRhAttachDevice(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnAttachDevice(pInterface, uPort); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDetachDevice */ +DECLINLINE(int) VUSBIRhDetachDevice(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnDetachDevice(pInterface, uPort); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnSetPeriodicFrameProcessing */ +DECLINLINE(int) VUSBIRhSetPeriodicFrameProcessing(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uFrameRate) +{ + return pInterface->pfnSetPeriodicFrameProcessing(pInterface, uFrameRate); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnGetPeriodicFrameRate */ +DECLINLINE(uint32_t) VUSBIRhGetPeriodicFrameRate(PVUSBIROOTHUBCONNECTOR pInterface) +{ + return pInterface->pfnGetPeriodicFrameRate(pInterface); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevReset */ +DECLINLINE(int) VUSBIRhDevReset(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort, bool fResetOnLinux, + PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM) +{ + return pInterface->pfnDevReset(pInterface, uPort, fResetOnLinux, pfnDone, pvUser, pVM); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevPowerOn */ +DECLINLINE(int) VUSBIRhDevPowerOn(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnDevPowerOn(pInterface, uPort); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevPowerOff */ +DECLINLINE(int) VUSBIRhDevPowerOff(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnDevPowerOff(pInterface, uPort); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevGetState */ +DECLINLINE(VUSBDEVICESTATE) VUSBIRhDevGetState(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnDevGetState(pInterface, uPort); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevGetState */ +DECLINLINE(bool) VUSBIRhDevIsSavedStateSupported(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnDevIsSavedStateSupported(pInterface, uPort); +} + +/** @copydoc VUSBIROOTHUBCONNECTOR::pfnDevGetSpeed */ +DECLINLINE(VUSBSPEED) VUSBIRhDevGetSpeed(PVUSBIROOTHUBCONNECTOR pInterface, uint32_t uPort) +{ + return pInterface->pfnDevGetSpeed(pInterface, uPort); +} +# endif /* IN_RING3 */ + +#endif /* ! RDESKTOP */ + + +#ifndef RDESKTOP + +/** + * USB Device Interface (up). + * No interface pair. + */ +typedef struct VUSBIDEVICE +{ + /** + * Resets the device. + * + * Since a device reset shall take at least 10ms from the guest point of view, + * it must be performed asynchronously. We create a thread which performs this + * operation and ensures it will take at least 10ms. + * + * At times - like init - a synchronous reset is required, this can be done + * by passing NULL for pfnDone. + * + * -- internal stuff, move it -- + * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state. + * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful, + * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed. + * -- internal stuff, move it -- + * + * @returns VBox status code. + * @param pInterface Pointer to this structure. + * @param fResetOnLinux Set if we can permit a real reset and a potential logical + * device reconnect on linux hosts. + * @param pfnDone Pointer to the completion routine. If NULL a synchronous + * reset is performed not respecting the 10ms. + * @param pvUser User argument to the completion routine. + * @param pVM The cross context VM structure. Required if pfnDone + * is not NULL. + */ + DECLR3CALLBACKMEMBER(int, pfnReset,(PVUSBIDEVICE pInterface, bool fResetOnLinux, + PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM)); + + /** + * Powers on the device. + * + * @returns VBox status code. + * @param pInterface Pointer to the device interface structure. + */ + DECLR3CALLBACKMEMBER(int, pfnPowerOn,(PVUSBIDEVICE pInterface)); + + /** + * Powers off the device. + * + * @returns VBox status code. + * @param pInterface Pointer to the device interface structure. + */ + DECLR3CALLBACKMEMBER(int, pfnPowerOff,(PVUSBIDEVICE pInterface)); + + /** + * Get the state of the device. + * + * @returns Device state. + * @param pInterface Pointer to the device interface structure. + */ + DECLR3CALLBACKMEMBER(VUSBDEVICESTATE, pfnGetState,(PVUSBIDEVICE pInterface)); + + /** + * Returns whether the device implements the saved state handlers + * and doesn't need to get detached. + * + * @returns true if the device supports saving the state, false otherwise. + * @param pInterface Pointer to the device interface structure. + */ + DECLR3CALLBACKMEMBER(bool, pfnIsSavedStateSupported,(PVUSBIDEVICE pInterface)); + + /** + * Get the speed the device is operating at. + * + * @returns Device state. + * @param pInterface Pointer to the device interface structure. + */ + DECLR3CALLBACKMEMBER(VUSBSPEED, pfnGetSpeed,(PVUSBIDEVICE pInterface)); + +} VUSBIDEVICE; +/** VUSBIDEVICE interface ID. */ +# define VUSBIDEVICE_IID "af576b38-e8ca-4db7-810a-2596d8d57ca0" + + +# ifdef IN_RING3 +/** + * Resets the device. + * + * Since a device reset shall take at least 10ms from the guest point of view, + * it must be performed asynchronously. We create a thread which performs this + * operation and ensures it will take at least 10ms. + * + * At times - like init - a synchronous reset is required, this can be done + * by passing NULL for pfnDone. + * + * -- internal stuff, move it -- + * While the device is being reset it is in the VUSB_DEVICE_STATE_RESET state. + * On completion it will be in the VUSB_DEVICE_STATE_DEFAULT state if successful, + * or in the VUSB_DEVICE_STATE_DETACHED state if the rest failed. + * -- internal stuff, move it -- + * + * @returns VBox status code. + * @param pInterface Pointer to the device interface structure. + * @param fResetOnLinux Set if we can permit a real reset and a potential logical + * device reconnect on linux hosts. + * @param pfnDone Pointer to the completion routine. If NULL a + * synchronous reset is performed not respecting the + * 10ms. + * @param pvUser User argument to the completion routine. + * @param pVM The cross context VM structure. Required if pfnDone + * is not NULL. + * + * NULL is acceptable Required if callback in EMT is desired, NULL is otherwise + * acceptable. + */ +DECLINLINE(int) VUSBIDevReset(PVUSBIDEVICE pInterface, bool fResetOnLinux, PFNVUSBRESETDONE pfnDone, void *pvUser, PVM pVM) +{ + return pInterface->pfnReset(pInterface, fResetOnLinux, pfnDone, pvUser, pVM); +} + +/** + * Powers on the device. + * + * @returns VBox status code. + * @param pInterface Pointer to the device interface structure. + */ +DECLINLINE(int) VUSBIDevPowerOn(PVUSBIDEVICE pInterface) +{ + return pInterface->pfnPowerOn(pInterface); +} + +/** + * Powers off the device. + * + * @returns VBox status code. + * @param pInterface Pointer to the device interface structure. + */ +DECLINLINE(int) VUSBIDevPowerOff(PVUSBIDEVICE pInterface) +{ + return pInterface->pfnPowerOff(pInterface); +} + +/** + * Get the state of the device. + * + * @returns Device state. + * @param pInterface Pointer to the device interface structure. + */ +DECLINLINE(VUSBDEVICESTATE) VUSBIDevGetState(PVUSBIDEVICE pInterface) +{ + return pInterface->pfnGetState(pInterface); +} + +/** + * @copydoc VUSBIDEVICE::pfnIsSavedStateSupported + */ +DECLINLINE(bool) VUSBIDevIsSavedStateSupported(PVUSBIDEVICE pInterface) +{ + return pInterface->pfnIsSavedStateSupported(pInterface); +} +# endif /* IN_RING3 */ + +#endif /* ! RDESKTOP */ + +/** @name URB + * @{ */ + +/** + * VUSB Transfer status codes. + */ +typedef enum VUSBSTATUS +{ + /** Transer was ok. */ + VUSBSTATUS_OK = 0, + /** Transfer stalled, endpoint halted. */ + VUSBSTATUS_STALL, + /** Device not responding. */ + VUSBSTATUS_DNR, + /** CRC error. */ + VUSBSTATUS_CRC, + /** Data underrun error. */ + VUSBSTATUS_DATA_UNDERRUN, + /** Data overrun error. */ + VUSBSTATUS_DATA_OVERRUN, + /** The isochronous buffer hasn't been touched. */ + VUSBSTATUS_NOT_ACCESSED, + /** Canceled/undone URB (VUSB internal). */ + VUSBSTATUS_UNDO, + /** Canceled URB. */ + VUSBSTATUS_CANCELED, + /** Invalid status. */ + VUSBSTATUS_INVALID = 0x7f +} VUSBSTATUS; + + +/** + * The URB states + */ +typedef enum VUSBURBSTATE +{ + /** The usual invalid state. */ + VUSBURBSTATE_INVALID = 0, + /** The URB is free, i.e. not in use. + * Next state: ALLOCATED */ + VUSBURBSTATE_FREE, + /** The URB is allocated, i.e. being prepared for submission. + * Next state: FREE, IN_FLIGHT */ + VUSBURBSTATE_ALLOCATED, + /** The URB is in flight. + * Next state: REAPED, CANCELLED */ + VUSBURBSTATE_IN_FLIGHT, + /** The URB has been reaped and is being completed. + * Next state: FREE */ + VUSBURBSTATE_REAPED, + /** The URB has been cancelled and is awaiting reaping and immediate freeing. + * Next state: FREE */ + VUSBURBSTATE_CANCELLED, + /** The end of the valid states (exclusive). */ + VUSBURBSTATE_END, + /** The usual 32-bit blow up. */ + VUSBURBSTATE_32BIT_HACK = 0x7fffffff +} VUSBURBSTATE; + + +/** + * Information about a isochronous packet. + */ +typedef struct VUSBURBISOCPKT +{ + /** The size of the packet. + * IN: The packet size. I.e. the number of bytes to the next packet or end of buffer. + * OUT: The actual size transferred. */ + uint32_t cb; + /** The offset of the packet. (Relative to VUSBURB::abData[0].) + * OUT: This can be changed by the USB device if it does some kind of buffer squeezing. */ + uint32_t off; + /** The status of the transfer. + * IN: VUSBSTATUS_INVALID + * OUT: VUSBSTATUS_INVALID if nothing was done, otherwise the correct status. */ + VUSBSTATUS enmStatus; +} VUSBURBISOCPKT; +/** Pointer to a isochronous packet. */ +typedef VUSBURBISOCPKT *PVUSBURBISOCPTK; +/** Pointer to a const isochronous packet. */ +typedef const VUSBURBISOCPKT *PCVUSBURBISOCPKT; + +/** Private controller emulation specific data for the associated USB request descriptor. */ +typedef struct VUSBURBHCIINT *PVUSBURBHCI; +/** Private controller emulation specific TD data. */ +typedef struct VUSBURBHCITDINT *PVUSBURBHCITD; +/** Private VUSB/roothub related state for the associated URB. */ +typedef struct VUSBURBVUSBINT *PVUSBURBVUSB; + +/** + * Asynchronous USB request descriptor + */ +typedef struct VUSBURB +{ + /** URB magic value. */ + uint32_t u32Magic; + /** The USR state. */ + VUSBURBSTATE enmState; + /** Flag whether the URB is about to be completed, + * either by the I/O thread or the cancellation worker. + */ + volatile bool fCompleting; + /** URB description, can be null. intended for logging. */ + char *pszDesc; + +#ifdef RDESKTOP + /** The next URB in rdesktop-vrdp's linked list */ + PVUSBURB pNext; + /** The previous URB in rdesktop-vrdp's linked list */ + PVUSBURB pPrev; + /** The vrdp handle for the URB */ + uint32_t handle; + /** Pointer used to find the usb proxy device */ + struct VUSBDEV *pDev; +#endif + + /** The VUSB stack private data. */ + PVUSBURBVUSB pVUsb; + /** Private host controller data associated with this URB. */ + PVUSBURBHCI pHci; + /** Pointer to the host controller transfer descriptor array. */ + PVUSBURBHCITD paTds; + + /** The device data. */ + struct VUSBURBDEV + { + /** Pointer to private device specific data. */ + void *pvPrivate; + /** Used by the device when linking the URB in some list of its own. */ + PVUSBURB pNext; + } Dev; + + /** The device address. + * This is set at allocation time. */ + uint8_t DstAddress; + + /** The endpoint. + * IN: Must be set before submitting the URB. + * @remark This does not have the high bit (direction) set! */ + uint8_t EndPt; + /** The transfer type. + * IN: Set at allocation time. */ + VUSBXFERTYPE enmType; + /** The transfer direction. + * IN: Set at allocation time. */ + VUSBDIRECTION enmDir; + /** Indicates whether it is OK to receive/send less data than requested. + * IN: Must be initialized before submitting the URB. */ + bool fShortNotOk; + /** The transfer status. + * OUT: This is set when reaping the URB. */ + VUSBSTATUS enmStatus; + + /** The relative starting frame for isochronous transfers. + * Zero indicates "transfer ASAP". + * This is ignored when enmType isn't VUSBXFERTYPE_ISOC. */ + uint16_t uStartFrameDelta; + /** Flag indicating whether the start frame delta is relative + * to the previous transfer (false) or now (true). + * This is ignored when enmType isn't VUSBXFERTYPE_ISOC. */ + bool fStartRelToNow; + /** The number of isochronous packets describe in aIsocPkts. + * This is ignored when enmType isn't VUSBXFERTYPE_ISOC. */ + uint8_t cIsocPkts; + /** The iso packets within abData. + * This is ignored when enmType isn't VUSBXFERTYPE_ISOC. */ + VUSBURBISOCPKT aIsocPkts[8]; + + /** The message length. + * IN: The amount of data to send / receive - set at allocation time. + * OUT: The amount of data sent / received. */ + uint32_t cbData; + /** The message data. + * IN: On host to device transfers, the data to send. + * OUT: On device to host transfers, the data to received. + * This array has actually a size of VUsb.cbDataAllocated, not 8KB! */ + uint8_t abData[8*_1K]; +} VUSBURB; + +/** The magic value of a valid VUSBURB. (Murakami Haruki) */ +#define VUSBURB_MAGIC UINT32_C(0x19490112) + +/** @} */ + + +/** @} */ + +RT_C_DECLS_END + +#endif /* !VBOX_INCLUDED_vusb_h */ diff --git a/include/VBox/xrandr-calls.h b/include/VBox/xrandr-calls.h new file mode 100644 index 00000000..5ede4291 --- /dev/null +++ b/include/VBox/xrandr-calls.h @@ -0,0 +1,80 @@ +/** @file + * Stubs for dynamically loading libXrandr and the symbols which are needed by + * VirtualBox. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +/** The file name of the libXrandr library. */ +#define RT_RUNTIME_LOADER_LIB_NAME "libXrandr.so.2" + +/** The name of the loader function. */ +#define RT_RUNTIME_LOADER_FUNCTION RTXrandrLoadLib + +/** The following are the symbols which we need from the Xrandr library. */ +#define RT_RUNTIME_LOADER_INSERT_SYMBOLS \ + RT_PROXY_STUB(XRRQueryExtension, Bool, (Display *dpy, int *event_base_return, int *error_base_return), \ + (dpy, event_base_return, error_base_return)) \ + RT_PROXY_STUB(XRRQueryVersion, Bool, (Display *dpy, int *major_version_return, int *minor_version_return), \ + (dpy, major_version_return, minor_version_return)) \ + RT_PROXY_STUB(XRRSelectInput, void, (Display *dpy, Window window, int mask), \ + (dpy, window, mask)) \ + RT_PROXY_STUB(XRRGetMonitors, XRRMonitorInfo *, (Display *dpy, Window window, Bool get_active, int *nmonitors), \ + (dpy, window, get_active, nmonitors)) \ + RT_PROXY_STUB(XRRFreeMonitors, void, (XRRMonitorInfo *monitors), \ + (monitors)) \ + RT_PROXY_STUB(XRRGetScreenResources, XRRScreenResources *, (Display *dpy, Window window), \ + (dpy, window)) \ + RT_PROXY_STUB(XRRFreeScreenResources, void, (XRRScreenResources *resources), \ + (resources)) \ + RT_PROXY_STUB(XRRSetOutputPrimary, void, (Display *dpy, Window window, RROutput output), \ + (dpy, window, output)) + +#ifdef VBOX_XRANDR_GENERATE_HEADER +# define RT_RUNTIME_LOADER_GENERATE_HEADER +# define RT_RUNTIME_LOADER_GENERATE_DECLS +# include +# undef RT_RUNTIME_LOADER_GENERATE_HEADER +# undef RT_RUNTIME_LOADER_GENERATE_DECLS + +#elif defined(VBOX_XRANDR_GENERATE_BODY) +# define RT_RUNTIME_LOADER_GENERATE_BODY_STUBS +# include +# undef RT_RUNTIME_LOADER_GENERATE_BODY_STUBS + +#else +# error This file should only be included to generate stubs for loading the Xrandr library at runtime +#endif + +#undef RT_RUNTIME_LOADER_LIB_NAME +#undef RT_RUNTIME_LOADER_INSERT_SYMBOLS + diff --git a/include/VBox/xrandr.h b/include/VBox/xrandr.h new file mode 100644 index 00000000..79adff4a --- /dev/null +++ b/include/VBox/xrandr.h @@ -0,0 +1,125 @@ +/** @file + * Module to dynamically load libXrandr and load all symbols which are needed by + * VirtualBox. + */ + +/* + * Copyright (C) 2008-2022 Oracle and/or its affiliates. + * + * This file is part of VirtualBox base platform packages, as + * available from https://www.virtualbox.org. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation, in version 3 of the + * License. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * The contents of this file may alternatively be used under the terms + * of the Common Development and Distribution License Version 1.0 + * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included + * in the VirtualBox distribution, in which case the provisions of the + * CDDL are applicable instead of those of the GPL. + * + * You may elect to license modified versions of this file under the + * terms and conditions of either the GPL or the CDDL or both. + * + * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0 + */ + +#ifndef VBOX_INCLUDED_xrandr_h +#define VBOX_INCLUDED_xrandr_h +#ifndef RT_WITHOUT_PRAGMA_ONCE +# pragma once +#endif + +#include +#include + +#ifndef __cplusplus +# error "This header requires C++ to avoid name clashes." +#endif + +/* Define missing X11/XRandr structures, types and macros. */ + +#define Bool int +#define RRScreenChangeNotifyMask (1L << 0) +#define RRScreenChangeNotify 0 + +struct _XDisplay; +typedef struct _XDisplay Display; + +typedef unsigned long Atom; +typedef unsigned long XID; +typedef XID RROutput; +typedef XID Window; +typedef XID RROutput; +typedef XID RRCrtc; +typedef XID RRMode; +typedef unsigned long XRRModeFlags; +typedef unsigned long int Time; + +struct XRRMonitorInfo +{ + Atom name; + Bool primary; + Bool automatic; + int noutput; + int x; + int y; + int width; + int height; + int mwidth; + int mheight; + RROutput *outputs; +}; +typedef struct XRRMonitorInfo XRRMonitorInfo; + +struct XRRModeInfo +{ + RRMode id; + unsigned int width; + unsigned int height; + unsigned long dotClock; + unsigned int hSyncStart; + unsigned int hSyncEnd; + unsigned int hTotal; + unsigned int hSkew; + unsigned int vSyncStart; + unsigned int vSyncEnd; + unsigned int vTotal; + char *name; + unsigned int nameLength; + XRRModeFlags modeFlags; +}; +typedef struct XRRModeInfo XRRModeInfo; + +struct XRRScreenResources +{ + Time timestamp; + Time configTimestamp; + int ncrtc; + RRCrtc *crtcs; + int noutput; + RROutput *outputs; + int nmode; + XRRModeInfo *modes; +}; +typedef struct XRRScreenResources XRRScreenResources; + +/* Declarations of the functions that we need from libXrandr. */ +#define VBOX_XRANDR_GENERATE_HEADER + +#include + +#undef VBOX_XRANDR_GENERATE_HEADER + +#endif /* !VBOX_INCLUDED_xrandr_h */ + -- cgit v1.2.3