Changeset 84111 in vbox for trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
- Timestamp:
- Apr 30, 2020 3:31:01 PM (5 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Devices/Bus/DevIommuAmd.cpp
r84101 r84111 327 327 */ 328 328 /** MsiCapId: Capability ID. */ 329 #define IOMMU_BF_MSI_CAP HDR_CAP_ID_SHIFT0330 #define IOMMU_BF_MSI_CAP HDR_CAP_ID_MASKUINT32_C(0x000000ff)329 #define IOMMU_BF_MSI_CAP_HDR_CAP_ID_SHIFT 0 330 #define IOMMU_BF_MSI_CAP_HDR_CAP_ID_MASK UINT32_C(0x000000ff) 331 331 /** MsiCapPtr: Pointer (PCI config offset) to the next capability. */ 332 #define IOMMU_BF_MSI_CAP HDR_CAP_PTR_SHIFT8333 #define IOMMU_BF_MSI_CAP HDR_CAP_PTR_MASKUINT32_C(0x0000ff00)332 #define IOMMU_BF_MSI_CAP_HDR_CAP_PTR_SHIFT 8 333 #define IOMMU_BF_MSI_CAP_HDR_CAP_PTR_MASK UINT32_C(0x0000ff00) 334 334 /** MsiEn: Message Signal Interrupt enable. */ 335 #define IOMMU_BF_MSI_CAP HDR_EN_SHIFT16336 #define IOMMU_BF_MSI_CAP HDR_EN_MASKUINT32_C(0x00010000)335 #define IOMMU_BF_MSI_CAP_HDR_EN_SHIFT 16 336 #define IOMMU_BF_MSI_CAP_HDR_EN_MASK UINT32_C(0x00010000) 337 337 /** MsiMultMessCap: MSI Multi-Message Capability. */ 338 #define IOMMU_BF_MSI_CAP HDR_MULTMESS_CAP_SHIFT17339 #define IOMMU_BF_MSI_CAP HDR_MULTMESS_CAP_MASKUINT32_C(0x000e0000)338 #define IOMMU_BF_MSI_CAP_HDR_MULTMESS_CAP_SHIFT 17 339 #define IOMMU_BF_MSI_CAP_HDR_MULTMESS_CAP_MASK UINT32_C(0x000e0000) 340 340 /** MsiMultMessEn: MSI Mult-Message Enable. */ 341 #define IOMMU_BF_MSI_CAP HDR_MULTMESS_EN_SHIFT20342 #define IOMMU_BF_MSI_CAP HDR_MULTMESS_EN_MASKUINT32_C(0x00700000)341 #define IOMMU_BF_MSI_CAP_HDR_MULTMESS_EN_SHIFT 20 342 #define IOMMU_BF_MSI_CAP_HDR_MULTMESS_EN_MASK UINT32_C(0x00700000) 343 343 /** Msi64BitEn: MSI 64-bit Enabled. */ 344 #define IOMMU_BF_MSI_CAP HDR_64BIT_EN_SHIFT23345 #define IOMMU_BF_MSI_CAP HDR_64BIT_EN_MASKUINT32_C(0x00800000)344 #define IOMMU_BF_MSI_CAP_HDR_64BIT_EN_SHIFT 23 345 #define IOMMU_BF_MSI_CAP_HDR_64BIT_EN_MASK UINT32_C(0x00800000) 346 346 /** Bits 31:24 reserved. */ 347 #define IOMMU_BF_MSI_CAP HDR_RSVD_24_31_SHIFT24348 #define IOMMU_BF_MSI_CAP HDR_RSVD_24_31_MASKUINT32_C(0xff000000)349 RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_MSI_CAP HDR_, UINT32_C(0), UINT32_MAX,347 #define IOMMU_BF_MSI_CAP_HDR_RSVD_24_31_SHIFT 24 348 #define IOMMU_BF_MSI_CAP_HDR_RSVD_24_31_MASK UINT32_C(0xff000000) 349 RT_BF_ASSERT_COMPILE_CHECKS(IOMMU_BF_MSI_CAP_HDR_, UINT32_C(0), UINT32_MAX, 350 350 (CAP_ID, CAP_PTR, EN, MULTMESS_CAP, MULTMESS_EN, 64BIT_EN, RSVD_24_31)); 351 351 /** @} */ … … 455 455 /** Number of device table segments supported (power of 2). */ 456 456 #define IOMMU_MAX_DEV_TAB_SEGMENTS 3 457 /** Maximum number of host address translation levels supported. */ 458 #define IOMMU_MAX_HOST_PT_LEVEL 6 457 459 /** @} */ 458 460 … … 1579 1581 } MSI_CAP_HDR_T; 1580 1582 AssertCompileSize(MSI_CAP_HDR_T, 4); 1583 #define IOMMU_MSI_CAP_HDR_RW_MASK RT_BIT(16) 1581 1584 1582 1585 /** … … 2636 2639 2637 2640 2641 #if 0 2642 static VBOXSTRICTRC iommuAmdMsiCapHdr_w(PPDMDEVINS pDevIns, PIOMMU pThis, uint32_t iReg, uint64_t u64Value) 2643 { 2644 RT_NOREF(pThis, iReg); 2645 2646 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0]; 2647 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev); 2648 2649 MSI_CAP_HDR_T MsiCapHdr; 2650 MsiCapHdr.u32 = PDMPciDevGetDWord(pPciDev, IOMMU_PCI_OFF_MSI_CAP_HDR); 2651 2652 /** @todo */ 2653 return VINF_SUCCESS; 2654 } 2655 #endif 2656 2638 2657 /** 2639 2658 * Writes the MSI Address (Lo) Register (32-bit). … … 3217 3236 * Constructs a DEV_TAB_HARDWARE_ERROR event. 3218 3237 * 3219 * @param uDevId The device ID.3220 * @param GCPhysDevTab The system physical address of the failed device table3221 * access.3222 * @param fOperationThe operation being performed.3223 * @param pEvent Where to store the constructed event.3238 * @param uDevId The device ID. 3239 * @param GCPhysDevTabEntry The system physical address of the failed device 3240 * table access. 3241 * @param enmOp The operation being performed. 3242 * @param pEvent Where to store the constructed event. 3224 3243 * 3225 3244 * @thread Any. … … 4143 4162 memset(&pThis->aDevTabBaseAddrs[0], 0, sizeof(pThis->aDevTabBaseAddrs)); 4144 4163 4145 pThis->CmdBufBaseAddr.u64 = 0; 4146 pThis->CmdBufBaseAddr.n.u4Len = 8; 4147 4148 pThis->EvtLogBaseAddr.u64 = 0; 4149 pThis->EvtLogBaseAddr.n.u4Len = 8; 4150 4151 pThis->Ctrl.u64 = 0; 4152 4153 pThis->ExclRangeBaseAddr.u64 = 0; 4154 pThis->ExclRangeLimit.u64 = 0; 4155 4164 pThis->CmdBufBaseAddr.u64 = 0; 4165 pThis->CmdBufBaseAddr.n.u4Len = 8; 4166 4167 pThis->EvtLogBaseAddr.u64 = 0; 4168 pThis->EvtLogBaseAddr.n.u4Len = 8; 4169 4170 pThis->Ctrl.u64 = 0; 4171 4172 pThis->ExclRangeBaseAddr.u64 = 0; 4173 pThis->ExclRangeLimit.u64 = 0; 4174 4175 pThis->PprLogBaseAddr.u64 = 0; 4176 pThis->PprLogBaseAddr.n.u4Len = 8; 4177 4178 pThis->HwEvtHi.u64 = 0; 4179 pThis->HwEvtLo = 0; 4180 pThis->HwEvtStatus.u64 = 0; 4181 4182 pThis->GALogBaseAddr.u64 = 0; 4183 pThis->GALogBaseAddr.n.u4Len = 8; 4184 pThis->GALogTailAddr.u64 = 0; 4185 4186 pThis->PprLogBBaseAddr.u64 = 0; 4187 pThis->PprLogBBaseAddr.n.u4Len = 8; 4188 4189 pThis->EvtLogBBaseAddr.u64 = 0; 4190 pThis->EvtLogBBaseAddr.n.u4Len = 8; 4191 4192 pThis->DevSpecificFeat.u64 = 0; 4193 pThis->DevSpecificCtrl.u64 = 0; 4194 pThis->DevSpecificStatus.u64 = 0; 4195 4196 pThis->MsiMiscInfo.u64 = 0; 4197 pThis->PerfOptCtrl.u32 = 0; 4198 4199 pThis->XtGenIntrCtrl.u64 = 0; 4200 pThis->XtPprIntrCtrl.u64 = 0; 4201 pThis->XtGALogIntrCtrl.u64 = 0; 4202 4203 memset(&pThis->aMarcApers[0], 0, sizeof(pThis->aMarcApers)); 4204 4205 pThis->CmdBufHeadPtr.u64 = 0; 4206 pThis->CmdBufTailPtr.u64 = 0; 4207 pThis->EvtLogHeadPtr.u64 = 0; 4208 pThis->EvtLogTailPtr.u64 = 0; 4209 4210 pThis->Status.u64 = 0; 4211 4212 pThis->PprLogHeadPtr.u64 = 0; 4213 pThis->PprLogTailPtr.u64 = 0; 4214 4215 pThis->GALogHeadPtr.u64 = 0; 4216 pThis->GALogTailPtr.u64 = 0; 4217 4218 pThis->PprLogBHeadPtr.u64 = 0; 4219 pThis->PprLogBTailPtr.u64 = 0; 4220 4221 pThis->EvtLogBHeadPtr.u64 = 0; 4222 pThis->EvtLogBTailPtr.u64 = 0; 4223 4224 pThis->PprLogAutoResp.u64 = 0; 4225 pThis->PprLogOverflowEarly.u64 = 0; 4226 pThis->PprLogBOverflowEarly.u64 = 0; 4227 4228 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_BASE_ADDR_REG_LO, 0); 4229 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_BASE_ADDR_REG_HI, 0); 4230 } 4231 4232 4233 /** 4234 * @interface_method_impl{PDMDEVREG,pfnDestruct} 4235 */ 4236 static DECLCALLBACK(int) iommuAmdR3Destruct(PPDMDEVINS pDevIns) 4237 { 4238 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); 4239 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 4240 LogFlowFunc(("\n")); 4241 4242 /* Close the command thread semaphore. */ 4243 if (pThis->hEvtCmdThread != NIL_SUPSEMEVENT) 4244 { 4245 PDMDevHlpSUPSemEventClose(pDevIns, pThis->hEvtCmdThread); 4246 pThis->hEvtCmdThread = NIL_SUPSEMEVENT; 4247 } 4248 return VINF_SUCCESS; 4249 } 4250 4251 4252 /** 4253 * @interface_method_impl{PDMDEVREG,pfnConstruct} 4254 */ 4255 static DECLCALLBACK(int) iommuAmdR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) 4256 { 4257 NOREF(iInstance); 4258 4259 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); 4260 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 4261 PIOMMUCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUCC); 4262 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3; 4263 int rc; 4264 LogFlowFunc(("\n")); 4265 4266 pThisCC->pDevInsR3 = pDevIns; 4267 4268 /* 4269 * Validate and read the configuration. 4270 */ 4271 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Device|Function", ""); 4272 4273 uint8_t uPciDevice; 4274 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "Device", &uPciDevice, 0); 4275 if (RT_FAILURE(rc)) 4276 return PDMDEV_SET_ERROR(pDevIns, rc, N_("IOMMU: Failed to query \"Device\"")); 4277 4278 uint8_t uPciFunction; 4279 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "Function", &uPciFunction, 2); 4280 if (RT_FAILURE(rc)) 4281 return PDMDEV_SET_ERROR(pDevIns, rc, N_("IOMMU: Failed to query \"Function\"")); 4282 4283 /* 4284 * Register the IOMMU with PDM. 4285 */ 4286 PDMIOMMUREGR3 IommuReg; 4287 RT_ZERO(IommuReg); 4288 IommuReg.u32Version = PDM_IOMMUREGCC_VERSION; 4289 IommuReg.pfnMemRead = iommuAmdDeviceMemRead; 4290 IommuReg.pfnMemWrite = iommuAmdDeviceMemWrite; 4291 IommuReg.u32TheEnd = PDM_IOMMUREGCC_VERSION; 4292 rc = PDMDevHlpIommuRegister(pDevIns, &IommuReg, &pThisCC->CTX_SUFF(pIommuHlp), &pThis->idxIommu); 4293 if (RT_FAILURE(rc)) 4294 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to register ourselves as an IOMMU device")); 4295 if (pThisCC->CTX_SUFF(pIommuHlp)->u32Version != PDM_IOMMUHLPR3_VERSION) 4296 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS, 4297 N_("IOMMU helper version mismatch; got %#x expected %#x"), 4298 pThisCC->CTX_SUFF(pIommuHlp)->u32Version, PDM_IOMMUHLPR3_VERSION); 4299 if (pThisCC->CTX_SUFF(pIommuHlp)->u32TheEnd != PDM_IOMMUHLPR3_VERSION) 4300 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS, 4301 N_("IOMMU helper end-version mismatch; got %#x expected %#x"), 4302 pThisCC->CTX_SUFF(pIommuHlp)->u32TheEnd, PDM_IOMMUHLPR3_VERSION); 4303 4304 /* 4305 * Initialize read-only PCI configuration space. 4306 */ 4307 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0]; 4308 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev); 4309 4310 /* Header. */ 4311 PDMPciDevSetVendorId(pPciDev, IOMMU_PCI_VENDOR_ID); /* AMD */ 4312 PDMPciDevSetDeviceId(pPciDev, IOMMU_PCI_DEVICE_ID); /* VirtualBox IOMMU device */ 4313 PDMPciDevSetCommand(pPciDev, 0); /* Command */ 4314 PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST); /* Status - CapList supported */ 4315 PDMPciDevSetRevisionId(pPciDev, IOMMU_PCI_REVISION_ID); /* VirtualBox specific device implementation revision */ 4316 PDMPciDevSetClassBase(pPciDev, 0x08); /* System Base Peripheral */ 4317 PDMPciDevSetClassSub(pPciDev, 0x06); /* IOMMU */ 4318 PDMPciDevSetClassProg(pPciDev, 0x00); /* IOMMU Programming interface */ 4319 PDMPciDevSetHeaderType(pPciDev, 0x00); /* Single function, type 0. */ 4320 PDMPciDevSetSubSystemId(pPciDev, IOMMU_PCI_DEVICE_ID); /* AMD */ 4321 PDMPciDevSetSubSystemVendorId(pPciDev, IOMMU_PCI_VENDOR_ID); /* VirtualBox IOMMU device */ 4322 PDMPciDevSetCapabilityList(pPciDev, IOMMU_PCI_OFF_CAP_HDR); /* Offset into capability registers. */ 4323 PDMPciDevSetInterruptPin(pPciDev, 0x01); /* INTA#. */ 4324 PDMPciDevSetInterruptLine(pPciDev, 0x00); /* For software compatibility; no effect on hardware. */ 4325 4326 /* Capability Header. */ 4327 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_CAP_HDR, 4328 RT_BF_MAKE(IOMMU_BF_CAPHDR_CAP_ID, 0xf) /* RO - Secure Device capability block */ 4329 | RT_BF_MAKE(IOMMU_BF_CAPHDR_CAP_PTR, IOMMU_PCI_OFF_MSI_CAP_HDR) /* RO - Offset to next capability */ 4330 | RT_BF_MAKE(IOMMU_BF_CAPHDR_CAP_TYPE, 0x3) /* RO - IOMMU capability block */ 4331 | RT_BF_MAKE(IOMMU_BF_CAPHDR_CAP_REV, 0x1) /* RO - IOMMU interface revision */ 4332 | RT_BF_MAKE(IOMMU_BF_CAPHDR_IOTLB_SUP, 0x0) /* RO - Remote IOTLB support */ 4333 | RT_BF_MAKE(IOMMU_BF_CAPHDR_HT_TUNNEL, 0x0) /* RO - HyperTransport Tunnel support */ 4334 | RT_BF_MAKE(IOMMU_BF_CAPHDR_NP_CACHE, 0x0) /* RO - Cache NP page table entries */ 4335 | RT_BF_MAKE(IOMMU_BF_CAPHDR_EFR_SUP, 0x1) /* RO - Extended Feature Register support */ 4336 | RT_BF_MAKE(IOMMU_BF_CAPHDR_CAP_EXT, 0x1)); /* RO - Misc. Information Register support */ 4337 4338 /* Base Address Low Register. */ 4339 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_BASE_ADDR_REG_LO, 0x0); /* RW - Base address (Lo) and enable bit. */ 4340 4341 /* Base Address High Register. */ 4342 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_BASE_ADDR_REG_HI, 0x0); /* RW - Base address (Hi) */ 4343 4344 /* IOMMU Range Register. */ 4345 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_RANGE_REG, 0x0); /* RW - Range register (implemented as RO by us). */ 4346 4347 /* Misc. Information Register 0. */ 4348 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_MISCINFO_REG_0, 4349 RT_BF_MAKE(IOMMU_BF_MISCINFO_0_MSI_NUM, 0x0) /* RO - MSI number */ 4350 | RT_BF_MAKE(IOMMU_BF_MISCINFO_0_GVA_SIZE, 0x2) /* RO - Guest Virt. Addr size (2=48 bits) */ 4351 | RT_BF_MAKE(IOMMU_BF_MISCINFO_0_PA_SIZE, 0x30) /* RO - Physical Addr size (48 bits) */ 4352 | RT_BF_MAKE(IOMMU_BF_MISCINFO_0_VA_SIZE, 0x40) /* RO - Virt. Addr size (64 bits) */ 4353 | RT_BF_MAKE(IOMMU_BF_MISCINFO_0_HT_ATS_RESV, 0x0) /* RW - HT ATS reserved */ 4354 | RT_BF_MAKE(IOMMU_BF_MISCINFO_0_MSI_NUM_PPR, 0x0)); /* RW - PPR interrupt number */ 4355 4356 /* Misc. Information Register 1. */ 4357 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_MISCINFO_REG_0, 0); 4358 4359 /* MSI Capability Header register. */ 4360 PDMMSIREG MsiReg; 4361 RT_ZERO(MsiReg); 4362 MsiReg.cMsiVectors = 1; 4363 MsiReg.iMsiCapOffset = IOMMU_PCI_OFF_MSI_CAP_HDR; 4364 MsiReg.iMsiNextOffset = 0; /* IOMMU_PCI_OFF_MSI_MAP_CAP_HDR */ 4365 MsiReg.fMsi64bit = 1; /* 64-bit addressing support is mandatory; See AMD spec. 2.8 "IOMMU Interrupt Support". */ 4366 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg); 4367 AssertRCReturn(rc, rc); 4368 4369 /* MSI Address (Lo, Hi) and MSI data are read-write PCI config registers handled by our generic PCI config space code. */ 4370 #if 0 4371 /* MSI Address Lo. */ 4372 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_MSI_ADDR_LO, 0); /* RW - MSI message address (Lo). */ 4373 /* MSI Address Hi. */ 4374 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_MSI_ADDR_HI, 0); /* RW - MSI message address (Hi). */ 4375 /* MSI Data. */ 4376 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_MSI_DATA, 0); /* RW - MSI data. */ 4377 #endif 4378 4379 #if 0 4380 /** @todo IOMMU: I don't know if we need to support this, enable later if 4381 * required. */ 4382 /* MSI Mapping Capability Header register. */ 4383 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_MSI_MAP_CAP_HDR, 4384 RT_BF_MAKE(IOMMU_BF_MSI_MAP_CAPHDR_CAP_ID, 0x8) /* RO - Capability ID */ 4385 | RT_BF_MAKE(IOMMU_BF_MSI_MAP_CAPHDR_CAP_PTR, 0x0) /* RO - Offset to next capability (NULL) */ 4386 | RT_BF_MAKE(IOMMU_BF_MSI_MAP_CAPHDR_EN, 0x1) /* RO - MSI mapping capability enable */ 4387 | RT_BF_MAKE(IOMMU_BF_MSI_MAP_CAPHDR_FIXED, 0x1) /* RO - MSI mapping range is fixed */ 4388 | RT_BF_MAKE(IOMMU_BF_MSI_MAP_CAPHDR_CAP_TYPE, 0x15)); /* RO - MSI mapping capability */ 4389 /* When implementing don't forget to copy this to its MMIO shadow register (MsiMapCapHdr) in iommuAmdR3Init. */ 4390 #endif 4391 4392 /* 4393 * Register the PCI function with PDM. 4394 */ 4395 rc = PDMDevHlpPCIRegisterEx(pDevIns, pPciDev, 0 /* fFlags */, uPciDevice, uPciFunction, "amd-iommu"); 4396 AssertLogRelRCReturn(rc, rc); 4397 4398 /* 4399 * Intercept PCI config. space accesses. 4400 */ 4401 rc = PDMDevHlpPCIInterceptConfigAccesses(pDevIns, pPciDev, iommuAmdR3PciConfigRead, iommuAmdR3PciConfigWrite); 4402 AssertLogRelRCReturn(rc, rc); 4403 4404 /* 4405 * Create the MMIO region. 4406 * Mapping of the region is done when software configures it via PCI config space. 4407 */ 4408 rc = PDMDevHlpMmioCreate(pDevIns, IOMMU_MMIO_REGION_SIZE, pPciDev, 0 /* iPciRegion */, iommuAmdMmioWrite, iommuAmdMmioRead, 4409 NULL /* pvUser */, IOMMMIO_FLAGS_READ_DWORD_QWORD | IOMMMIO_FLAGS_WRITE_DWORD_QWORD_ZEROED, 4410 "AMD-IOMMU", &pThis->hMmio); 4411 AssertLogRelRCReturn(rc, rc); 4412 4413 /* 4414 * Register saved state. 4415 */ 4416 rc = PDMDevHlpSSMRegisterEx(pDevIns, IOMMU_SAVED_STATE_VERSION, sizeof(IOMMU), NULL, 4417 NULL, NULL, NULL, 4418 NULL, iommuAmdR3SaveExec, NULL, 4419 NULL, iommuAmdR3LoadExec, NULL); 4420 AssertLogRelRCReturn(rc, rc); 4421 4422 /* 4423 * Register debugger info item. 4424 */ 4425 rc = PDMDevHlpDBGFInfoRegister(pDevIns, "iommu", "Display IOMMU state.", iommuAmdR3DbgInfo); 4426 AssertLogRelRCReturn(rc, rc); 4427 4428 /* 4429 * Create the command thread and its event semaphore. 4430 */ 4431 rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->pCmdThread, pThis, iommuAmdR3CmdThread, iommuAmdR3CmdThreadWakeUp, 4432 0 /* cbStack */, RTTHREADTYPE_IO, "AMD-IOMMU"); 4433 AssertLogRelRCReturn(rc, rc); 4434 4435 rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->hEvtCmdThread); 4436 AssertLogRelRCReturn(rc, rc); 4437 4438 /* 4439 * Initialize read-only registers. 4440 */ 4441 /** @todo Don't remove the =0 assignment for now. It's just there so it's easier 4442 * for me to see existing features that we might want to implement. Do it 4443 * later. */ 4444 pThis->ExtFeat.u64 = 0; 4156 4445 pThis->ExtFeat.n.u1PrefetchSup = 0; 4157 4446 pThis->ExtFeat.n.u1PprSup = 0; … … 4163 4452 pThis->ExtFeat.n.u1HwErrorSup = 1; 4164 4453 pThis->ExtFeat.n.u1PerfCounterSup = 0; 4165 pThis->ExtFeat.n.u2HostAddrTranslateSize = 0; /* Requires GstTranslateSup. */4454 pThis->ExtFeat.n.u2HostAddrTranslateSize = IOMMU_MAX_HOST_PT_LEVEL; 4166 4455 pThis->ExtFeat.n.u2GstAddrTranslateSize = 0; /* Requires GstTranslateSup. */ 4167 4456 pThis->ExtFeat.n.u2GstCr3RootTblLevel = 0; /* Requires GstTranslateSup. */ … … 4190 4479 pThis->ExtFeat.n.u1ForcePhysDstSup = 0; 4191 4480 4192 pThis->PprLogBaseAddr.u64 = 0; 4193 pThis->PprLogBaseAddr.n.u4Len = 8; 4194 4195 pThis->HwEvtHi.u64 = 0; 4196 pThis->HwEvtLo = 0; 4197 pThis->HwEvtStatus.u64 = 0; 4198 4199 pThis->GALogBaseAddr.u64 = 0; 4200 pThis->GALogBaseAddr.n.u4Len = 8; 4201 pThis->GALogTailAddr.u64 = 0; 4202 4203 pThis->PprLogBBaseAddr.u64 = 0; 4204 pThis->PprLogBBaseAddr.n.u4Len = 8; 4205 4206 pThis->EvtLogBBaseAddr.u64 = 0; 4207 pThis->EvtLogBBaseAddr.n.u4Len = 8; 4208 4209 pThis->DevSpecificFeat.u64 = 0; 4210 pThis->DevSpecificCtrl.u64 = 0; 4211 pThis->DevSpecificStatus.u64 = 0; 4212 4213 pThis->MsiMiscInfo.u64 = 0; 4214 pThis->PerfOptCtrl.u32 = 0; 4215 4216 pThis->XtGenIntrCtrl.u64 = 0; 4217 pThis->XtPprIntrCtrl.u64 = 0; 4218 pThis->XtGALogIntrCtrl.u64 = 0; 4219 4220 memset(&pThis->aMarcApers[0], 0, sizeof(pThis->aMarcApers)); 4221 4222 pThis->RsvdReg = 0; 4223 4224 pThis->CmdBufHeadPtr.u64 = 0; 4225 pThis->CmdBufTailPtr.u64 = 0; 4226 pThis->EvtLogHeadPtr.u64 = 0; 4227 pThis->EvtLogTailPtr.u64 = 0; 4228 4229 pThis->Status.u64 = 0; 4230 4231 pThis->PprLogHeadPtr.u64 = 0; 4232 pThis->PprLogTailPtr.u64 = 0; 4233 4234 pThis->GALogHeadPtr.u64 = 0; 4235 pThis->GALogTailPtr.u64 = 0; 4236 4237 pThis->PprLogBHeadPtr.u64 = 0; 4238 pThis->PprLogBTailPtr.u64 = 0; 4239 4240 pThis->EvtLogBHeadPtr.u64 = 0; 4241 pThis->EvtLogBTailPtr.u64 = 0; 4242 4243 pThis->PprLogAutoResp.u64 = 0; 4244 pThis->PprLogOverflowEarly.u64 = 0; 4245 pThis->PprLogBOverflowEarly.u64 = 0; 4246 4247 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_BASE_ADDR_REG_LO, 0); 4248 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_BASE_ADDR_REG_HI, 0); 4249 } 4250 4251 4252 /** 4253 * @interface_method_impl{PDMDEVREG,pfnDestruct} 4254 */ 4255 static DECLCALLBACK(int) iommuAmdR3Destruct(PPDMDEVINS pDevIns) 4256 { 4257 PDMDEV_CHECK_VERSIONS_RETURN_QUIET(pDevIns); 4258 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 4259 LogFlowFunc(("\n")); 4260 4261 /* Close the command thread semaphore. */ 4262 if (pThis->hEvtCmdThread != NIL_SUPSEMEVENT) 4263 { 4264 PDMDevHlpSUPSemEventClose(pDevIns, pThis->hEvtCmdThread); 4265 pThis->hEvtCmdThread = NIL_SUPSEMEVENT; 4266 } 4267 return VINF_SUCCESS; 4268 } 4269 4270 4271 /** 4272 * @interface_method_impl{PDMDEVREG,pfnConstruct} 4273 */ 4274 static DECLCALLBACK(int) iommuAmdR3Construct(PPDMDEVINS pDevIns, int iInstance, PCFGMNODE pCfg) 4275 { 4276 NOREF(iInstance); 4277 4278 PDMDEV_CHECK_VERSIONS_RETURN(pDevIns); 4279 PIOMMU pThis = PDMDEVINS_2_DATA(pDevIns, PIOMMU); 4280 PIOMMUCC pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PIOMMUCC); 4281 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3; 4282 int rc; 4283 LogFlowFunc(("\n")); 4284 4285 pThisCC->pDevInsR3 = pDevIns; 4286 4287 /* 4288 * Validate and read the configuration. 4289 */ 4290 PDMDEV_VALIDATE_CONFIG_RETURN(pDevIns, "Device|Function", ""); 4291 4292 uint8_t uPciDevice; 4293 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "Device", &uPciDevice, 0); 4294 if (RT_FAILURE(rc)) 4295 return PDMDEV_SET_ERROR(pDevIns, rc, N_("IOMMU: Failed to query \"Device\"")); 4296 4297 uint8_t uPciFunction; 4298 rc = pHlp->pfnCFGMQueryU8Def(pCfg, "Function", &uPciFunction, 2); 4299 if (RT_FAILURE(rc)) 4300 return PDMDEV_SET_ERROR(pDevIns, rc, N_("IOMMU: Failed to query \"Function\"")); 4301 4302 /* 4303 * Register the IOMMU with PDM. 4304 */ 4305 PDMIOMMUREGR3 IommuReg; 4306 RT_ZERO(IommuReg); 4307 IommuReg.u32Version = PDM_IOMMUREGCC_VERSION; 4308 IommuReg.pfnMemRead = iommuAmdDeviceMemRead; 4309 IommuReg.pfnMemWrite = iommuAmdDeviceMemWrite; 4310 IommuReg.u32TheEnd = PDM_IOMMUREGCC_VERSION; 4311 rc = PDMDevHlpIommuRegister(pDevIns, &IommuReg, &pThisCC->CTX_SUFF(pIommuHlp), &pThis->idxIommu); 4312 if (RT_FAILURE(rc)) 4313 return PDMDEV_SET_ERROR(pDevIns, rc, N_("Failed to register ourselves as an IOMMU device")); 4314 if (pThisCC->CTX_SUFF(pIommuHlp)->u32Version != PDM_IOMMUHLPR3_VERSION) 4315 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS, 4316 N_("IOMMU helper version mismatch; got %#x expected %#x"), 4317 pThisCC->CTX_SUFF(pIommuHlp)->u32Version, PDM_IOMMUHLPR3_VERSION); 4318 if (pThisCC->CTX_SUFF(pIommuHlp)->u32TheEnd != PDM_IOMMUHLPR3_VERSION) 4319 return PDMDevHlpVMSetError(pDevIns, VERR_VERSION_MISMATCH, RT_SRC_POS, 4320 N_("IOMMU helper end-version mismatch; got %#x expected %#x"), 4321 pThisCC->CTX_SUFF(pIommuHlp)->u32TheEnd, PDM_IOMMUHLPR3_VERSION); 4322 4323 /* 4324 * Initialize read-only PCI configuration space. 4325 */ 4326 PPDMPCIDEV pPciDev = pDevIns->apPciDevs[0]; 4327 PDMPCIDEV_ASSERT_VALID(pDevIns, pPciDev); 4328 4329 /* Header. */ 4330 PDMPciDevSetVendorId(pPciDev, IOMMU_PCI_VENDOR_ID); /* AMD */ 4331 PDMPciDevSetDeviceId(pPciDev, IOMMU_PCI_DEVICE_ID); /* VirtualBox IOMMU device */ 4332 PDMPciDevSetCommand(pPciDev, 0); /* Command */ 4333 PDMPciDevSetStatus(pPciDev, VBOX_PCI_STATUS_CAP_LIST); /* Status - CapList supported */ 4334 PDMPciDevSetRevisionId(pPciDev, IOMMU_PCI_REVISION_ID); /* VirtualBox specific device implementation revision */ 4335 PDMPciDevSetClassBase(pPciDev, 0x08); /* System Base Peripheral */ 4336 PDMPciDevSetClassSub(pPciDev, 0x06); /* IOMMU */ 4337 PDMPciDevSetClassProg(pPciDev, 0x00); /* IOMMU Programming interface */ 4338 PDMPciDevSetHeaderType(pPciDev, 0x00); /* Single function, type 0. */ 4339 PDMPciDevSetSubSystemId(pPciDev, IOMMU_PCI_DEVICE_ID); /* AMD */ 4340 PDMPciDevSetSubSystemVendorId(pPciDev, IOMMU_PCI_VENDOR_ID); /* VirtualBox IOMMU device */ 4341 PDMPciDevSetCapabilityList(pPciDev, IOMMU_PCI_OFF_CAP_HDR); /* Offset into capability registers. */ 4342 PDMPciDevSetInterruptPin(pPciDev, 0x01); /* INTA#. */ 4343 PDMPciDevSetInterruptLine(pPciDev, 0x00); /* For software compatibility; no effect on hardware. */ 4344 4345 /* Capability Header. */ 4346 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_CAP_HDR, 4347 RT_BF_MAKE(IOMMU_BF_CAPHDR_CAP_ID, 0xf) /* RO - Secure Device capability block */ 4348 | RT_BF_MAKE(IOMMU_BF_CAPHDR_CAP_PTR, IOMMU_PCI_OFF_MSI_CAP_HDR) /* RO - Offset to next capability */ 4349 | RT_BF_MAKE(IOMMU_BF_CAPHDR_CAP_TYPE, 0x3) /* RO - IOMMU capability block */ 4350 | RT_BF_MAKE(IOMMU_BF_CAPHDR_CAP_REV, 0x1) /* RO - IOMMU interface revision */ 4351 | RT_BF_MAKE(IOMMU_BF_CAPHDR_IOTLB_SUP, 0x0) /* RO - Remote IOTLB support */ 4352 | RT_BF_MAKE(IOMMU_BF_CAPHDR_HT_TUNNEL, 0x0) /* RO - HyperTransport Tunnel support */ 4353 | RT_BF_MAKE(IOMMU_BF_CAPHDR_NP_CACHE, 0x0) /* RO - Cache NP page table entries */ 4354 | RT_BF_MAKE(IOMMU_BF_CAPHDR_EFR_SUP, 0x1) /* RO - Extended Feature Register support */ 4355 | RT_BF_MAKE(IOMMU_BF_CAPHDR_CAP_EXT, 0x1)); /* RO - Misc. Information Register support */ 4356 4357 /* Base Address Low Register. */ 4358 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_BASE_ADDR_REG_LO, 0x0); /* RW - Base address (Lo) and enable bit. */ 4359 4360 /* Base Address High Register. */ 4361 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_BASE_ADDR_REG_HI, 0x0); /* RW - Base address (Hi) */ 4362 4363 /* IOMMU Range Register. */ 4364 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_RANGE_REG, 0x0); /* RW - Range register (implemented as RO by us). */ 4365 4366 /* Misc. Information Register 0. */ 4367 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_MISCINFO_REG_0, 4368 RT_BF_MAKE(IOMMU_BF_MISCINFO_0_MSI_NUM, 0x0) /* RO - MSI number */ 4369 | RT_BF_MAKE(IOMMU_BF_MISCINFO_0_GVA_SIZE, 0x2) /* RO - Guest Virt. Addr size (2=48 bits) */ 4370 | RT_BF_MAKE(IOMMU_BF_MISCINFO_0_PA_SIZE, 0x30) /* RO - Physical Addr size (48 bits) */ 4371 | RT_BF_MAKE(IOMMU_BF_MISCINFO_0_VA_SIZE, 0x40) /* RO - Virt. Addr size (64 bits) */ 4372 | RT_BF_MAKE(IOMMU_BF_MISCINFO_0_HT_ATS_RESV, 0x0) /* RW - HT ATS reserved */ 4373 | RT_BF_MAKE(IOMMU_BF_MISCINFO_0_MSI_NUM_PPR, 0x0)); /* RW - PPR interrupt number */ 4374 4375 /* Misc. Information Register 1. */ 4376 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_MISCINFO_REG_0, 0); 4377 4378 /* MSI Capability Header register. */ 4379 PDMMSIREG MsiReg; 4380 RT_ZERO(MsiReg); 4381 MsiReg.cMsiVectors = 1; 4382 MsiReg.iMsiCapOffset = IOMMU_PCI_OFF_MSI_CAP_HDR; 4383 MsiReg.iMsiNextOffset = 0; /* IOMMU_PCI_OFF_MSI_MAP_CAP_HDR */ 4384 MsiReg.fMsi64bit = 1; /* 64-bit addressing support is mandatory; See AMD spec. 2.8 "IOMMU Interrupt Support". */ 4385 rc = PDMDevHlpPCIRegisterMsi(pDevIns, &MsiReg); 4386 AssertRCReturn(rc, rc); 4387 4388 /* MSI Address (Lo, Hi) and MSI data are read-write PCI config registers handled by our generic PCI config space code. */ 4389 #if 0 4390 /* MSI Address Lo. */ 4391 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_MSI_ADDR_LO, 0); /* RW - MSI message address (Lo). */ 4392 /* MSI Address Hi. */ 4393 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_MSI_ADDR_HI, 0); /* RW - MSI message address (Hi). */ 4394 /* MSI Data. */ 4395 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_MSI_DATA, 0); /* RW - MSI data. */ 4396 #endif 4397 4398 #if 0 4399 /** @todo IOMMU: I don't know if we need to support this, enable later if 4400 * required. */ 4401 /* MSI Mapping Capability Header register. */ 4402 PDMPciDevSetDWord(pPciDev, IOMMU_PCI_OFF_MSI_MAP_CAP_HDR, 4403 RT_BF_MAKE(IOMMU_BF_MSI_MAP_CAPHDR_CAP_ID, 0x8) /* RO - Capability ID */ 4404 | RT_BF_MAKE(IOMMU_BF_MSI_MAP_CAPHDR_CAP_PTR, 0x0) /* RO - Offset to next capability (NULL) */ 4405 | RT_BF_MAKE(IOMMU_BF_MSI_MAP_CAPHDR_EN, 0x1) /* RO - MSI mapping capability enable */ 4406 | RT_BF_MAKE(IOMMU_BF_MSI_MAP_CAPHDR_FIXED, 0x1) /* RO - MSI mapping range is fixed */ 4407 | RT_BF_MAKE(IOMMU_BF_MSI_MAP_CAPHDR_CAP_TYPE, 0x15)); /* RO - MSI mapping capability */ 4408 /* When implementing don't forget to copy this to its MMIO shadow register (MsiMapCapHdr) in iommuAmdR3Init. */ 4409 #endif 4410 4411 /* 4412 * Register the PCI function with PDM. 4413 */ 4414 rc = PDMDevHlpPCIRegisterEx(pDevIns, pPciDev, 0 /* fFlags */, uPciDevice, uPciFunction, "amd-iommu"); 4415 AssertLogRelRCReturn(rc, rc); 4416 4417 /* 4418 * Intercept PCI config. space accesses. 4419 */ 4420 rc = PDMDevHlpPCIInterceptConfigAccesses(pDevIns, pPciDev, iommuAmdR3PciConfigRead, iommuAmdR3PciConfigWrite); 4421 AssertLogRelRCReturn(rc, rc); 4422 4423 /* 4424 * Create the MMIO region. 4425 * Mapping of the region is done when software configures it via PCI config space. 4426 */ 4427 rc = PDMDevHlpMmioCreate(pDevIns, IOMMU_MMIO_REGION_SIZE, pPciDev, 0 /* iPciRegion */, iommuAmdMmioWrite, iommuAmdMmioRead, 4428 NULL /* pvUser */, IOMMMIO_FLAGS_READ_DWORD_QWORD | IOMMMIO_FLAGS_WRITE_DWORD_QWORD_ZEROED, 4429 "AMD-IOMMU", &pThis->hMmio); 4430 AssertLogRelRCReturn(rc, rc); 4431 4432 /* 4433 * Register saved state. 4434 */ 4435 rc = PDMDevHlpSSMRegisterEx(pDevIns, IOMMU_SAVED_STATE_VERSION, sizeof(IOMMU), NULL, 4436 NULL, NULL, NULL, 4437 NULL, iommuAmdR3SaveExec, NULL, 4438 NULL, iommuAmdR3LoadExec, NULL); 4439 AssertLogRelRCReturn(rc, rc); 4440 4441 /* 4442 * Register debugger info item. 4443 */ 4444 rc = PDMDevHlpDBGFInfoRegister(pDevIns, "iommu", "Display IOMMU state.", iommuAmdR3DbgInfo); 4445 AssertLogRelRCReturn(rc, rc); 4446 4447 /* 4448 * Create the command thread and its event semaphore. 4449 */ 4450 rc = PDMDevHlpThreadCreate(pDevIns, &pThisCC->pCmdThread, pThis, iommuAmdR3CmdThread, iommuAmdR3CmdThreadWakeUp, 4451 0 /* cbStack */, RTTHREADTYPE_IO, "AMD-IOMMU"); 4452 AssertLogRelRCReturn(rc, rc); 4453 4454 rc = PDMDevHlpSUPSemEventCreate(pDevIns, &pThis->hEvtCmdThread); 4455 AssertLogRelRCReturn(rc, rc); 4481 pThis->RsvdReg = 0; 4456 4482 4457 4483 /*
Note:
See TracChangeset
for help on using the changeset viewer.