Skip to content

Commit

Permalink
Version 3.4
Browse files Browse the repository at this point in the history
  • Loading branch information
ufrisk committed Jul 14, 2018
1 parent f50feb8 commit ec7a8ba
Show file tree
Hide file tree
Showing 11 changed files with 203 additions and 39 deletions.
6 changes: 3 additions & 3 deletions pcileech/help.c
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ VOID Help_ShowGeneral()
" Option has no value. Example: -pt. Used in conjunction with \n" \
" -kmd option to trigger KMD insertion by page table hijack. \n" \
" -cr3 : base address of page table (PML4) / CR3 CPU register. \n" \
" -efibase : base address of EFI_SYSTEM_TABLE (IBI SYST). Used when inserting \n" \
" UEFI 'kernel' modules. \n" \
" -efibase : base address of EFI table when inserting select kernel modules. \n" \
" EFI_SYSTEM_TABLE(IBI SYST) == UEFI ; RUNTSERV == LINUX RUNTSERV EFI. \n" \
" -kmd : address of already loaded kernel module helper (KMD). \n" \
" ALTERNATIVELY \n" \
" kernel module to use, see list below for choices: \n" \
Expand Down Expand Up @@ -143,7 +143,7 @@ VOID Help_ShowInfo()
printf(
" PCILEECH INFORMATION \n" \
" PCILeech (c) 2016-2018 Ulf Frisk \n" \
" Version: 3.3 \n" \
" Version: 3.4 \n" \
" License: GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 \n" \
" Contact information: pcileech@frizk.net \n" \
" System requirements: 64-bit Windows 7, 10 or Linux. \n" \
Expand Down
12 changes: 12 additions & 0 deletions pcileech/kmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,18 @@ BOOL KMD_FindSignature_EfiRuntimeServices(_Inout_ PPCILEECH_CONTEXT ctx, _Out_ P
if(!(pbBuffer16M = LocalAlloc(0, 0x01000000))) {
return FALSE;
}
// Option 1: User-supplied efibase option (= base of EFI RUNTIME SERVICES table (RUNTSERV)).
if(ctx->cfg->qwEFI_IBI_SYST) { // technically not EFI_IBI_SYST table but we use this user-supplied option anyway here.
result =
((ctx->cfg->qwEFI_IBI_SYST & 0xfff) > 0x18) &&
((ctx->cfg->qwEFI_IBI_SYST & 0xfff) < (0x1000 - 0x88)) &&
DeviceReadMEM(ctx, ctx->cfg->qwEFI_IBI_SYST & ~0xfff, pbBuffer16M, 0x1000, PCILEECH_MEM_FLAG_RETRYONFAIL) &&
IS_SIGNATURE_EFI_RUNTIME_SERVICES(pbBuffer16M + (ctx->cfg->qwEFI_IBI_SYST & 0xfff));
LocalFree(pbBuffer16M);
*pqwAddrPhys = ctx->cfg->qwEFI_IBI_SYST;
return result;
}
// Option 2: Scan for EFI RUNTIME SERVICES table (RUNTSERV).
ctx->cfg->qwAddrMin &= ~0xfff;
ctx->cfg->qwAddrMax = (ctx->cfg->qwAddrMax + 1) & ~0xfff;
if(ctx->cfg->qwAddrMax == 0) {
Expand Down
14 changes: 7 additions & 7 deletions pcileech/statistics.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// statistics.c : implementation of statistics related functionality.
//
// (c) Ulf Frisk, 2016, 2017
// (c) Ulf Frisk, 2016-2018
// Author: Ulf Frisk, pcileech@frizk.net
//
#include "statistics.h"
Expand All @@ -10,14 +10,14 @@ VOID _PageStatPrintMemMap(_Inout_ PPAGE_STATISTICS ps)
BOOL fIsLinePrinted = FALSE;
QWORD i, qwAddrBase, qwAddrEnd;
if(!ps->i.fIsFirstPrintCompleted) {
printf(" Memory Map: \n START END #PAGES\n");
printf(" Memory Map: \n START END #PAGES \n");
}
if(!ps->i.MemMapIdx && !ps->i.MemMap[0]) {
printf(" \n \n");
printf(" \n \n");
return;
}
if(ps->i.MemMapPrintCommitIdx >= PAGE_STATISTICS_MEM_MAP_MAX_ENTRY - 4) {
printf(" Maximum number of memory map entries reached.\n \n");
printf(" Maximum number of memory map entries reached. \n \n");
return;
}
qwAddrBase = ps->i.qwAddrBase + ps->i.MemMapPrintCommitPages * 0x1000;
Expand All @@ -32,7 +32,7 @@ VOID _PageStatPrintMemMap(_Inout_ PPAGE_STATISTICS ps)
if((i % 2) == 0) {
fIsLinePrinted = TRUE;
printf(
" %016llx - %016llx %08x\n",
" %016llx - %016llx %08x \n",
qwAddrBase,
qwAddrEnd - 1,
ps->i.MemMap[i]);
Expand All @@ -45,9 +45,9 @@ VOID _PageStatPrintMemMap(_Inout_ PPAGE_STATISTICS ps)
qwAddrBase = qwAddrEnd;
}
if(!fIsLinePrinted) { // print extra line for formatting reasons.
printf(" (No memory successfully read yet) \n");
printf(" (No memory successfully read yet) \n");
}
printf(" \n");
printf(" \n");
}

VOID _PageStatShowUpdate(_Inout_ PPAGE_STATISTICS ps)
Expand Down
4 changes: 2 additions & 2 deletions pcileech/vfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -835,7 +835,7 @@ VfsCallback_ReadFile(LPCWSTR wcsFileName, LPVOID Buffer, DWORD BufferLength, LPD
if(!_wcsnicmp(wcsFileName, L"\\files\\", 7) && pds->fKMD) {
return _VfsReadFile_File(wcsFileName, Buffer, BufferLength, ReadLength, Offset, DokanFileInfo);
}
if(pds->fVMM && (!_wcsnicmp(wcsFileName, L"\\proc\\name\\", 1) || !_wcsnicmp(wcsFileName, L"\\proc\\pid\\", 10))) {
if(pds->fVMM && (!_wcsnicmp(wcsFileName, L"\\proc\\name\\", 11) || !_wcsnicmp(wcsFileName, L"\\proc\\pid\\", 10))) {
return VmmVfsReadFile(pds->ctx, wcsFileName, Buffer, BufferLength, ReadLength, Offset);
}
return STATUS_FILE_INVALID;
Expand Down Expand Up @@ -865,7 +865,7 @@ VfsCallback_WriteFile(LPCWSTR wcsFileName, LPCVOID Buffer, DWORD NumberOfBytesTo
if(!_wcsnicmp(wcsFileName, L"\\files\\", 7) && pds->fKMD) {
return _VfsWriteFile_File(wcsFileName, Buffer, NumberOfBytesToWrite, NumberOfBytesWritten, Offset, DokanFileInfo);
}
if(pds->fVMM && (!_wcsnicmp(wcsFileName, L"\\proc\\name\\", 1) || !_wcsnicmp(wcsFileName, L"\\proc\\pid\\", 10))) {
if(pds->fVMM && (!_wcsnicmp(wcsFileName, L"\\proc\\name\\", 11) || !_wcsnicmp(wcsFileName, L"\\proc\\pid\\", 10))) {
return VmmVfsWriteFile(pds->ctx, wcsFileName, (PBYTE)Buffer, NumberOfBytesToWrite, NumberOfBytesWritten, Offset);
}
return STATUS_FILE_INVALID;
Expand Down
44 changes: 37 additions & 7 deletions pcileech/vmm.c
Original file line number Diff line number Diff line change
Expand Up @@ -739,23 +739,53 @@ BOOL VmmReadPhysicalPage(_Inout_ PVMM_CONTEXT ctxVmm, _In_ QWORD qwPA, _Inout_by
return FALSE;
}

VOID VmmReadScatterVirtual(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _Inout_ PPDMA_IO_SCATTER_HEADER ppDMAsVirt, _In_ DWORD cpDMAsVirt)
VOID VmmReadScatterVirtual(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _Inout_ PPDMA_IO_SCATTER_HEADER ppDMAsVirt, _In_ DWORD cpDMAsVirt, _In_ QWORD flags)
{
BOOL result;
QWORD i, j, cPagesPerScatterRead, qwVA, qwPA, cpDMAsPhys = 0;
PDMA_IO_SCATTER_HEADER pDMA_Virt, pDMA_Phys;
PVMM_CACHE_ENTRY ppDMAsPhysCacheEntry[0x48];
PDMA_IO_SCATTER_HEADER ppDMAsPhys[0x48];
DMA_IO_SCATTER_HEADER pDMAsPhys_NoCache[0x48];
BOOL fCacheDisable = flags & VMM_FLAG_NOCACHE;
// 1: translate virt2phys
for(i = 0; i < cpDMAsVirt; i++) {
pDMA_Virt = ppDMAsVirt[i];
result = VmmVirt2Phys(ctxVmm, pProcess, pDMA_Virt->qwA, &qwPA);
(QWORD)pDMA_Virt->pvReserved1 = (result && (pDMA_Virt->cbMax == 0x1000)) ? 0 : 1;
(QWORD)pDMA_Virt->pvReserved2 = qwPA;
}
// 2: translate virt2phys and retrieve data loop
// 2: retrieve data loop below
cpDMAsPhys = 0;
cPagesPerScatterRead = min(0x48, ((ctxVmm->ctxPcileech->cfg->qwMaxSizeDmaIo & ~0xfff) >> 12));
// 2.1: retrieve data loop - read strategy: non-cached read
if(fCacheDisable) {
for(i = 0; i < cpDMAsVirt; i++) {
pDMA_Virt = ppDMAsVirt[i];
if(!(QWORD)pDMA_Virt->pvReserved1) { // phys2virt translation exists
pDMA_Phys = &pDMAsPhys_NoCache[cpDMAsPhys];
pDMA_Phys->pb = pDMA_Virt->pb;
pDMA_Phys->cbMax = pDMA_Virt->cbMax;
pDMA_Phys->cb = 0;
pDMA_Phys->qwA = (QWORD)pDMA_Virt->pvReserved2;
(QWORD)pDMA_Phys->pvReserved1 = i;
ppDMAsPhys[cpDMAsPhys] = pDMA_Phys;
cpDMAsPhys++;
}
// physical read if requesting queue is full or if this is last
if(cpDMAsPhys && ((cpDMAsPhys == cPagesPerScatterRead) || (i == cpDMAsVirt - 1))) {
// physical memory access
DeviceReadScatterDMA(ctxVmm->ctxPcileech, ppDMAsPhys, (DWORD)cpDMAsPhys, NULL);
for(j = 0; j < cpDMAsPhys; j++) {
pDMA_Phys = ppDMAsPhys[j];
ppDMAsVirt[(QWORD)pDMA_Phys->pvReserved1]->cb = pDMA_Phys->cb;
}
cpDMAsPhys = 0;
}
}
return;
}
// 2.2: retrieve data loop - read strategy: cached read (standard/preferred)
for(i = 0; i < cpDMAsVirt; i++) {
// retrieve from cache (if found)
pDMA_Virt = ppDMAsVirt[i];
Expand All @@ -777,7 +807,7 @@ VOID VmmReadScatterVirtual(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProce
cpDMAsPhys++;
}
}
// physical read if requesting queue is full of if this is last
// physical read if requesting queue is full or if this is last
if(cpDMAsPhys && ((cpDMAsPhys == cPagesPerScatterRead) || (i == cpDMAsVirt - 1))) {
// SPECULATIVE FUTURE READ IF NEGLIGIBLE PERFORMANCE LOSS
while(cpDMAsPhys < min(0x18, cPagesPerScatterRead)) {
Expand Down Expand Up @@ -875,7 +905,7 @@ BOOL VmmWrite(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _In_ QWOR
return (cbWrite == cb);
}

VOID VmmReadEx(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt)
VOID VmmReadEx(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags)
{
DWORD cbP, cDMAs, cbRead = 0;
PBYTE pbBuffer;
Expand All @@ -901,7 +931,7 @@ VOID VmmReadEx(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _In_ QWO
pDMAs[cDMAs - 1].pb = pbBuffer + 0x1000;
}
// Read VMM and handle result
VmmReadScatterVirtual(ctxVmm, pProcess, ppDMAs, cDMAs);
VmmReadScatterVirtual(ctxVmm, pProcess, ppDMAs, cDMAs, flags);
for(i = 0; i < cDMAs; i++) {
if(pDMAs[i].cb == 0x1000) {
cbRead += 0x1000;
Expand Down Expand Up @@ -951,7 +981,7 @@ BOOL VmmReadString_Unicode2Ansi(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS p
BOOL VmmRead(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Out_ PBYTE pb, _In_ DWORD cb)
{
DWORD cbRead;
VmmReadEx(ctxVmm, pProcess, qwVA, pb, cb, &cbRead);
VmmReadEx(ctxVmm, pProcess, qwVA, pb, cb, &cbRead, 0);
return (cbRead == cb);
}

Expand All @@ -963,7 +993,7 @@ BOOL VmmReadPage(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _In_ Q
pDMA->pb = pbPage;
pDMA->cb = 0;
pDMA->cbMax = 0x1000;
VmmReadScatterVirtual(ctxVmm, pProcess, &pDMA, 1);
VmmReadScatterVirtual(ctxVmm, pProcess, &pDMA, 1, 0);
return (pDMA->cb == 0x1000);
}

Expand Down
14 changes: 12 additions & 2 deletions pcileech/vmm.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@
#define VMM_CACHE_TLB_ENTRIES 0x4000 // -> 64MB of cached data
#define VMM_CACHE_PHYS_ENTRIES 0x4000 // -> 64MB of cached data

#define VMM_FLAG_NOCACHE 0x0001 // do not use the data cache (force reading from DMA device)

typedef struct tdVMM_MEMMAP_ENTRY {
QWORD AddrBase;
QWORD cPages;
Expand Down Expand Up @@ -60,6 +62,7 @@ typedef struct tdVMM_PROCESS {
BOOL _i_fMigrated;
BOOL fUserOnly;
BOOL fSpiderPageTableDone;
BOOL fFileCacheDisabled;
// memmap related pointers (free must be called separately)
QWORD cMemMap;
PVMM_MEMMAP_ENTRY pMemMap;
Expand Down Expand Up @@ -137,6 +140,11 @@ typedef struct tdVMM_CONTEXT {
struct {
BOOL fEnabled;
HANDLE hThread;
DWORD cMs_TickPeriod;
DWORD cTick_Phys;
DWORD cTick_TLB;
DWORD cTick_ProcPartial;
DWORD cTick_ProcTotal;
} ThreadProcCache;
} VMM_CONTEXT, *PVMM_CONTEXT;

Expand Down Expand Up @@ -198,8 +206,9 @@ BOOL VmmRead(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _In_ QWORD
* -- pb
* -- cb
* -- pcbRead
* -- flags = flags as in VMM_FLAG_*
*/
VOID VmmReadEx(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt);
VOID VmmReadEx(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _In_ QWORD qwVA, _Inout_ PBYTE pb, _In_ DWORD cb, _Out_opt_ PDWORD pcbReadOpt, _In_ QWORD flags);

/*
* Read a single 4096-byte page of virtual memory.
Expand All @@ -217,8 +226,9 @@ BOOL VmmReadPage(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _In_ Q
* -- pProcess
* -- ppDMAsVirt
* -- cpDMAsVirt
* -- flags = flags as in VMM_FLAG_*, [VMM_FLAG_NOCACHE for supression of data (not tlb) caching]
*/
VOID VmmReadScatterVirtual(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _Inout_ PPDMA_IO_SCATTER_HEADER ppDMAsVirt, _In_ DWORD cpDMAsVirt);
VOID VmmReadScatterVirtual(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS pProcess, _Inout_ PPDMA_IO_SCATTER_HEADER ppDMAsVirt, _In_ DWORD cpDMAsVirt, _In_ QWORD flags);

/*
* Read a single 4096-byte page of physical memory.
Expand Down
25 changes: 15 additions & 10 deletions pcileech/vmmproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ VOID VmmProcWindows_PE_LoadIAT_DisplayBuffer(_Inout_ PVMM_CONTEXT ctxVmm, _Inout
if(pModule->SizeOfImage > 0x01000000) { return; }
cbModule = pModule->SizeOfImage;
if(!(pbModule = LocalAlloc(LMEM_ZEROINIT, cbModule))) { return; }
VmmReadEx(ctxVmm, pProcess, pModule->BaseAddress, pbModule, cbModule, &cbRead);
VmmReadEx(ctxVmm, pProcess, pModule->BaseAddress, pbModule, cbModule, &cbRead, 0);
if(cbRead <= 0x2000) { goto cleanup; }
// load both 32/64 bit ntHeader (only one will be valid)
if(!(ntHeader64 = VmmProcWindows_GetVerifyHeaderPE(ctxVmm, pProcess, pModule->BaseAddress, pbModuleHeader, &fHdr32))) { goto cleanup; }
Expand Down Expand Up @@ -533,7 +533,7 @@ QWORD VmmProcWindows_FindNtoskrnl(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS
if(!pb) { goto cleanup; }
// Scan back in 2MB chunks a time, (ntoskrnl.exe is loaded in 2MB pages).
for(vaBase = vaKernelEntry & ~0x1fffff; vaBase + 0x02000000 > vaKernelEntry; vaBase -= 0x200000) {
VmmReadEx(ctxVmm, pSystemProcess, vaBase, pb, 0x200000, &cbRead);
VmmReadEx(ctxVmm, pSystemProcess, vaBase, pb, 0x200000, &cbRead, 0);
// only fail here if all virtual memory in read fails. reason is that kernel is
// properly mapped in memory (with NX MZ header in separate page) with empty
// space before next valid kernel pages when running Virtualization Based Security.
Expand Down Expand Up @@ -713,7 +713,7 @@ VOID VmmProcWindows_ScanHeaderPE(_Inout_ PVMM_CONTEXT ctxVmm, _In_ PVMM_PROCESS
}
}
// 3: read all MZ header candicates previously selected and try load name from them (after read is successful)
VmmReadScatterVirtual(ctxVmm, pProcess, ppDMAs, cDMAs);
VmmReadScatterVirtual(ctxVmm, pProcess, ppDMAs, cDMAs, 0);
for(i = 0; i < cDMAs; i++) {
if(pMaps[i].dma.cb == 0x1000) {
pMap = pMaps + i;
Expand Down Expand Up @@ -1041,7 +1041,7 @@ QWORD VmmProcPHYS_ScanWindowsKernel_LargePages(_Inout_ PVMM_CONTEXT ctxVmm, _In_
// try locate ntoskrnl.exe base inside suggested area
pbBuffer = (PBYTE)LocalAlloc(0, cbSize);
if(!pbBuffer) { return 0; }
VmmReadEx(ctxVmm, pSystemProcess, vaBase, pbBuffer, (DWORD)cbSize, NULL);
VmmReadEx(ctxVmm, pSystemProcess, vaBase, pbBuffer, (DWORD)cbSize, NULL, 0);
for(p = 0; p < cbSize; p += 0x1000) {
if(*(PWORD)(pbBuffer + p) != 0x5a4d) { continue; }
// check if module header contains INITKDBG and POOLCODE
Expand Down Expand Up @@ -1149,8 +1149,8 @@ BOOL VmmProcUserCR3TryInitialize(_Inout_ PVMM_CONTEXT ctxVmm)

#define VMMPROC_UPDATERTHREAD_PERIOD 50
#define VMMPROC_UPDATERTHREAD_PHYSCACHE (500 / VMMPROC_UPDATERTHREAD_PERIOD) // 0.5s
#define VMMPROC_UPDATERTHREAD_TLB (5 * 1000 / VMMPROC_UPDATERTHREAD_PERIOD) // 5s
#define VMMPROC_UPDATERTHREAD_PROC_REFRESHLIST (5 * 1000 / VMMPROC_UPDATERTHREAD_PERIOD) // 5s
#define VMMPROC_UPDATERTHREAD_TLB (15 * 1000 / VMMPROC_UPDATERTHREAD_PERIOD) // 15s
#define VMMPROC_UPDATERTHREAD_PROC_REFRESHTOTAL (15 * 1000 / VMMPROC_UPDATERTHREAD_PERIOD) // 15s

DWORD VmmProcCacheUpdaterThread(_Inout_ PVMM_CONTEXT ctxVmm)
Expand All @@ -1162,13 +1162,18 @@ DWORD VmmProcCacheUpdaterThread(_Inout_ PVMM_CONTEXT ctxVmm)
if(ctxVmm->ctxPcileech->cfg->fVerbose) {
printf("VmmProc: Start periodic cache flushing.\n");
}
ctxVmm->ThreadProcCache.cMs_TickPeriod = VMMPROC_UPDATERTHREAD_PERIOD;
ctxVmm->ThreadProcCache.cTick_Phys = VMMPROC_UPDATERTHREAD_PHYSCACHE;
ctxVmm->ThreadProcCache.cTick_TLB = VMMPROC_UPDATERTHREAD_TLB;
ctxVmm->ThreadProcCache.cTick_ProcPartial = VMMPROC_UPDATERTHREAD_PROC_REFRESHLIST;
ctxVmm->ThreadProcCache.cTick_ProcTotal = VMMPROC_UPDATERTHREAD_PROC_REFRESHTOTAL;
while(ctxVmm->ThreadProcCache.fEnabled) {
Sleep(VMMPROC_UPDATERTHREAD_PERIOD);
Sleep(ctxVmm->ThreadProcCache.cMs_TickPeriod);
i++;
fTLB = !(i % VMMPROC_UPDATERTHREAD_PHYSCACHE);
fPHYS = !(i % VMMPROC_UPDATERTHREAD_PHYSCACHE);
fProcTotal = !(i % VMMPROC_UPDATERTHREAD_PROC_REFRESHTOTAL);
fProcList = !(i % VMMPROC_UPDATERTHREAD_PROC_REFRESHLIST) && !fProcTotal;
fTLB = !(i % ctxVmm->ThreadProcCache.cTick_TLB);
fPHYS = !(i % ctxVmm->ThreadProcCache.cTick_Phys);
fProcTotal = !(i % ctxVmm->ThreadProcCache.cTick_ProcTotal);
fProcList = !(i % ctxVmm->ThreadProcCache.cTick_ProcPartial) && !fProcTotal;
EnterCriticalSection(&ctxVmm->MasterLock);
// PHYS / TLB cache clear
if(fPHYS || fTLB) {
Expand Down
Loading

0 comments on commit ec7a8ba

Please sign in to comment.