106 _In_ void *DataAddress,
118 PSWAPMEM_TRANSACTION pCtx;
124 if (NULL != pCtx->
Data)
142 _In_ PSWAPMEM_TRANSACTION Transaction
155 list = Transaction->Pages.
Flink;
156 while (list != &Transaction->Pages)
167 if (NULL != pPage->
Hook)
172 ERROR(
"[ERROR] IntHookPtsRemoveHook failed: 0x%08x\n", status);
187 ERROR(
"[ERROR] IntSwapMemCleanupCallback failed: 0x%08x\n", status);
219 TRACE(
"[SWAPMEM] Injecting a #PF from #BP handler at %p on cpu %d\n", Context,
gVcpu->
Index);
224 ERROR(
"[ERROR] IntInjectExceptionInGuest failed for 0x%016llx: 0x%08x\n", (
QWORD)Context, status);
287 PSWAPMEM_TRANSACTION pCtx;
289 DWORD readSize, offset;
295 if (0 == (NewEntry &
PT_P))
307 if (NULL == pCtx->
Data)
327 if (0 != (NewEntry &
PT_XD))
344 TRACE(
"[SWAPMEM] Page %llx was swapped in at %llx, will read 0x%x bytes at offset 0x%x\n",
345 VirtualAddress, NewEntry, readSize, offset);
353 ERROR(
"[ERROR] IntPhysicalMemReadAnySize failed for 0x%016llx : %08x (%08x) : 0x%08x\n",
354 NewEntry, (
DWORD)NewPageSize, readSize, status);
363 if (NULL != pPage->
Hook)
368 ERROR(
"[ERROR] IntHookPtsRemoveHook failed: 0x%08x\n", status);
391 ERROR(
"[ERROR] Callback failed: 0x%08x\n", status);
407 ERROR(
"[ERROR] IntSwapMemCleanupCallback failed: 0x%08x\n", status);
464 PSWAPMEM_TRANSACTION pCtx;
467 QWORD tCr3, page = 0;
495 if (NULL != SwapHandle)
508 goto cleanup_and_exit;
524 if (NULL == pCtx->
Data)
527 goto cleanup_and_exit;
530 for (page = VirtualAddress; page < VirtualAddress + Length; page = (page &
PAGE_MASK) +
PAGE_SIZE_4K)
538 TRACE(
"[SWAPMEM] Page %llx is at %llx with flags %llx and opts %x, " 539 "scheduling #PF injection to read %d bytes...\n",
548 goto cleanup_and_exit;
566 ERROR(
"[ERROR] IntHookPtsSetHook failed: 0x%08x\n", status);
567 goto cleanup_and_exit;
572 ERROR(
"[ERROR] IntTranslateVirtualAddressEx failed: 0x%08x\n", status);
573 goto cleanup_and_exit;
583 pCtx->
Data + (page - VirtualAddress),
587 ERROR(
"[ERROR] IntPhysicalMemReadAnySize failed: 0x%08x\n", status);
588 goto cleanup_and_exit;
593 if (page == VirtualAddress)
627 ERROR(
"[ERROR] Callback failed: 0x%08x\n", status);
647 ERROR(
"[ERROR] IntSwapMemCancelTransaction failed: 0x%08x\n", status2);
654 if (NULL != SwapHandle)
750 ERROR(
"[ERROR] IntCr3Read failed: 0x%08x\n", status);
757 ERROR(
"[ERROR] IntGetCurrentRing failed: 0x%08x\n", status);
767 listCtx = listCtx->
Flink;
776 if ((cr3 != pCtx->
Cr3) && (0 != pCtx->
Cr3))
790 while (listPage != &pCtx->
Pages)
795 listPage = listPage->
Flink;
816 TRACE(
"[SWAPMEM] [VCPU %d] Translated page 0x%016llx to 0x%016llx, entry 0x%016llx\n",
gVcpu->
Index,
825 TRACE(
"[SWAPMEM] The pre-injection callback decided we cannot inject a #PF yet for 0x%016llx!\n",
841 ERROR(
"[ERROR] IntSwapMemInjectMiniSwapper failed: 0x%08x\n", status);
846 TRACE(
"[SWAPMEM] Injecting UM/KM/direct #PF for %llx/%llx!\n", cr3, pPage->
VirtualAddress);
851 ERROR(
"[ERROR] IntInjectExceptionInGuest failed: 0x%08x\n", status);
898 TRACE(
"[SWAPMEM] Canceling pending #PF for 0x%016llx, CR3 0x%016llx, CPU %d...\n",
928 LOG(
"[SWAPMEM] Page 0x%016llx with CR3 0x%016llx exceeds the age limit, will retry injection...\n",
943 _In_ void *Transaction
959 PSWAPMEM_TRANSACTION pCtx;
961 if (NULL == Transaction)
974 ERROR(
"[ERROR] IntSwapMemCancelTransaction failed: 0x%08x\n", status);
1005 if (pCtx->
Cr3 == Cr3)
1007 TRACE(
"[SWAPMEM] Removing transaction request at 0x%016llx for VA space 0x%016llx.\n",
1016 ERROR(
"[ERROR] IntSwapMemCancelTransaction failed: 0x%08x\n", status);
1059 memzero(&gSwapState,
sizeof(gSwapState));
1080 list1 = list1->
Flink;
1082 LOG(
"Transaction %p: CR3 = 0x%016llx, GVA = 0x%016llx, max len = %d, cur len = %d, options = %d\n",
1086 while (list2 != &pCtx->
Pages)
1090 list2 = list2->
Flink;
1092 LOG(
" Page %p: GVA = 0x%016llx, state: %d %d %d\n",
#define SWAPMEM_OPT_NO_FAULT
If set, no PF will be injected. Introcore will wait for the pages to be naturally swapped in...
#define INT_STATUS_PAGE_NOT_PRESENT
Indicates that a virtual address is not present.
QWORD PhysicalAddress
The physical address to which VirtualAddress translates to.
#define CONTAINING_RECORD(List, Type, Member)
static PSWAPMEM_PAGE IntSwapMemFindPendingPage(QWORD VirtualAddress, QWORD Cr3)
Finds a pending page, given the guest virtual address and the Cr3.
BOOLEAN IsEnqueued
True if the page has been inserted inside the list of pages.
void IntSwapMemReinjectFailedPF(void)
Reinject timed-out PFs.
struct _SWAPMEM_PAGE SWAPMEM_PAGE
static INTSTATUS IntSwapMemPageSwappedIn(void *Context, QWORD VirtualAddress, QWORD OldEntry, QWORD NewEntry, QWORD OldPageSize, QWORD NewPageSize)
Handle a page swap-in event.
static INTSTATUS IntSwapMemInjectMiniSwapper(QWORD VirtualAddress)
Injects the mini swapper, which is basically just a breakpoint agent.
DWORD Index
The VCPU number.
struct _SWAPMEM_STATE SWAPMEM_STATE
QWORD SystemCr3
The Cr3 used to map the kernel.
#define INT_STATUS_SUCCESS
#define PAGE_REMAINING(addr)
PSWAPMEM_TRANSACTION Transaction
Parent transaction.
BOOLEAN IsWritable
True if this page is writable.
LIST_HEAD SwapTranzactionsList
List of transactions.
struct _LIST_ENTRY * Flink
PHOOK_PTS Hook
Swap in hook handle set on this page.
LIST_ENTRY Link
List entry element.
void IntSwapMemDump(void)
Dump all active transactions & pages.
#define INT_SUCCESS(Status)
static BOOLEAN IsListEmpty(const LIST_ENTRY *ListHead)
PSWAPMEM_PAGE PendingPage
Currently pending page. There can be only one pending page.
#define SWAPMEM_OPT_NO_DUPS
If set, will make sure that a single PF is scheduled for this page.
DWORD DataCurrentSize
How much we've read so far.
#define INT_STATUS_NOT_NEEDED_HINT
#define HpAllocWithTag(Len, Tag)
int INTSTATUS
The status data type.
INTSTATUS(* PFUNC_PagesReadCallback)(void *Context, QWORD Cr3, QWORD VirtualAddress, QWORD PhysicalAddress, void *Data, DWORD DataSize, DWORD Flags)
Called when all the required data is available.
LIST_ENTRY Link
List entry link.
INTSTATUS IntInjectExceptionInGuest(BYTE Vector, QWORD Cr2, DWORD ErrorCode, DWORD CpuNumber)
Injects an exception inside the guest.
#define TRFLG_NONE
No special options.
#define SWAPMEM_FLAG_ENTRY_XD
PBYTE Data
memory will be read.
static INTSTATUS IntSwapMemCleanupCallback(void *DataAddress, QWORD DataInfo)
Cleans up a transaction, by freeing the data buffer, the context and the transaction itself...
INTRO_GUEST_TYPE OSType
The type of the guest.
#define INT_STATUS_OPERATION_NOT_IMPLEMENTED
INTSTATUS IntSwapMemInjectPendingPF(void)
Inject a PF for a pending page.
BOOLEAN IsEnqueued
transactions list.
INTSTATUS IntHookPtsSetHook(QWORD Cr3, QWORD VirtualAddress, PFUNC_SwapCallback Callback, void *Context, void *Parent, DWORD Flags, PHOOK_PTS *Hook)
Start monitoring translation modifications for the given VirtualAddress.
QWORD TimeStamp
When was the last time we injected a PF for this page.
INTSTATUS IntSwapMemRemoveTransactionsForVaSpace(QWORD Cr3)
Remove all transactions initiated for a virtual address space.
static INTSTATUS IntSwapMemCancelTransaction(PSWAPMEM_TRANSACTION Transaction)
Cancels a transaction.
static INTSTATUS IntSwapMemHandleBreakpointAgent(QWORD GuestVirtualAddress, DWORD AgentTag, void *Context)
Handles a breakpoint agent.
static SWAPMEM_STATE gSwapState
QWORD Flags
The entry that maps VirtualAddress to PhysicalAddress, together with all the control bits...
struct _SWAPMEM_TRANSACTION * PSWAPMEM_TRANSACTION
#define IG_CURRENT_VCPU
For APIs that take a VCPU number as a parameter, this can be used to specify that the current VCPU sh...
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
BOOLEAN IsReady
True if the page is ready to be read.
QWORD PhysicalAddress
Guest physical address, once we get a translation.
#define SWAPMEM_OPT_RW_FAULT
If set, the PF will be generated with write access. Useful when CoW must be done. ...
DWORD Flags
Transaction flags. Take a look at SWAPMEM_FLAG* for more info.
#define HpFreeAndNullWithTag(Add, Tag)
INTSTATUS IntHookPtsRemoveHook(HOOK_PTS **Hook, DWORD Flags)
Remove a PTS hook.
BOOLEAN IsDone
True if the page has been read.
BOOLEAN IsPending
True if we injected a PF for the page, and we are waiting for it.
QWORD VirtualAddress
Guest virtual address of the page.
static void InsertTailList(LIST_ENTRY *ListHead, LIST_ENTRY *Entry)
INTSTATUS IntTranslateVirtualAddressEx(QWORD Gva, QWORD Cr3, DWORD Flags, VA_TRANSLATION *Translation)
Translates a guest virtual address to a guest physical address.
#define SWAPMEM_FLAG_ASYNC_CALL
INTSTATUS IntSwapMemReadData(QWORD Cr3, QWORD VirtualAddress, DWORD Length, DWORD Options, void *Context, DWORD ContextTag, PFUNC_PagesReadCallback Callback, PFUNC_PreInjectCallback PreInject, void **SwapHandle)
Reads a region of guest virtual memory, and calls the indicated callback when all the data is availab...
DWORD DataMaxSize
Maximum data size to be read.
QWORD Cr3
Virtual address space from where we read memory.
PFUNC_PreInjectCallback PreInject
returns INT_STATUS_NOT_NEEDED_HINT, the PF will be canceled.
static void InitializeListHead(LIST_ENTRY *ListHead)
INTSTATUS IntSwapMemRemoveTransaction(void *Transaction)
Remove a transaction.
struct _SWAPMEM_TRANSACTION SWAPMEM_TRANSACTION
#define UNREFERENCED_PARAMETER(P)
void * Context
Options context to be passed to the callbacks.
struct _SWAPMEM_STATE * PSWAPMEM_STATE
QWORD VirtualAddress
Guest virtual address to be read.
INTSTATUS IntSwapMemInit(void)
Init the swapmem system.
#define SWAPMEM_OPT_KM_FAULT
#define SWAPMEM_OPT_BP_FAULT
If set, the #PF will be generated from an int3 detour. Use this when injecting kernel PFs...
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
GUEST_STATE gGuest
The current guest state.
PFUNC_PagesReadCallback Callback
Callback called as soon as all the requested data is available.
INTSTATUS(* PFUNC_PreInjectCallback)(void *Context, QWORD Cr3, QWORD VirtualAddress)
Called before injecting a PF inside the guest.
QWORD TimerCalls
The number of times the timer callback has been invoked.
struct _VCPU_STATE::@80 Exception
The exception to be injected in guest.
INTSTATUS IntPhysicalMemReadAnySize(QWORD PhysicalAddress, DWORD Length, void *Buffer, DWORD *RetLength)
Reads data from a guest physical memory range, regardless of how many pages it spans across...
INTSTATUS IntWinAgentInjectBreakpoint(PFUNC_AgentInjection InjectionCallback, void *Context, PWIN_AGENT *Agent)
Injects a breakpoint agent inside the guest.
#define INT_STATUS_NO_MAPPING_STRUCTURES
Indicates that not all mapping structures of a virtual address are present.
BOOLEAN Initialized
True if the state has been initialized.
INTSTATUS IntCr3Read(DWORD CpuNumber, QWORD *Cr3Value)
Reads the value of the guest CR3.
#define INT_STATUS_NOT_INITIALIZED_HINT
Encapsulates information about a virtual to physical memory translation.
BOOLEAN Valid
True if the fields are valid; False if they are not.
#define INT_STATUS_INVALID_PARAMETER_1
VCPU_STATE * gVcpu
The state of the current VCPU.
BOOLEAN IsCanceled
True if the transaction has been canceled.
struct _SWAPMEM_PAGE * PSWAPMEM_PAGE
INTSTATUS IntGetCurrentRing(DWORD CpuNumber, DWORD *Ring)
Read the current protection level.
DWORD Options
Transaction options. Take a look at SWAPMEM_OPT* for more info.
LIST_HEAD Pages
List of pages to be read (list of SWAPMEM_PAGE).
#define INT_STATUS_INVALID_PARAMETER_2
INTSTATUS IntSwapMemUnInit(void)
Uninit the swapmem system.
#define SWAPMEM_OPT_UM_FAULT
If set, the PF must be injected only while in user-mode. Use it when reading user-mode memory...
void IntSwapMemCancelPendingPF(QWORD VirtualAddress)
Cancel a pending PF.
#define INT_STATUS_INSUFFICIENT_RESOURCES