27 return (Gva >> 12) & (Cache->InvCount - 1);
50 return (Gva >> 12) & (Cache->LinesCount - 1);
68 LOG(
"Instruction cache:\n");
88 char text[ND_MIN_BUF_SIZE] = {0};
95 NLOG(
"-> %04d - %04d: 0x%016llx:0x%016llx, %08d %d %d %d > %s\n",
108 NLOG(
"Invalidation queue:\n");
111 for (i = 0; i < cache->
InvCount; i++)
154 if (NULL != Invd->SwapHook)
159 ERROR(
"[ERROR] IntHookPtsRemoveHook failed: 0x%08x\n", status);
163 if (NULL != Invd->WriteHook)
168 ERROR(
"[ERROR] IntHookGpaRemoveHook failed: 0x%08x\n", status);
193 for (i = 0; i < Cache->InvCount; i++)
197 while (list != &Cache->InsInvGva[i])
209 ERROR(
"[ERROR] IntIcFreeInvdEntry failed: 0x%08x\n", status);
237 if (0 == Invd->RefCount)
244 if (0 == Invd->RefCount)
251 ERROR(
"[ERROR] IntIcFreeInvdEntry failed: 0x%08x\n", status);
279 if (NULL != Entry->Invd1)
284 ERROR(
"[ERROR] IntIcInvdEntry failed: 0x%08x\n", status);
290 if (NULL != Entry->Invd2)
295 ERROR(
"[ERROR] IntIcInvdEntry failed: 0x%08x\n", status);
308 _In_ void const *Hook,
408 #define INV_MASK (~0x60ULL) 429 _Out_ PINSTRUX Instrux,
463 for (i = 0; i < Cache->EntriesCount; i++)
465 if ((Cache->Lines[line].Entries[i].Gva == Gva) &&
466 (Cache->Lines[line].Entries[i].Valid) &&
467 ((Cache->Lines[line].Entries[i].Cr3 == Cr3) ||
469 (Cache->Lines[line].Entries[i].Global)))
471 memcpy(Instrux, &Cache->Lines[line].Entries[i].Instruction,
sizeof(INSTRUX));
473 Cache->Lines[line].Entries[i].RefCount += Lru;
497 _Out_ PINSTRUX Instrux,
564 for (i = 0; i < Cache->LinesCount; i++)
566 for (j = 0; j < Cache->EntriesCount; j++)
568 if (Cache->Lines[i].Entries[j].Valid)
570 Cache->Lines[i].Entries[j].Gva = 0;
571 Cache->Lines[i].Entries[j].Cr3 = 0;
572 Cache->Lines[i].Entries[j].Invd1 = NULL;
573 Cache->Lines[i].Entries[j].Invd2 = NULL;
574 Cache->Lines[i].Entries[j].Pinned =
FALSE;
575 Cache->Lines[i].Entries[j].Global =
FALSE;
576 Cache->Lines[i].Entries[j].RefCount = 0;
577 Cache->Lines[i].Entries[j].Valid =
FALSE;
585 ERROR(
"[ERROR] IntIcRemoveAllInvdEntries failed: 0x%08x\n", status);
590 Cache->Dirty =
FALSE;
634 for (i = 0; i < Cache->EntriesCount; i++)
636 if ((Cache->Lines[line].Entries[i].Gva == Gva) &&
637 (Cache->Lines[line].Entries[i].Valid) &&
638 ((Cache->Lines[line].Entries[i].Cr3 == Cr3) ||
640 (Cache->Lines[line].Entries[i].Global)))
646 ERROR(
"[ERROR] IntIcInvdCacheEntry failed: 0x%08x\n", status);
649 Cache->Lines[line].Entries[i].Valid = 0;
650 Cache->Lines[line].Entries[i].Gva = 0;
651 Cache->Lines[line].Entries[i].Cr3 = 0;
652 Cache->Lines[line].Entries[i].Invd1 = NULL;
653 Cache->Lines[line].Entries[i].Invd2 = NULL;
695 Cache->PageFlushCount++;
702 for (i = 0; i < Cache->EntriesCount; i++)
704 if (((Cache->Lines[line].Entries[i].Gva &
PAGE_MASK) == Gva) &&
705 (Cache->Lines[line].Entries[i].Valid) &&
706 ((Cache->Lines[line].Entries[i].Cr3 == Cr3) ||
708 (Cache->Lines[line].Entries[i].Global)) &&
709 ((!Spill) || ((Cache->Lines[line].Entries[i].Gva &
PAGE_OFFSET) +
710 Cache->Lines[line].Entries[i].Instruction.Length >
PAGE_SIZE)))
716 ERROR(
"[ERROR] IntIcInvdCacheEntry failed: 0x%08x\n", status);
719 Cache->Lines[line].Entries[i].Valid = 0;
720 Cache->Lines[line].Entries[i].Gva = 0;
721 Cache->Lines[line].Entries[i].Cr3 = 0;
722 Cache->Lines[line].Entries[i].Invd1 = NULL;
723 Cache->Lines[line].Entries[i].Invd2 = NULL;
764 Cache->PageFlushCount++;
766 for (i = 0; i < Cache->LinesCount; i++)
768 for (j = 0; j < Cache->EntriesCount; j++)
770 if ((Cache->Lines[i].Entries[j].Valid) &&
771 (((NULL != Cache->Lines[i].Entries[j].Invd1) && (Cache->Lines[i].Entries[j].Invd1->Gpa == Gpa)) ||
772 ((NULL != Cache->Lines[i].Entries[j].Invd2) && (Cache->Lines[i].Entries[j].Invd2->Gpa == Gpa))))
778 ERROR(
"[ERROR] IntIcInvdCacheEntry failed: 0x%08x\n", status);
781 Cache->Lines[i].Entries[j].Valid = 0;
782 Cache->Lines[i].Entries[j].Gva = 0;
783 Cache->Lines[i].Entries[j].Cr3 = 0;
784 Cache->Lines[i].Entries[j].Invd1 = NULL;
785 Cache->Lines[i].Entries[j].Invd2 = NULL;
823 for (i = 0; i < Cache->LinesCount; i++)
825 for (j = 0; j < Cache->EntriesCount; j++)
827 if ((Cache->Lines[i].Entries[j].Cr3 == Cr3) || (
IC_ANY_VAS == Cr3))
833 ERROR(
"[ERROR] IntIcInvdCacheEntry failed: 0x%08x\n", status);
836 Cache->Lines[i].Entries[j].Valid = 0;
837 Cache->Lines[i].Entries[j].Gva = 0;
838 Cache->Lines[i].Entries[j].Cr3 = 0;
839 Cache->Lines[i].Entries[j].Invd1 = NULL;
840 Cache->Lines[i].Entries[j].Invd2 = NULL;
888 list = Cache->InsInvGva[invline].
Flink;
889 while (list != &Cache->InsInvGva[invline])
927 ERROR(
"[ERROR] IntHookPtsSetHook failed: 0x%08x\n", status);
936 ERROR(
"[ERROR] IntHookGpaSetHook failed on %llx: 0x%08x\n", pInv->
Gva, status);
954 _In_ PINSTRUX Instruction,
980 DWORD line, target, i;
987 if (Instruction == NULL)
996 for (i = 0; i < Cache->EntriesCount; i++)
998 if (!Cache->Lines[line].Entries[i].Valid)
1008 if (0xFFFFFFFF == target)
1010 target =
__rdtsc() % Cache->EntriesCount;
1014 if (Cache->Lines[line].Entries[target].Valid)
1019 ERROR(
"[ERROR] IntIcInvdCacheEntry failed: 0x%08x\n", status);
1025 Cache->Lines[line].Entries[target].Valid =
FALSE;
1027 Cache->Lines[line].Entries[target].Gva = Gva;
1028 Cache->Lines[line].Entries[target].Cr3 = Cr3;
1029 Cache->Lines[line].Entries[target].RefCount = 0;
1030 Cache->Lines[line].Entries[target].Pinned =
FALSE;
1031 Cache->Lines[line].Entries[target].Global = Global;
1033 memcpy(&Cache->Lines[line].Entries[target].Instruction, Instruction,
sizeof(INSTRUX));
1035 Cache->Lines[line].Entries[target].Invd1 = NULL;
1036 Cache->Lines[line].Entries[target].Invd2 = NULL;
1045 ERROR(
"[ERROR] IntIcAddInvdForInstruction failed: 0x%08x\n", status);
1052 if ((Gva &
PAGE_MASK) != ((Gva + Instruction->Length - 1) & PAGE_MASK))
1054 TRACE(
"[ICACHE] Instruction at %llx:%d spills the page...\n", Gva, Instruction->Length);
1057 &Cache->Lines[line].Entries[target].Invd2);
1063 ERROR(
"[ERROR] IntIcAddInvdForInstruction failed: 0x%08x\n", status);
1073 Cache->Lines[line].Entries[target].Invd2->Spill =
TRUE;
1077 Cache->Lines[line].Entries[target].Valid =
TRUE;
1079 Cache->Dirty =
TRUE;
1117 if (0 != (LinesCount & (LinesCount - 1)))
1122 if (0 != (InvCount & (InvCount - 1)))
1145 if (NULL == pCache->
Lines)
1148 goto cleanup_and_exit;
1151 for (
DWORD i = 0; i < LinesCount; i++)
1157 goto cleanup_and_exit;
1165 goto cleanup_and_exit;
1168 for (
DWORD j = 0; j < InvCount; j++)
1183 if (NULL != pCache->
Lines)
1185 for (
DWORD i = 0; i < LinesCount; i++)
1243 ERROR(
"[ERROR] IntIcRemoveAllInvdEntries failed: 0x%08x\n", status);
BOOLEAN Spill
True if there is an instruction inside this entry that spills inside the next page.
#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)
BOOLEAN Pinned
True if the entry is pinned (it cannot be evicted).
DWORD FillRate
How many entries or occupied by valid instructions.
DWORD EntriesCount
Number of entries inside each line.
INTSTATUS IntHookGpaRemoveHook(HOOK_GPA **Hook, DWORD Flags)
Remove a GPA hook.
QWORD SystemCr3
The Cr3 used to map the kernel.
#define INT_STATUS_SUCCESS
INSTRUX Instruction
The decoded instruction.
INTSTATUS IntIcAddInstruction(PINS_CACHE Cache, PINSTRUX Instruction, QWORD Gva, QWORD Cr3, BOOLEAN Global)
Adds an instruction to the cache.
struct _LIST_ENTRY * Flink
static __inline DWORD IntIcHashLine(PINS_CACHE Cache, QWORD Gva)
Compute an instruction line index.
static INTSTATUS IntIcWriteHandler(INS_CACHE_INV_ENTRY const *Context, void const *Hook, QWORD Address, INTRO_ACTION *Action)
Cached instruction page write handler.
#define INT_SUCCESS(Status)
static INTSTATUS IntIcInvdCacheEntry(PINS_CACHE Cache, PINS_CACHE_ENTRY Entry)
Invalidate an instruction cache entry.
static BOOLEAN IsListEmpty(const LIST_ENTRY *ListHead)
QWORD Cr3
Virtual address space containing the instruction. Can be IC_ANY_VAS.
INTSTATUS IntIcDestroy(PINS_CACHE *Cache)
Destroy an instruction cache.
DWORD FlushCount
Number of times the cache has been flushed.
#define HpAllocWithTag(Len, Tag)
int INTSTATUS
The status data type.
QWORD Gva
The guest virtual page described by this entry.
#define INT_STATUS_NOT_FOUND
#define TRFLG_NONE
No special options.
LIST_ENTRY Link
List entry element.
DWORD RefCount
Number of times this instruction has been hit.
DWORD MissCount
Number of cache misses.
BOOLEAN Valid
True if the entry is valid.
INTSTATUS IntHookGpaSetHook(QWORD Gpa, DWORD Length, BYTE Type, PFUNC_EptViolationCallback Callback, void *Context, void *ParentHook, DWORD Flags, HOOK_GPA **Hook)
Places an EPT hook on the indicated memory range.
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.
static INTSTATUS IntIcInvdEntry(PINS_CACHE Cache, PINS_CACHE_INV_ENTRY Invd)
Decrements the reference count of the provided invalidation entry, and, if it reaches 0...
INTSTATUS IntIcCreate(INS_CACHE **Cache, DWORD LinesCount, DWORD EntriesCount, DWORD InvCount)
Create anew instruction cache.
void IntIcDumpIcache(void)
Dumps the entire contents of the implicit, per guest, instruction cache.
static INTSTATUS IntIcRemoveAllInvdEntries(PINS_CACHE Cache)
Removes all the invalidation entries contained in this cache. This should be used only during uninit...
DWORD PageFlushCount
Number of page flushes.
static BOOLEAN RemoveEntryList(LIST_ENTRY *Entry)
static INTSTATUS IntIcFreeInvdEntry(PINS_CACHE_INV_ENTRY Invd)
Free an invalidation entry.
INS_CACHE_ENTRY * Entries
Array containing the entries.
#define INT_STATUS_INVALID_PARAMETER_4
INTSTATUS IntIcFlushGvaPage(PINS_CACHE Cache, QWORD Gva, QWORD Cr3, BOOLEAN Spill)
Flush all entries cached from a given guest virtual page.
void * SwapHook
Swap handle.
static INTSTATUS IntIcLookupInstructionInternal(PINS_CACHE Cache, PINSTRUX Instrux, QWORD Gva, QWORD Cr3, DWORD Lru)
Lookup an instruction inside the cache.
LIST_HEAD * InsInvGva
Array of invalidation entries.
#define HpFreeAndNullWithTag(Add, Tag)
INTSTATUS IntIcFlush(PINS_CACHE Cache)
Flush the entire instruction cache.
INTSTATUS IntHookPtsRemoveHook(HOOK_PTS **Hook, DWORD Flags)
Remove a PTS hook.
static INTSTATUS IntIcSwapHandler(void *Context, QWORD VirtualAddress, QWORD OldEntry, QWORD NewEntry, QWORD OldPageSize, QWORD NewPageSize)
Cache instruction page swap handler.
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.
INTSTATUS IntIcFlushGpaPage(PINS_CACHE Cache, QWORD Gpa)
Flush all entries cached from a given guest physical page.
static void InitializeListHead(LIST_ENTRY *ListHead)
#define UNREFERENCED_PARAMETER(P)
static INTSTATUS IntIcAddInvdForInstruction(PINS_CACHE Cache, QWORD Gva, QWORD Cr3, PINS_CACHE_INV_ENTRY *Invd)
Add invalidation entries for a newly cached instruction.
void * InstructionCache
The currently used instructions cache.
QWORD Gpa
The guest physical page described by this entry.
INTSTATUS IntIcLookupInstruction(PINS_CACHE Cache, PINSTRUX Instrux, QWORD Gva, QWORD Cr3)
Lookup an instruction inside the cache.
DWORD LinesCount
Number of lines inside the cache. Must be a power of 2.
enum _INTRO_ACTION INTRO_ACTION
Event actions.
static uint64_t __rdtsc(void)
INTSTATUS IntIcFlushAddress(PINS_CACHE Cache, QWORD Gva, QWORD Cr3)
Flush entries cached from a given address.
DWORD InvCount
Number of lines inside the invalidation array. Must be a power of 2.
MM Mm
Guest memory information, such as paging mode, system Cr3 value, etc.
GUEST_STATE gGuest
The current guest state.
void * WriteHook
EPT write hook handle.
INTSTATUS IntIcFlushVaSpace(PINS_CACHE Cache, QWORD Cr3)
Flush an entire virtual address space.
#define INT_STATUS_NO_MAPPING_STRUCTURES
Indicates that not all mapping structures of a virtual address are present.
static __inline DWORD IntIcHashInv(PINS_CACHE Cache, QWORD Gva)
Compute the invalidation entry index.
#define INT_STATUS_NOT_INITIALIZED_HINT
Encapsulates information about a virtual to physical memory translation.
#define INT_STATUS_INVALID_PARAMETER_1
QWORD Gva
The instruction guest virtual address.
INS_CACHE_LINE * Lines
Array of cache lines.
DWORD HitCount
Number of cache hits.
#define INT_STATUS_INVALID_PARAMETER_2
DWORD ReplaceCount
Number of times entries were evicted & replaced by other ones.
BOOLEAN Global
True if the entry is global (shared in multiple processes).
struct _INS_CACHE * PINS_CACHE
QWORD Cr3
Virtual address space the page belongs to.
#define INT_STATUS_INSUFFICIENT_RESOURCES