Changeset 108398 in vbox for trunk/src/VBox/VMM/VMMR3/GICR3Nem-win.cpp
- Timestamp:
- Feb 26, 2025 4:41:49 PM (2 months ago)
- svn:sync-xref-src-repo-rev:
- 167763
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/VMM/VMMR3/GICR3Nem-win.cpp
r107929 r108398 33 33 #include <iprt/nt/nt-and-windows.h> 34 34 #include <iprt/nt/hyperv.h> 35 #include <iprt/mem.h> 35 36 #include <WinHvPlatform.h> 36 37 … … 54 55 * Defined Constants And Macros * 55 56 *********************************************************************************************************************************/ 57 /** The current GIC saved state version. */ 58 #define GIC_NEM_SAVED_STATE_VERSION 1 56 59 57 60 … … 110 113 111 114 115 typedef struct MY_WHV_INTERRUPT_STATE 116 { 117 uint8_t fState; 118 uint8_t bIPriorityCfg; 119 uint8_t bIPriorityActive; 120 uint8_t bRsvd0; 121 } MY_WHV_INTERRUPT_STATE; 122 AssertCompileSize(MY_WHV_INTERRUPT_STATE, sizeof(uint32_t)); 123 124 #define WHV_INTERRUPT_STATE_F_ENABLED RT_BIT(0) 125 #define WHV_INTERRUPT_STATE_F_EDGE_TRIGGERED RT_BIT(1) 126 #define WHV_INTERRUPT_STATE_F_ASSERTED RT_BIT(2) 127 #define WHV_INTERRUPT_STATE_F_SET_PENDING RT_BIT(3) 128 #define WHV_INTERRUPT_STATE_F_ACTIVE RT_BIT(4) 129 #define WHV_INTERRUPT_STATE_F_DIRECT RT_BIT(5) 130 131 132 typedef struct MY_WHV_GLOBAL_INTERRUPT_STATE 133 { 134 uint32_t u32IntId; 135 uint32_t idActiveVp; 136 uint32_t u32TargetMpidrOrVpIndex; 137 MY_WHV_INTERRUPT_STATE State; 138 } MY_WHV_GLOBAL_INTERRUPT_STATE; 139 AssertCompileSize(MY_WHV_GLOBAL_INTERRUPT_STATE, 4 * sizeof(uint32_t)); 140 141 142 typedef struct MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE 143 { 144 uint8_t bVersion; 145 uint8_t bGicVersion; 146 uint8_t abPad[2]; 147 148 uint32_t cInterrupts; 149 uint64_t u64RegGicdCtrlEnableGrp1A; 150 151 MY_WHV_GLOBAL_INTERRUPT_STATE aSpis[1]; /* Flexible */ 152 } MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE; 153 AssertCompileSize(MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE, 2 * sizeof(uint32_t) + sizeof(uint64_t) + sizeof(MY_WHV_GLOBAL_INTERRUPT_STATE)); 154 155 #define MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE_VERSION 1 156 157 158 typedef struct MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE 159 { 160 uint8_t bVersion; 161 uint8_t bGicVersion; 162 uint8_t abPad[6]; 163 164 uint64_t u64RegIccIGrpEn1El1; 165 uint64_t u64RegGicrCtrlEnableLpis; 166 uint64_t u64RegIccBprEl1; 167 uint64_t u64RegIccPmrEl1; 168 uint64_t u64RegGicrPropBase; 169 uint64_t u64RegGicrPendBase; 170 171 uint32_t au32RegIchAp1REl2[4]; 172 173 MY_WHV_INTERRUPT_STATE aPpiStates[32]; 174 } MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE; 175 AssertCompileSize(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, 7 * sizeof(uint64_t) + 4 * sizeof(uint32_t) + 32 * sizeof(MY_WHV_INTERRUPT_STATE)); 176 177 #define MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE_VERSION 1 178 179 #define MY_WHV_VIRTUAL_PROCESSOR_STATE_TYPE_LOCAL_INTERRUPT_CTRL (WHV_VIRTUAL_PROCESSOR_STATE_TYPE)0x00001000 180 #define MY_WHV_VIRTUAL_PROCESSOR_STATE_TYPE_GLOBAL_INTERRUPT_CTRL (WHV_VIRTUAL_PROCESSOR_STATE_TYPE)0x00001003 181 182 112 183 /********************************************************************************************************************************* 113 184 * Global Variables * 114 185 *********************************************************************************************************************************/ 115 extern decltype(WHvRequestInterrupt) * g_pfnWHvRequestInterrupt; 186 extern decltype(WHvGetVirtualProcessorState) * g_pfnWHvGetVirtualProcessorState; 187 extern decltype(WHvSetVirtualProcessorState) * g_pfnWHvSetVirtualProcessorState; 188 extern decltype(WHvRequestInterrupt) * g_pfnWHvRequestInterrupt; 116 189 117 190 /* … … 119 192 */ 120 193 #ifndef IN_SLICKEDIT 121 # define WHvRequestInterrupt g_pfnWHvRequestInterrupt 194 # define WHvGetVirtualProcessorState g_pfnWHvGetVirtualProcessorState 195 # define WHvSetVirtualProcessorState g_pfnWHvSetVirtualProcessorState 196 # define WHvRequestInterrupt g_pfnWHvRequestInterrupt 122 197 #endif 198 199 200 /** Saved state field descriptors for the global interrupt state. */ 201 static const SSMFIELD g_aWHvGicGlobalInterruptState[] = 202 { 203 SSMFIELD_ENTRY(MY_WHV_GLOBAL_INTERRUPT_STATE, u32IntId), 204 SSMFIELD_ENTRY(MY_WHV_GLOBAL_INTERRUPT_STATE, idActiveVp), 205 SSMFIELD_ENTRY(MY_WHV_GLOBAL_INTERRUPT_STATE, u32TargetMpidrOrVpIndex), 206 SSMFIELD_ENTRY(MY_WHV_GLOBAL_INTERRUPT_STATE, State.fState), 207 SSMFIELD_ENTRY(MY_WHV_GLOBAL_INTERRUPT_STATE, State.bIPriorityCfg), 208 SSMFIELD_ENTRY(MY_WHV_GLOBAL_INTERRUPT_STATE, State.bIPriorityActive), 209 SSMFIELD_ENTRY_TERM() 210 }; 211 212 213 /** Saved state field descriptors for the global GIC state (sans the flexible interrupts array. */ 214 static const SSMFIELD g_aWHvGicGlobalState[] = 215 { 216 SSMFIELD_ENTRY(MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE, bGicVersion), 217 SSMFIELD_ENTRY(MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE, cInterrupts), 218 SSMFIELD_ENTRY(MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE, u64RegGicdCtrlEnableGrp1A), 219 SSMFIELD_ENTRY_TERM() 220 }; 221 222 223 #define GIC_NEM_HV_PPI_STATE(a_idx) \ 224 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, aPpiStates[a_idx].fState), \ 225 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, aPpiStates[a_idx].bIPriorityCfg), \ 226 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, aPpiStates[a_idx].bIPriorityActive) 227 228 229 /** Saved state field descriptors for the local interrupt controller state. */ 230 static const SSMFIELD g_aWHvGicLocalInterruptState[] = 231 { 232 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, bGicVersion), 233 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, u64RegIccIGrpEn1El1), 234 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, u64RegGicrCtrlEnableLpis), 235 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, u64RegIccBprEl1), 236 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, u64RegIccPmrEl1), 237 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, u64RegGicrPropBase), 238 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, u64RegGicrPendBase), 239 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, au32RegIchAp1REl2[0]), 240 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, au32RegIchAp1REl2[1]), 241 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, au32RegIchAp1REl2[2]), 242 SSMFIELD_ENTRY(MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE, au32RegIchAp1REl2[3]), 243 GIC_NEM_HV_PPI_STATE(0), 244 GIC_NEM_HV_PPI_STATE(1), 245 GIC_NEM_HV_PPI_STATE(2), 246 GIC_NEM_HV_PPI_STATE(3), 247 GIC_NEM_HV_PPI_STATE(4), 248 GIC_NEM_HV_PPI_STATE(5), 249 GIC_NEM_HV_PPI_STATE(6), 250 GIC_NEM_HV_PPI_STATE(7), 251 GIC_NEM_HV_PPI_STATE(8), 252 GIC_NEM_HV_PPI_STATE(9), 253 GIC_NEM_HV_PPI_STATE(10), 254 GIC_NEM_HV_PPI_STATE(11), 255 GIC_NEM_HV_PPI_STATE(12), 256 GIC_NEM_HV_PPI_STATE(13), 257 GIC_NEM_HV_PPI_STATE(14), 258 GIC_NEM_HV_PPI_STATE(15), 259 GIC_NEM_HV_PPI_STATE(16), 260 GIC_NEM_HV_PPI_STATE(17), 261 GIC_NEM_HV_PPI_STATE(18), 262 GIC_NEM_HV_PPI_STATE(19), 263 GIC_NEM_HV_PPI_STATE(20), 264 GIC_NEM_HV_PPI_STATE(21), 265 GIC_NEM_HV_PPI_STATE(22), 266 GIC_NEM_HV_PPI_STATE(23), 267 GIC_NEM_HV_PPI_STATE(24), 268 GIC_NEM_HV_PPI_STATE(25), 269 GIC_NEM_HV_PPI_STATE(26), 270 GIC_NEM_HV_PPI_STATE(27), 271 GIC_NEM_HV_PPI_STATE(28), 272 GIC_NEM_HV_PPI_STATE(29), 273 GIC_NEM_HV_PPI_STATE(30), 274 GIC_NEM_HV_PPI_STATE(31), 275 SSMFIELD_ENTRY_TERM() 276 }; 123 277 124 278 … … 199 353 200 354 /** 355 * @copydoc FNSSMDEVSAVEEXEC 356 */ 357 static DECLCALLBACK(int) gicR3HvSaveExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM) 358 { 359 PGICHVDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICHVDEV); 360 PVM pVM = PDMDevHlpGetVM(pDevIns); 361 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3; 362 363 AssertReturn(pVM, VERR_INVALID_VM_HANDLE); 364 365 LogFlowFunc(("Enter\n")); 366 367 /* 368 * Save the global interrupt state first. 369 */ 370 /** @todo The saved state is not final because it would be great if we could have 371 * a compatible saved state format between all possible GIC variants (no idea whether this is feasible). 372 */ 373 uint32_t cbWritten = 0; 374 HRESULT hrc = WHvGetVirtualProcessorState(pThis->hPartition, WHV_ANY_VP, MY_WHV_VIRTUAL_PROCESSOR_STATE_TYPE_GLOBAL_INTERRUPT_CTRL, 375 NULL, 0, &cbWritten); 376 AssertLogRelMsgReturn(hrc == WHV_E_INSUFFICIENT_BUFFER, 377 ("WHvGetVirtualProcessorState(%p, WHV_ANY_VP, WHvVirtualProcessorStateTypeGlobalInterruptState,) -> %Rhrc (Last=%#x/%u)\n", 378 pVM->nem.s.hPartition, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()) 379 , VERR_NEM_GET_REGISTERS_FAILED); 380 381 /* Allocate a buffer to write the whole state to based on the amount of interrupts indicated. */ 382 uint32_t const cbState = cbWritten; 383 MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE *pState = (MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE *)RTMemTmpAllocZ(cbState); 384 AssertLogRelMsgReturn(pState, ("Allocating %u bytes of memory for the global interrupt state buffer failed\n", cbState), 385 VERR_NO_MEMORY); 386 387 hrc = WHvGetVirtualProcessorState(pThis->hPartition, WHV_ANY_VP, MY_WHV_VIRTUAL_PROCESSOR_STATE_TYPE_GLOBAL_INTERRUPT_CTRL, 388 pState, cbState, &cbWritten); 389 AssertLogRelMsg(SUCCEEDED(hrc), 390 ("WHvGetVirtualProcessorState(%p, WHV_ANY_VP, WHvVirtualProcessorStateTypeGlobalInterruptState, %p, %u) -> %Rhrc (Last=%#x/%u)\n", 391 pVM->nem.s.hPartition, pState, cbState, hrc, RTNtLastStatusValue(), RTNtLastErrorValue())); 392 AssertLogRelMsgReturn(cbWritten == cbState, 393 ("WHvGetVirtualProcessorState(%p, WHV_ANY_VP, WHvVirtualProcessorStateTypeGlobalInterruptState,) -> cbWritten=%u vs expected=%u\n", 394 pVM->nem.s.hPartition, cbWritten, cbState); 395 , VERR_NEM_GET_REGISTERS_FAILED); 396 AssertLogRelMsgReturn(pState->bVersion == MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE_VERSION, 397 ("WHvGetVirtualProcessorState(%p, WHV_ANY_VP, WHvVirtualProcessorStateTypeGlobalInterruptState,) -> bVersion=%u vs expected=%u\n", 398 pVM->nem.s.hPartition, pState->bVersion, MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE_VERSION); 399 , VERR_NEM_GET_REGISTERS_FAILED); 400 401 if (SUCCEEDED(hrc)) 402 { 403 pHlp->pfnSSMPutStruct(pSSM, (const void *)pState, &g_aWHvGicGlobalState[0]); 404 for (uint32_t i = 0; i < pState->cInterrupts; i++) 405 pHlp->pfnSSMPutStruct(pSSM, (const void *)&pState->aSpis[i], &g_aWHvGicGlobalInterruptState[0]); 406 } 407 408 RTMemTmpFree(pState); 409 if (FAILED(hrc)) 410 return VERR_NEM_GET_REGISTERS_FAILED; 411 412 /* 413 * Now for the local interrupt state for each vCPU. 414 */ 415 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++) 416 { 417 MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE LocalState; 418 419 hrc = WHvGetVirtualProcessorState(pThis->hPartition, idCpu, MY_WHV_VIRTUAL_PROCESSOR_STATE_TYPE_LOCAL_INTERRUPT_CTRL, 420 &LocalState, sizeof(LocalState), &cbWritten); 421 AssertLogRelMsgReturn(SUCCEEDED(hrc), 422 ("WHvGetVirtualProcessorState(%p, WHV_ANY_VP, WHvVirtualProcessorStateTypeInterruptControllerState2,) -> %Rhrc (Last=%#x/%u)\n", 423 pVM->nem.s.hPartition, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()) 424 , VERR_NEM_GET_REGISTERS_FAILED); 425 AssertLogRelMsgReturn(cbWritten == sizeof(LocalState), 426 ("WHvGetVirtualProcessorState(%p, WHV_ANY_VP, WHvVirtualProcessorStateTypeInterruptControllerState2,) -> cbWritten=%u vs expected=%u\n", 427 pVM->nem.s.hPartition, cbWritten, sizeof(LocalState)); 428 , VERR_NEM_GET_REGISTERS_FAILED); 429 AssertLogRelMsgReturn(LocalState.bVersion == MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE_VERSION, 430 ("WHvGetVirtualProcessorState(%p, %u, WHvVirtualProcessorStateTypeInterruptControllerState2,) -> bVersion=%u vs expected=%u\n", 431 pVM->nem.s.hPartition, idCpu, LocalState.bVersion, MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE_VERSION); 432 , VERR_NEM_GET_REGISTERS_FAILED); 433 434 pHlp->pfnSSMPutStruct(pSSM, (const void *)&LocalState, &g_aWHvGicLocalInterruptState[0]); 435 436 /* 437 * Check that we're still good wrt restored data. 438 */ 439 int rc = pHlp->pfnSSMHandleGetStatus(pSSM); 440 AssertRCReturn(rc, rc); 441 } 442 443 return VINF_SUCCESS; 444 } 445 446 447 /** 448 * @copydoc FNSSMDEVLOADEXEC 449 */ 450 static DECLCALLBACK(int) gicR3HvLoadExec(PPDMDEVINS pDevIns, PSSMHANDLE pSSM, uint32_t uVersion, uint32_t uPass) 451 { 452 PGICHVDEV pThis = PDMDEVINS_2_DATA(pDevIns, PGICHVDEV); 453 PVM pVM = PDMDevHlpGetVM(pDevIns); 454 PCPDMDEVHLPR3 pHlp = pDevIns->pHlpR3; 455 456 AssertReturn(pVM, VERR_INVALID_VM_HANDLE); 457 AssertReturn(uPass == SSM_PASS_FINAL, VERR_WRONG_ORDER); 458 459 LogFlowFunc(("uVersion=%u uPass=%#x\n", uVersion, uPass)); 460 461 /* Weed out invalid versions. */ 462 if (uVersion != GIC_NEM_SAVED_STATE_VERSION) 463 { 464 LogRel(("GIC: gicR3HvLoadExec: Invalid/unrecognized saved-state version %u (%#x)\n", uVersion, uVersion)); 465 return VERR_SSM_UNSUPPORTED_DATA_UNIT_VERSION; 466 } 467 468 /* 469 * Restore the global state. 470 */ 471 MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE GlobalState; RT_ZERO(GlobalState); 472 int rc = pHlp->pfnSSMGetStruct(pSSM, &GlobalState, &g_aWHvGicGlobalState[0]); 473 AssertRCReturn(rc, rc); 474 475 if (GlobalState.cInterrupts >= _64K) /* Interrupt IDs are 16-bit. */ 476 return VERR_INVALID_PARAMETER; 477 478 /* Calculate size of the final buffer and allocate. */ 479 uint32_t const cbState = RT_UOFFSETOF_DYN(MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE, aSpis[GlobalState.cInterrupts]); 480 MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE *pState = (MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE *)RTMemTmpAllocZ(cbState); 481 AssertLogRelMsgReturn(pState, ("Allocating %u bytes of memory for the global interrupt state buffer failed\n", cbState), 482 VERR_NO_MEMORY); 483 484 pState->bVersion = MY_WHV_GLOBAL_INTERRUPT_CONTROLLER_STATE_VERSION; 485 pState->bGicVersion = GlobalState.bGicVersion; 486 pState->cInterrupts = GlobalState.cInterrupts; 487 pState->u64RegGicdCtrlEnableGrp1A = GlobalState.u64RegGicdCtrlEnableGrp1A; 488 for (uint32_t i = 0; i < pState->cInterrupts; i++) 489 { 490 rc = pHlp->pfnSSMGetStruct(pSSM, &pState->aSpis[i], &g_aWHvGicGlobalInterruptState[0]); 491 if (RT_FAILURE(rc)) 492 break; 493 } 494 AssertRCReturnStmt(rc, RTMemTmpFree(pState), rc); 495 496 HRESULT hrc = WHvSetVirtualProcessorState(pThis->hPartition, WHV_ANY_VP, MY_WHV_VIRTUAL_PROCESSOR_STATE_TYPE_GLOBAL_INTERRUPT_CTRL, 497 pState, cbState); 498 RTMemTmpFree(pState); 499 pState = NULL; 500 501 AssertLogRelMsgReturn(SUCCEEDED(hrc), 502 ("WHvSetVirtualProcessorState(%p, WHV_ANY_VP, WHvVirtualProcessorStateTypeGlobalInterruptState,,%u) -> %Rhrc (Last=%#x/%u)\n", 503 pVM->nem.s.hPartition, cbState, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()) 504 , VERR_NEM_SET_REGISTERS_FAILED); 505 506 /* 507 * Restore per CPU state. 508 */ 509 for (VMCPUID idCpu = 0; idCpu < pVM->cCpus; idCpu++) 510 { 511 MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE LocalState; 512 RT_ZERO(LocalState); 513 514 rc = pHlp->pfnSSMGetStruct(pSSM, &LocalState, &g_aWHvGicLocalInterruptState[0]); 515 AssertRCReturn(rc, rc); 516 517 LocalState.bVersion = MY_WHV_LOCAL_INTERRUPT_CONTROLLER_STATE_VERSION; 518 519 hrc = WHvSetVirtualProcessorState(pThis->hPartition, idCpu, MY_WHV_VIRTUAL_PROCESSOR_STATE_TYPE_LOCAL_INTERRUPT_CTRL, 520 &LocalState, sizeof(LocalState)); 521 AssertLogRelMsgReturn(SUCCEEDED(hrc), 522 ("WHvSetVirtualProcessorState(%p, %u, WHvVirtualProcessorStateTypeInterruptControllerState2,) -> %Rhrc (Last=%#x/%u)\n", 523 pVM->nem.s.hPartition, idCpu, hrc, RTNtLastStatusValue(), RTNtLastErrorValue()) 524 , VERR_NEM_SET_REGISTERS_FAILED); 525 } 526 527 return VINF_SUCCESS; 528 } 529 530 531 /** 201 532 * @interface_method_impl{PDMDEVREG,pfnReset} 202 533 */ … … 278 609 return PDMDEV_SET_ERROR(pDevIns, rc, 279 610 N_("Configuration error: Failed to get the \"RedistributorMmioBase\" value")); 611 612 /* 613 * Register saved state callbacks. 614 */ 615 rc = PDMDevHlpSSMRegister(pDevIns, GIC_NEM_SAVED_STATE_VERSION, 0 /*cbGuess*/, gicR3HvSaveExec, gicR3HvLoadExec); 616 AssertRCReturn(rc, rc); 280 617 281 618 gicR3HvReset(pDevIns);
Note:
See TracChangeset
for help on using the changeset viewer.