📄 celog.c
字号:
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
//
// This source code is licensed under Microsoft Shared Source License
// Version 1.0 for Windows CE.
// For a copy of the license visit http://go.microsoft.com/fwlink/?LinkId=3223.
//
//------------------------------------------------------------------------------
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF
// ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO
// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
//
//------------------------------------------------------------------------------
//
// Module Name:
//
// celog.c
//
// Abstract:
//
// Implements the CeLog event logging functions.
//
//------------------------------------------------------------------------------
#include <kernel.h>
#ifndef _PREFAST_
#pragma warning(disable: 4068) // Disable pragma warnings
#endif
#define MODNAME TEXT("CeLog")
#ifdef DEBUG
DBGPARAM dpCurSettings = { MODNAME, {
TEXT("<unused>"), TEXT("<unused>"), TEXT("<unused>"), TEXT("<unused>"),
TEXT("<unused>"), TEXT("<unused>"), TEXT("<unused>"), TEXT("<unused>"),
TEXT("<unused>"), TEXT("<unused>"), TEXT("<unused>"), TEXT("<unused>"),
TEXT("<unused>"), TEXT("<unused>"), TEXT("<unused>"), TEXT("<unused>") },
0x00000000};
#endif
#define ZONE_VERBOSE 0
//------------------------------------------------------------------------------
// BUFFERS
typedef struct __CEL_BUFFER {
DWORD dwMaskProcess; // Process mask (1 bit per process slot)
DWORD dwMaskUser; // User zone mask
DWORD dwMaskCE; // Predefined zone mask (CELZONE_xxx)
PDWORD pWrite; // Pointer to next entry to be written
DWORD dwBytesLeft; // Bytes left available in the buffer
DWORD dwSize; // Total number of bytes in the buffer
PDWORD pBuffer; // Start of the data
} CEL_BUFFER, *PCEL_BUFFER;
typedef struct _RINGBUFFER {
HANDLE hMap; // Used for RingBuf memory mapping
PMAPHEADER pHeader; // Pointer to RingBuf map header
LPBYTE pBuffer;
LPBYTE pRead;
LPBYTE pWrite;
LPBYTE pWrap;
DWORD dwSize;
DWORD dwBytesLeft; // Calculated during flush for RingBuf, always valid for IntBuf
} RINGBUFFER, *PRINGBUFFER;
RINGBUFFER RingBuf;
RINGBUFFER IntBuf;
PCEL_BUFFER pCelBuf;
CEL_BUFFER CelBuf;
//------------------------------------------------------------------------------
// EXPORTED GLOBAL VARIABLES
#define SMALLBUF_MAX 4096*1024 // Maximum size an OEM can boost the small buffer to
#define PAGES_IN_MAX_BUFFER (SMALLBUF_MAX/PAGE_SIZE)
#define RINGBUF_SIZE 128*1024 // Default size of large buffer
#ifndef CELOG_SIZE
#define SMALLBUF_SIZE 4*1024 // Default size of small buffer
#else
#define SMALLBUF_SIZE CELOG_SIZE // Default size of small buffer
#endif
//------------------------------------------------------------------------------
// MISC
// RESERVED zones cannot be turned on, CELZONE_ALWAYSON cannot be turned off
#define VALIDATE_ZONES(dwVal) (((dwVal) & ~(CELZONE_RESERVED1|CELZONE_RESERVED2)) | CELZONE_ALWAYSON)
#define MAX_ROLLOVER_MINUTES 30
#define MAX_ROLLOVER_COUNT (0xFFFFFFFF / (MAX_ROLLOVER_MINUTES * 60))
HANDLE g_hFillEvent; // Used to indicate the secondary buffer is getting full
BOOL g_fInit;
DWORD g_dwDiscardedInterrupts;
DWORD g_dwPerfTimerShift;
// Inputs from kernel
CeLogImportTable g_PubImports;
CeLogPrivateImports g_PrivImports;
#define DATAMAP_NAME CELOG_DATAMAP_NAME
#define FILLEVENT_NAME CELOG_FILLEVENT_NAME
//------------------------------------------------------------------------------
// Abstract accesses to imports
#define PUB_FUNC(Api, Args) ((g_PubImports.p##Api) Args)
#define PUB_VAR(Var) (g_PubImports.Var)
#define PRIV_FUNC(Api, Args) ((g_PrivImports.p##Api) Args)
#define PRIV_VAR(Var) (g_PrivImports.Var)
#define ISAPIREADY(hAPI) ((UserKInfo[KINX_API_MASK] & (1 << (hAPI))) != 0)
// KData accesses are hidden in SWITCHKEY, SETCURKEY
#undef KData
#define KData (*PRIV_VAR(pKData))
#ifndef SHIP_BUILD
#undef RETAILMSG
#define RETAILMSG(cond, printf_exp) ((cond)?(PUB_FUNC(NKDbgPrintfW, printf_exp),1):0)
#endif // SHIP_BUILD
#ifdef DEBUG
#undef DEBUGMSG
#define DEBUGMSG RETAILMSG
#endif // DEBUG
#ifdef DEBUG
#undef DBGCHK
#undef DEBUGCHK
#define DBGCHK(module,exp) \
((void)((exp)?1 \
:(PUB_FUNC(NKDbgPrintfW, (TEXT("%s: DEBUGCHK failed in file %s at line %d\r\n"), \
(LPWSTR)module, TEXT(__FILE__), __LINE__)), \
DebugBreak(), \
0 \
)))
#define DEBUGCHK(exp) DBGCHK(dpCurSettings.lpszName, exp)
#endif // DEBUG
//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static void
INT_WriteRingBuffer(
PRINGBUFFER pRingBuf,
LPBYTE lpbData, // NULL = just move pointers/counters
DWORD dwBytes,
LPDWORD lpdwBytesLeft1,
LPDWORD lpdwBytesLeft2
)
{
DWORD dwSrcLen1, dwSrcLen2;
dwSrcLen1 = min(dwBytes, *lpdwBytesLeft1);
dwSrcLen2 = dwBytes - dwSrcLen1;
// Write to middle or end of buffer
if (dwSrcLen1) {
if (lpbData) {
memcpy(pRingBuf->pWrite, lpbData, dwSrcLen1);
lpbData += dwSrcLen1;
}
pRingBuf->pWrite += dwSrcLen1;
pRingBuf->dwBytesLeft -= dwSrcLen1;
*lpdwBytesLeft1 -= dwSrcLen1;
if (pRingBuf->pWrite >= pRingBuf->pWrap) {
pRingBuf->pWrite = pRingBuf->pBuffer;
}
}
// Write to front of buffer in case of wrap
if (dwSrcLen2) {
if (lpbData) {
memcpy(pRingBuf->pWrite, lpbData, dwSrcLen2);
}
pRingBuf->pWrite += dwSrcLen2;
pRingBuf->dwBytesLeft -= dwSrcLen2;
*lpdwBytesLeft2 -= dwSrcLen2;
}
}
//------------------------------------------------------------------------------
// FlushBuffer is interruptable but non-preemptible
//------------------------------------------------------------------------------
static void
INT_FlushBuffer()
{
DWORD dwSrcLen1, dwSrcLen2, dwSrcTotal;
DWORD dwDestLen1, dwDestLen2; // Locals instead of ringbuf members because temp.
LPBYTE pReadCopy, pWriteCopy;
DWORD dwBytesLeftCopy;
ACCESSKEY akyOld;
static DWORD dwTLBPrev = 0;
SWITCHKEY(akyOld, 0x00000001); // Guarantee access to NK
pReadCopy = RingBuf.pHeader->pRead;
RingBuf.dwBytesLeft = (DWORD) pReadCopy - (DWORD) RingBuf.pWrite + RingBuf.dwSize;
if (RingBuf.dwBytesLeft > RingBuf.dwSize) {
// wrapped.
RingBuf.dwBytesLeft -= RingBuf.dwSize;
}
if ((RingBuf.dwBytesLeft < RingBuf.dwSize / 4) && RingBuf.pHeader->fSetEvent) {
// Signal that the secondary buffer is getting full
RingBuf.pHeader->fSetEvent = FALSE; // Block any more SetEvent calls
PUB_FUNC(EventModify, (g_hFillEvent, EVENT_SET)); // SetEvent
}
dwSrcTotal = (DWORD) pCelBuf->pWrite - (DWORD) pCelBuf->pBuffer;
if (RingBuf.dwBytesLeft <= dwSrcTotal) {
RETAILMSG(ZONE_VERBOSE, (MODNAME TEXT(": ERROR, Secondary Buffer Overrun. Dropping %d bytes (%d available)\r\n"),
dwSrcTotal, RingBuf.dwBytesLeft));
RingBuf.pHeader->dwLostBytes += dwSrcTotal;
// Reset primary buffer to the beginning
pCelBuf->pWrite = pCelBuf->pBuffer;
pCelBuf->dwBytesLeft = pCelBuf->dwSize;
SETCURKEY(akyOld);
return;
}
//
// Determine where we can write into the large buffer
//
if (RingBuf.pWrite >= pReadCopy) {
// pRead pWrap
// v v
// +-----------------------+
// | 2 |XXXXXX| 1 |
// +-----------------------+
// ^ ^
// pBuffer pWrite
dwDestLen1 = (DWORD) RingBuf.pWrap - (DWORD) RingBuf.pWrite;
dwDestLen2 = (DWORD) pReadCopy - (DWORD) RingBuf.pBuffer;
} else {
// pBuffer pRead
// v v
// +-----------------------+
// |XXXXX| |XXXXXXX|
// +-----------------------+
// ^ ^
// pWrite pWrap
dwDestLen1 = (DWORD) pReadCopy - (DWORD) RingBuf.pWrite;
dwDestLen2 = 0;
}
// Copy the data
INT_WriteRingBuffer(&RingBuf, (LPBYTE)pCelBuf->pBuffer, dwSrcTotal, &dwDestLen1, &dwDestLen2);
RingBuf.pHeader->pWrite = RingBuf.pWrite; // Update map header
pCelBuf->pWrite = pCelBuf->pBuffer;
pCelBuf->dwBytesLeft = pCelBuf->dwSize;
//--------------------------------------------------------------
// Now copy in the interrupts that happened during this quantum
//
// Copy the counters because interrupts are still on (retry if interrupted)
do {
pWriteCopy = *(volatile LPBYTE*)&IntBuf.pWrite;
dwBytesLeftCopy = *(volatile DWORD*)&IntBuf.dwBytesLeft;
} while ((pWriteCopy != *(volatile LPBYTE*)&IntBuf.pWrite)
|| (dwBytesLeftCopy != *(volatile DWORD*)&IntBuf.dwBytesLeft));
dwSrcTotal = IntBuf.dwSize - dwBytesLeftCopy;
if (dwSrcTotal) {
if (RingBuf.dwBytesLeft < (dwSrcTotal + 8)) {
RETAILMSG(ZONE_VERBOSE, (MODNAME TEXT(": ERROR, Secondary Buffer Overrun. Dropping %d bytes (interrupts) (%d available)\r\n"),
dwSrcTotal, RingBuf.dwBytesLeft));
RingBuf.pHeader->dwLostBytes += dwSrcTotal + 8;
// Reset interrupt buffer to the beginning
IntBuf.pRead = pWriteCopy;
IntBuf.dwBytesLeft += dwSrcTotal;
SETCURKEY(akyOld);
return;
}
// Write in the interrupt header
*((PDWORD) RingBuf.pWrite) = CELID_INTERRUPTS << 16 | (WORD) (dwSrcTotal + 4);
INT_WriteRingBuffer(&RingBuf, NULL, sizeof(DWORD), &dwDestLen1, &dwDestLen2);
*((PDWORD) RingBuf.pWrite) = g_dwDiscardedInterrupts;
INT_WriteRingBuffer(&RingBuf, NULL, sizeof(DWORD), &dwDestLen1, &dwDestLen2);
// Determine where to copy from in the interrupt buffer
if (pWriteCopy > IntBuf.pRead) {
// pRead pWrap
// v v
// +-----------------------+
// | |XX 1 X| |
// +-----------------------+
// ^ ^
// pBuffer pWrite
dwSrcLen1 = (DWORD) pWriteCopy - (DWORD) IntBuf.pRead;
dwSrcLen2 = 0;
} else {
// pBuffer pRead
// v v
// +-----------------------+
// |X 2 X| |XX 1 XX|
// +-----------------------+
// ^ ^
// pWrite pWrap
dwSrcLen1 = (DWORD) IntBuf.pWrap - (DWORD) IntBuf.pRead;
dwSrcLen2 = (DWORD) pWriteCopy - (DWORD) IntBuf.pBuffer;
}
// Copy the data
if (dwSrcLen1) {
INT_WriteRingBuffer(&RingBuf, IntBuf.pRead, dwSrcLen1, &dwDestLen1, &dwDestLen2);
}
if (dwSrcLen2) {
INT_WriteRingBuffer(&RingBuf, IntBuf.pBuffer, dwSrcLen2, &dwDestLen1, &dwDestLen2);
}
RingBuf.pHeader->pWrite = RingBuf.pWrite; // Update map header
IntBuf.pRead = pWriteCopy;
IntBuf.dwBytesLeft += dwSrcLen1 + dwSrcLen2;
g_dwDiscardedInterrupts = 0;
}
//--------------------------------------------------------------
// Now copy in the TLB Misses that happened in this quantum
//
if (PUB_VAR(pdwCeLogTLBMiss) && (*PUB_VAR(pdwCeLogTLBMiss) != dwTLBPrev)
&& (pCelBuf->dwMaskCE & CELZONE_TLB)) {
if (RingBuf.dwBytesLeft < 2*sizeof(DWORD)) {
RETAILMSG(ZONE_VERBOSE, (MODNAME TEXT(": ERROR, Secondary Buffer Overrun. Delaying TLB Miss Data report\r\n")));
RingBuf.pHeader->dwLostBytes += 2*sizeof(DWORD);
SETCURKEY(akyOld);
return;
}
// Write in the TLB miss header
*((PDWORD) RingBuf.pWrite) = CELID_SYSTEM_TLB << 16 | sizeof(CEL_SYSTEM_TLB);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -