Changeset 108434 in vbox
- Timestamp:
- Mar 4, 2025 11:24:21 AM (2 months ago)
- svn:sync-xref-src-repo-rev:
- 167808
- Location:
- trunk
- Files:
-
- 1 added
- 7 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/include/VBox/vmm/pdmdev.h
r107308 r108434 755 755 /** The PDM APIC device registration structure. */ 756 756 extern const PDMDEVREG g_DeviceAPIC; 757 # if defined(RT_OS_WINDOWS) 758 /** The PDM APIC device registration structure for the Hyper-V NEM. */ 759 extern const PDMDEVREG g_DeviceAPICNem; 760 # endif 757 761 #elif defined(VBOX_VMM_TARGET_ARMV8) 758 762 /** The PDM GIC device registration structure. */ -
trunk/src/VBox/VMM/Makefile.kmk
r108409 r108434 311 311 VBoxVMM_SOURCES.linux.amd64 += VMMR3/NEMR3Native-linux.cpp 312 312 313 VBoxVMM_SOURCES.win.amd64 += VMMR3/NEMR3Native-win.cpp 313 VBoxVMM_SOURCES.win.amd64 += \ 314 VMMR3/NEMR3Native-win.cpp \ 315 VMMR3/APICR3Nem-win.cpp 316 314 317 VBoxVMM_DEFS.win.amd64 += VBOX_WITH_NATIVE_NEM 315 318 VBoxVMM_SDKS.win += VBoxNtDll -
trunk/src/VBox/VMM/VMMAll/NEMAllNativeTemplate-win.cpp.h
r108076 r108434 365 365 ADD_REG64(WHvRegisterPendingInterruption, 0); 366 366 367 /* Interruptibility state. This can get a little complicated since we get 368 half of the state via HV_X64_VP_EXECUTION_STATE. */ 369 if ( (fWhat & (CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI)) 370 == (CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI) ) 371 { 372 ADD_REG64(WHvRegisterInterruptState, 0); 373 if (CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx)) 374 aValues[iReg - 1].InterruptState.InterruptShadow = 1; 375 aValues[iReg - 1].InterruptState.NmiMasked = CPUMAreInterruptsInhibitedByNmi(&pVCpu->cpum.GstCtx); 376 } 377 else if (fWhat & CPUMCTX_EXTRN_INHIBIT_INT) 378 { 379 if ( pVCpu->nem.s.fLastInterruptShadow 380 || CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx)) 367 if (!pVM->nem.s.fLocalApicEmulation) 368 { 369 /* Interruptibility state. This can get a little complicated since we get 370 half of the state via HV_X64_VP_EXECUTION_STATE. */ 371 if ( (fWhat & (CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI)) 372 == (CPUMCTX_EXTRN_INHIBIT_INT | CPUMCTX_EXTRN_INHIBIT_NMI) ) 381 373 { 382 374 ADD_REG64(WHvRegisterInterruptState, 0); 383 375 if (CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx)) 384 376 aValues[iReg - 1].InterruptState.InterruptShadow = 1; 385 /** @todo Retrieve NMI state, currently assuming it's zero. (yes this may happen on I/O) */ 386 //if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_BLOCK_NMIS)) 387 // aValues[iReg - 1].InterruptState.NmiMasked = 1; 388 } 389 } 390 else 391 Assert(!(fWhat & CPUMCTX_EXTRN_INHIBIT_NMI)); 392 393 /* Interrupt windows. Always set if active as Hyper-V seems to be forgetful. */ 394 uint8_t const fDesiredIntWin = pVCpu->nem.s.fDesiredInterruptWindows; 395 if ( fDesiredIntWin 396 || pVCpu->nem.s.fCurrentInterruptWindows != fDesiredIntWin) 397 { 398 pVCpu->nem.s.fCurrentInterruptWindows = pVCpu->nem.s.fDesiredInterruptWindows; 399 Log8(("Setting WHvX64RegisterDeliverabilityNotifications, fDesiredIntWin=%X\n", fDesiredIntWin)); 400 ADD_REG64(WHvX64RegisterDeliverabilityNotifications, fDesiredIntWin); 401 Assert(aValues[iReg - 1].DeliverabilityNotifications.NmiNotification == RT_BOOL(fDesiredIntWin & NEM_WIN_INTW_F_NMI)); 402 Assert(aValues[iReg - 1].DeliverabilityNotifications.InterruptNotification == RT_BOOL(fDesiredIntWin & NEM_WIN_INTW_F_REGULAR)); 403 Assert(aValues[iReg - 1].DeliverabilityNotifications.InterruptPriority == (unsigned)((fDesiredIntWin & NEM_WIN_INTW_F_PRIO_MASK) >> NEM_WIN_INTW_F_PRIO_SHIFT)); 404 } 405 406 /// @todo WHvRegisterPendingEvent 377 aValues[iReg - 1].InterruptState.NmiMasked = CPUMAreInterruptsInhibitedByNmi(&pVCpu->cpum.GstCtx); 378 } 379 else if (fWhat & CPUMCTX_EXTRN_INHIBIT_INT) 380 { 381 if ( pVCpu->nem.s.fLastInterruptShadow 382 || CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx)) 383 { 384 ADD_REG64(WHvRegisterInterruptState, 0); 385 if (CPUMIsInInterruptShadow(&pVCpu->cpum.GstCtx)) 386 aValues[iReg - 1].InterruptState.InterruptShadow = 1; 387 /** @todo Retrieve NMI state, currently assuming it's zero. (yes this may happen on I/O) */ 388 //if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_BLOCK_NMIS)) 389 // aValues[iReg - 1].InterruptState.NmiMasked = 1; 390 } 391 } 392 else 393 Assert(!(fWhat & CPUMCTX_EXTRN_INHIBIT_NMI)); 394 395 /* Interrupt windows. Always set if active as Hyper-V seems to be forgetful. */ 396 uint8_t const fDesiredIntWin = pVCpu->nem.s.fDesiredInterruptWindows; 397 if ( fDesiredIntWin 398 || pVCpu->nem.s.fCurrentInterruptWindows != fDesiredIntWin) 399 { 400 pVCpu->nem.s.fCurrentInterruptWindows = pVCpu->nem.s.fDesiredInterruptWindows; 401 Log8(("Setting WHvX64RegisterDeliverabilityNotifications, fDesiredIntWin=%X\n", fDesiredIntWin)); 402 ADD_REG64(WHvX64RegisterDeliverabilityNotifications, fDesiredIntWin); 403 Assert(aValues[iReg - 1].DeliverabilityNotifications.NmiNotification == RT_BOOL(fDesiredIntWin & NEM_WIN_INTW_F_NMI)); 404 Assert(aValues[iReg - 1].DeliverabilityNotifications.InterruptNotification == RT_BOOL(fDesiredIntWin & NEM_WIN_INTW_F_REGULAR)); 405 Assert(aValues[iReg - 1].DeliverabilityNotifications.InterruptPriority == (unsigned)((fDesiredIntWin & NEM_WIN_INTW_F_PRIO_MASK) >> NEM_WIN_INTW_F_PRIO_SHIFT)); 406 } 407 } 408 else if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC)) 409 { 410 Log8(("Setting WHvX64RegisterDeliverabilityNotifications, fDesiredIntWin=%X fPicReadyForInterrupt=%RTbool\n", 411 pVCpu->nem.s.fDesiredInterruptWindows, pVCpu->nem.s.fPicReadyForInterrupt)); 412 413 if ( pVCpu->nem.s.fDesiredInterruptWindows 414 && pVCpu->nem.s.fPicReadyForInterrupt) 415 { 416 ADD_REG64(WHvRegisterPendingEvent, 0); 417 418 uint8_t bInterrupt; 419 int rc = PDMGetInterrupt(pVCpu, &bInterrupt); 420 AssertRC(rc); 421 422 aValues[iReg - 1].Reg64 = 0; 423 aValues[iReg - 1].ExtIntEvent.EventPending = 1; 424 aValues[iReg - 1].ExtIntEvent.EventType = WHvX64PendingEventExtInt; 425 aValues[iReg - 1].ExtIntEvent.Vector = bInterrupt; 426 } 427 428 if (!pVCpu->nem.s.fIrqWindowRegistered) 429 { 430 ADD_REG64(WHvX64RegisterDeliverabilityNotifications, 0); 431 aValues[iReg - 1].DeliverabilityNotifications.InterruptNotification = 1; 432 pVCpu->nem.s.fIrqWindowRegistered = true; 433 } 434 } 407 435 408 436 #undef ADD_REG64 … … 419 447 pVM->nem.s.hPartition, pVCpu->idCpu, aenmNames, iReg, aValues)); 420 448 #endif 449 450 pVCpu->nem.s.fPicReadyForInterrupt = false; 451 452 if (!iReg) 453 return VINF_SUCCESS; 454 421 455 HRESULT hrc = WHvSetVirtualProcessorRegisters(pVM->nem.s.hPartition, pVCpu->idCpu, aenmNames, iReg, aValues); 422 456 if (SUCCEEDED(hrc)) … … 1761 1795 pExit->InterruptWindow.DeliverableType, RT_BOOL(pExit->VpContext.Rflags & X86_EFL_IF), 1762 1796 pExit->VpContext.ExecutionState.InterruptShadow, pExit->VpContext.Cr8)); 1797 1798 pVCpu->nem.s.fIrqWindowRegistered = false; 1799 pVCpu->nem.s.fPicReadyForInterrupt = true; 1763 1800 1764 1801 /** @todo call nemHCWinHandleInterruptFF */ … … 2366 2403 return nemR3WinHandleExitUnrecoverableException(pVM, pVCpu, pExit); 2367 2404 2405 case WHvRunVpExitReasonX64ApicEoi: 2406 Assert(pVM->nem.s.fLocalApicEmulation); 2407 PDMIoApicBroadcastEoi(pVCpu->CTX_SUFF(pVM), pExit->ApicEoi.InterruptVector); 2408 return VINF_SUCCESS; 2409 2368 2410 case WHvRunVpExitReasonUnsupportedFeature: 2369 2411 case WHvRunVpExitReasonInvalidVpRegisterValue: … … 2391 2433 NEM_TMPL_STATIC VBOXSTRICTRC nemHCWinHandleInterruptFF(PVMCC pVM, PVMCPUCC pVCpu, uint8_t *pfInterruptWindows) 2392 2434 { 2393 Assert(!TRPMHasTrap(pVCpu) );2435 Assert(!TRPMHasTrap(pVCpu) && !pVM->nem.s.fLocalApicEmulation); 2394 2436 RT_NOREF_PV(pVM); 2395 2437 … … 2548 2590 */ 2549 2591 pVCpu->nem.s.fDesiredInterruptWindows = 0; 2550 if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_PIC 2551 | VMCPU_FF_INTERRUPT_NMI | VMCPU_FF_INTERRUPT_SMI)) 2552 { 2553 /* Try inject interrupt. */ 2554 rcStrict = nemHCWinHandleInterruptFF(pVM, pVCpu, &pVCpu->nem.s.fDesiredInterruptWindows); 2555 if (rcStrict == VINF_SUCCESS) 2556 { /* likely */ } 2557 else 2592 if (!pVM->nem.s.fLocalApicEmulation) 2593 { 2594 if (VMCPU_FF_IS_ANY_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC | VMCPU_FF_UPDATE_APIC | VMCPU_FF_INTERRUPT_PIC 2595 | VMCPU_FF_INTERRUPT_NMI | VMCPU_FF_INTERRUPT_SMI)) 2558 2596 { 2559 LogFlow(("NEM/%u: breaking: nemHCWinHandleInterruptFF -> %Rrc\n", pVCpu->idCpu, VBOXSTRICTRC_VAL(rcStrict) )); 2560 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatBreakOnStatus); 2561 break; 2597 /* Try inject interrupt. */ 2598 rcStrict = nemHCWinHandleInterruptFF(pVM, pVCpu, &pVCpu->nem.s.fDesiredInterruptWindows); 2599 if (rcStrict == VINF_SUCCESS) 2600 { /* likely */ } 2601 else 2602 { 2603 LogFlow(("NEM/%u: breaking: nemHCWinHandleInterruptFF -> %Rrc\n", pVCpu->idCpu, VBOXSTRICTRC_VAL(rcStrict) )); 2604 STAM_REL_COUNTER_INC(&pVCpu->nem.s.StatBreakOnStatus); 2605 break; 2606 } 2562 2607 } 2608 } 2609 else 2610 { 2611 /* We only need to handle the PIC usign ExtInt here, the APIC is handled through the NEM APIC backend. */ 2612 Assert(!VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_APIC)); 2613 2614 if (VMCPU_FF_IS_SET(pVCpu, VMCPU_FF_INTERRUPT_PIC)) 2615 pVCpu->nem.s.fDesiredInterruptWindows |= NEM_WIN_INTW_F_REGULAR; 2563 2616 } 2564 2617 -
trunk/src/VBox/VMM/VMMR3/NEMR3Native-win.cpp
r107931 r108434 163 163 static decltype(WHvGetVirtualProcessorRegisters) * g_pfnWHvGetVirtualProcessorRegisters; 164 164 static decltype(WHvSetVirtualProcessorRegisters) * g_pfnWHvSetVirtualProcessorRegisters; 165 static decltype(WHvSuspendPartitionTime) * g_pfnWHvSuspendPartitionTime; 166 static decltype(WHvResumePartitionTime) * g_pfnWHvResumePartitionTime; 167 decltype(WHvGetVirtualProcessorState) * g_pfnWHvGetVirtualProcessorState = NULL; 168 decltype(WHvSetVirtualProcessorState) * g_pfnWHvSetVirtualProcessorState = NULL; 169 decltype(WHvGetVirtualProcessorInterruptControllerState) *g_pfnWHvGetVirtualProcessorInterruptControllerState = NULL; 170 decltype(WHvSetVirtualProcessorInterruptControllerState) *g_pfnWHvSetVirtualProcessorInterruptControllerState = NULL; 171 decltype(WHvGetVirtualProcessorInterruptControllerState2) *g_pfnWHvGetVirtualProcessorInterruptControllerState2 = NULL; 172 decltype(WHvSetVirtualProcessorInterruptControllerState2) *g_pfnWHvSetVirtualProcessorInterruptControllerState2 = NULL; 173 decltype(WHvRequestInterrupt) * g_pfnWHvRequestInterrupt; 165 174 /** @} */ 166 175 … … 213 222 NEM_WIN_IMPORT(0, false, WHvGetVirtualProcessorRegisters), 214 223 NEM_WIN_IMPORT(0, false, WHvSetVirtualProcessorRegisters), 224 NEM_WIN_IMPORT(0, true, WHvSuspendPartitionTime), 225 NEM_WIN_IMPORT(0, true, WHvResumePartitionTime), 226 NEM_WIN_IMPORT(0, true, WHvRequestInterrupt), 227 NEM_WIN_IMPORT(0, true, WHvGetVirtualProcessorState), 228 NEM_WIN_IMPORT(0, true, WHvSetVirtualProcessorState), 229 NEM_WIN_IMPORT(0, true, WHvGetVirtualProcessorInterruptControllerState), 230 NEM_WIN_IMPORT(0, true, WHvSetVirtualProcessorInterruptControllerState), 231 NEM_WIN_IMPORT(0, true, WHvGetVirtualProcessorInterruptControllerState2), 232 NEM_WIN_IMPORT(0, true, WHvSetVirtualProcessorInterruptControllerState2), 215 233 216 234 NEM_WIN_IMPORT(1, true, VidGetHvPartitionId), … … 285 303 # define WHvGetVirtualProcessorRegisters g_pfnWHvGetVirtualProcessorRegisters 286 304 # define WHvSetVirtualProcessorRegisters g_pfnWHvSetVirtualProcessorRegisters 305 # define WHvSuspendPartitionTime g_pfnWHvSuspendPartitionTime 306 # define WHvResumePartitionTime g_pfnWHvResumePartitionTime 307 # define WHvRequestInterrupt g_pfnWHvRequestInterrupt 308 # define WHvGetVirtualProcessorState g_pfnWHvGetVirtualProcessorState 309 # define WHvSetVirtualProcessorState g_pfnWHvSetVirtualProcessorState 310 # define WHvGetVirtualProcessorInterruptControllerState g_pfnWHvGetVirtualProcessorInterruptControllerState 311 # define WHvGetVirtualProcessorInterruptControllerState2 g_pfnWHvGetVirtualProcessorInterruptControllerState2 287 312 288 313 # define VidMessageSlotHandleAndGetNext g_pfnVidMessageSlotHandleAndGetNext … … 585 610 *g_aImports[i].ppfn = NULL; 586 611 587 LogRel(("NEM: %s: Failed to import %s!%s: %Rrc ",612 LogRel(("NEM: %s: Failed to import %s!%s: %Rrc\n", 588 613 g_aImports[i].fOptional ? "info" : fForced ? "fatal" : "error", 589 614 s_apszDllNames[g_aImports[i].idxDll], g_aImports[i].pszName, rc2)); … … 740 765 NEM_LOG_REL_CAP_SUB_EX("Unknown features", "%#RX64", Caps.ExtendedVmExits.AsUINT64 & ~fKnownVmExits); 741 766 pVM->nem.s.fSpeculationControl = RT_BOOL(Caps.Features.SpeculationControl); 767 pVM->nem.s.fLocalApicEmulation = RT_BOOL(Caps.Features.LocalApicEmulation); 742 768 /** @todo RECHECK: WHV_CAPABILITY_FEATURES typedef. */ 743 769 … … 1255 1281 hrc, RTNtLastStatusValue(), RTNtLastErrorValue()); 1256 1282 1257 int rc ;1283 int rc = VINF_SUCCESS; 1258 1284 1259 1285 /* … … 1281 1307 if (SUCCEEDED(hrc)) 1282 1308 { 1309 RT_ZERO(Property); 1283 1310 /* 1284 * We'll continue setup in nemR3NativeInitAfterCPUM. 1311 * If the APIC is enabled and LocalApicEmulation is supported we'll use Hyper-V's APIC emulation 1312 * for best performance. 1285 1313 */ 1286 pVM->nem.s.fCreatedEmts = false; 1287 pVM->nem.s.hPartition = hPartition; 1288 LogRel(("NEM: Created partition %p.\n", hPartition)); 1289 return VINF_SUCCESS; 1314 PCFGMNODE pCfgmApic = CFGMR3GetChild(CFGMR3GetRoot(pVM), "/Devices/apic"); 1315 if ( pCfgmApic 1316 && pVM->nem.s.fLocalApicEmulation 1317 && 0) /** @todo Finish */ 1318 { 1319 /* If setting this fails log an error but continue. */ 1320 Property.LocalApicEmulationMode = WHvX64LocalApicEmulationModeXApic; 1321 hrc = WHvSetPartitionProperty(hPartition, WHvPartitionPropertyCodeLocalApicEmulationMode , &Property, sizeof(Property)); 1322 if (FAILED(hrc)) 1323 { 1324 LogRel(("NEM: Failed setting WHvPartitionPropertyCodeLocalApicEmulationMode to WHvX64LocalApicEmulationModeXApic: %Rhrc (Last=%#x/%u)", 1325 hrc, RTNtLastStatusValue(), RTNtLastErrorValue())); 1326 pVM->nem.s.fLocalApicEmulation = false; 1327 } 1328 else 1329 { 1330 /* Rewrite the configuration tree to point to our APIC emulation. */ 1331 PCFGMNODE pCfgmDev = CFGMR3GetChild(CFGMR3GetRoot(pVM), "/Devices"); 1332 Assert(pCfgmDev); 1333 1334 PCFGMNODE pCfgmApicHv = NULL; 1335 rc = CFGMR3InsertNode(pCfgmDev, "apic-nem", &pCfgmApicHv); 1336 if (RT_SUCCESS(rc)) 1337 { 1338 rc = CFGMR3CopyTree(pCfgmApicHv, pCfgmApic, CFGM_COPY_FLAGS_IGNORE_EXISTING_KEYS | CFGM_COPY_FLAGS_IGNORE_EXISTING_VALUES); 1339 if (RT_SUCCESS(rc)) 1340 CFGMR3RemoveNode(pCfgmApic); 1341 } 1342 1343 if (RT_FAILURE(rc)) 1344 rc = RTErrInfoSetF(pErrInfo, rc, "Failed replace APIC device config with Hyper-V one"); 1345 } 1346 } 1347 else 1348 pVM->nem.s.fLocalApicEmulation = false; 1349 1350 1351 if (RT_SUCCESS(rc)) 1352 { 1353 /* 1354 * We'll continue setup in nemR3NativeInitAfterCPUM. 1355 */ 1356 pVM->nem.s.fCreatedEmts = false; 1357 pVM->nem.s.hPartition = hPartition; 1358 LogRel(("NEM: Created partition %p.\n", hPartition)); 1359 return VINF_SUCCESS; 1360 } 1290 1361 } 1291 1362 … … 1321 1392 */ 1322 1393 PCFGMNODE pCfg = CFGMR3GetChild(CFGMR3GetRoot(pVM), "/Devices/apic/0/Config"); 1394 if (!pCfg) 1395 pCfg = CFGMR3GetChild(CFGMR3GetRoot(pVM), "/Devices/apic-nem/0/Config"); 1323 1396 if (pCfg) 1324 1397 { -
trunk/src/VBox/VMM/VMMR3/PDMDevice.cpp
r107308 r108434 721 721 int rc = pdmR3DevReg_Register(&RegCB.Core, &g_DeviceAPIC); 722 722 AssertRCReturn(rc, rc); 723 724 # if defined(RT_OS_WINDOWS) 725 /* Register the internal VMM APIC device for NEM mode. */ 726 rc = pdmR3DevReg_Register(&RegCB.Core, &g_DeviceAPICNem); 727 AssertRCReturn(rc, rc); 728 # endif 723 729 #endif 724 730 -
trunk/src/VBox/VMM/include/APICInternal.h
r107113 r108434 46 46 /** The VirtualBox APIC backend table. */ 47 47 extern const PDMAPICBACKEND g_ApicBackend; 48 #if defined(RT_OS_WINDOWS) 49 /** The Hyper-V APIC backend. */ 50 extern const PDMAPICBACKEND g_ApicNemBackend; 51 # endif 48 52 #endif 49 53 -
trunk/src/VBox/VMM/include/NEMInternal.h
r108413 r108434 267 267 /** Whether to export/import IA32_SPEC_CTRL. */ 268 268 bool fDoIa32SpecCtrl : 1; 269 /** WHvX64LocalApicEmulationModeXApic is used. */ 270 bool fLocalApicEmulation : 1; 269 271 # ifdef NEM_WIN_WITH_A20 270 272 /** Set if we've started more than one CPU and cannot mess with A20. */ … … 284 286 uint64_t u64; 285 287 # ifdef _WINHVAPIDEFS_H_ 286 /** Interpre ed features. */288 /** Interpreted features. */ 287 289 WHV_PROCESSOR_FEATURES u; 288 290 # endif … … 513 515 /** The desired state of the interrupt windows (NEM_WIN_INTW_F_XXX). */ 514 516 uint8_t fDesiredInterruptWindows; 517 /** Cached TPR value. */ 518 uint8_t bTpr; 515 519 /** Last copy of HV_X64_VP_EXECUTION_STATE::InterruptShadow. */ 516 520 bool fLastInterruptShadow : 1; 521 /** Flag whether the IRQ window notification was registered (for injecting PIC interrupts). */ 522 bool fIrqWindowRegistered: 1; 523 /** Flag whether it is possible inject a PIC interrupt. */ 524 bool fPicReadyForInterrupt: 1; 517 525 uint32_t uPadding; 518 526 /** The VID_MSHAGN_F_XXX flags.
Note:
See TracChangeset
for help on using the changeset viewer.