⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 profxsc1.c

📁 Windows CE 6.0 BSP for VOIPAC Board (PXA270) Version 2b.
💻 C
字号:
//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//
#include <windows.h>
#include <string.h>
#include <nkintr.h>
#include <profiler.h>
#include <profxsc1.h>
#include <Xsc1RegisterBitsPMNC.h>
#include <CspPerfRegFuncs.h>

// Current profiler settings
static XSC1_ProfilerControl g_PMUSettings;

// Rollover counters for each register
static DWORD g_dwRolloverCCNT;
static DWORD g_dwRolloverPMN0;
static DWORD g_dwRolloverPMN1;

// Keep track of whether the profiler is running
static BOOL g_fIsPMURunning;

// defined in winceos\coreos\nk\kernel\profiler.c
extern DWORD g_dwProfilerFlags; 

//
// Handle IOCTL_HAL_OEM_PROFILER
//
DWORD g_dwDebugFlag = 0;
DWORD CspPerfRegIoctl(LPVOID lpInBuf, DWORD nInBufSize, LPVOID lpOutBuf,
	                  DWORD nOutBufSize, LPDWORD lpBytesReturned, DWORD *lpAction)
{
    ProfilerControl *pControl = (ProfilerControl*)lpInBuf;

    if (!lpInBuf
        || (nInBufSize != (sizeof(ProfilerControl) + pControl->OEM.dwControlSize)) ||
        (NULL == lpAction) ) {
        return ERROR_INVALID_PARAMETER;
    }

    *lpAction = XSC1PROFILERCONTROL_NOACTION;
    
    // Only START, STOP, QUERY are currently supported
    if (pControl->dwOptions & (PROFILE_OEM_QUERY | PROFILE_STOP)) {  

        OEMProfilerData   *pOemData;
        XSC1_ProfilerData *pHitData;

        // Cannot stop if it's not running
        if ((pControl->dwOptions & PROFILE_STOP) && !g_fIsPMURunning) {
            return ERROR_ALREADY_EXISTS;
        }
        
        // Return PMU values as an XSC1_ProfilerData struct in lpOutBuf.
        // Allow lpOutBuf to be NULL if the user does not want to query the
        // settings on STOP.
        if (lpOutBuf) {
        	
            // BUGBUG should check caller trust & access rights to lpOutBuf & lpBytesReturned
            if (lpBytesReturned) {
                *lpBytesReturned = sizeof(OEMProfilerData) + sizeof(XSC1_ProfilerData);
            }

            if (nOutBufSize < (sizeof(OEMProfilerData) + sizeof(XSC1_ProfilerData))) {
                return ERROR_INSUFFICIENT_BUFFER;  // Required size is set in lpBytesReturned
            }

        	// Read the registers into the output buffer
        	pOemData = lpOutBuf;
        	pOemData->dwBufSize = sizeof(XSC1_ProfilerData);

        	pHitData = (XSC1_ProfilerData*)pOemData->buf;

        	pHitData->dwValCCNT      = ReadPMURegister(PMUREG_CCNT);
        	pHitData->dwOverflowCCNT = g_dwRolloverCCNT;
        	pHitData->dwValPMN0      = ReadPMURegister(PMUREG_PMN0);
        	pHitData->dwOverflowPMN0 = g_dwRolloverPMN0;
        	pHitData->dwValPMN1      = ReadPMURegister(PMUREG_PMN1);
        	pHitData->dwOverflowPMN1 = g_dwRolloverPMN1;

        }

        if (pControl->dwOptions & PROFILE_STOP) {

            DWORD dwPMNC;  // PMU control register setting
            
    		// Stop PMU
    		dwPMNC = ReadPMURegister(PMUREG_PMNC);
    		CLEAR_PMNC(dwPMNC);
    		PMNC_BIT_P_SET(dwPMNC);
    		PMNC_BIT_C_SET(dwPMNC);
    		WritePMURegister(PMUREG_PMNC, dwPMNC);

            *lpAction = XSC1PROFILERCONTROL_STOP;

            g_fIsPMURunning = FALSE;
            
        }

        return NO_ERROR;

    
    } else if (pControl->dwOptions & PROFILE_START) {
        XSC1_ProfilerControl *pXSC1Control;
        DWORD dwPMNC;  // PMU control register setting
        
        // XSC1_ProfilerControl struct is required as input
        if (nInBufSize != sizeof(ProfilerControl) + sizeof(XSC1_ProfilerControl)) {
            return ERROR_INVALID_PARAMETER;
        }

        // Cannot start if it's already running
        if (g_fIsPMURunning) {
            return ERROR_ALREADY_EXISTS;  // BUGBUG there must be a better error
        }

        *lpAction = XSC1PROFILERCONTROL_START;
        
        pXSC1Control = (XSC1_ProfilerControl*)&(pControl->OEM.bHardwareSpecificSettings);
        memcpy(&g_PMUSettings, pXSC1Control, sizeof(XSC1_ProfilerControl));

        dwPMNC = ReadPMURegister(PMUREG_PMNC);

        // clear out read-unpredictable / write-as-zero bits, as well as everything else
        CLEAR_PMNC(dwPMNC);

        // ensure that clock divisor is not set
        PMNC_BIT_D_DIS(dwPMNC);

        g_dwRolloverCCNT = 0;
        g_dwRolloverPMN0 = 0;
        g_dwRolloverPMN1 = 0;

        // CCNT, PMN0, and/or PMN1 are being used to generate an irq.  Seed the register(s).
        if(g_PMUSettings.dwCCNTOverflowInterval) {
        	WritePMURegister(PMUREG_CCNT, 0xFFFFFFFF - g_PMUSettings.dwCCNTOverflowInterval);
        } 
        else {
        	WritePMURegister(PMUREG_CCNT, 0);
        }

        if(g_PMUSettings.dwPMN0OverflowInterval) {
        	WritePMURegister(PMUREG_PMN0, 0xFFFFFFFF - g_PMUSettings.dwPMN0OverflowInterval);
        }
        else {
        	WritePMURegister(PMUREG_PMN0, 0);
        }

        if(g_PMUSettings.dwPMN1OverflowInterval) {
        	WritePMURegister(PMUREG_PMN1, 0xFFFFFFFF - g_PMUSettings.dwPMN1OverflowInterval);
        }
        else {
        	WritePMURegister(PMUREG_PMN1, 0);
        }

        // set the events, and what is generating irq's
        dwPMNC |= g_PMUSettings.dwPMNCFlags;
        	WritePMURegister(PMUREG_PMNC, dwPMNC);

        g_fIsPMURunning = TRUE;

        return NO_ERROR;

    
    } else {
        // STARTPAUSED, PAUSE, CONTINUE are not currently supported
        return ERROR_NOT_SUPPORTED;
    }

	// should never get here
    return ERROR_BAD_COMMAND;
}


// Read the PMU registers and send the data to the kernel profiler
static VOID LogHit(unsigned int ra)
{
    BYTE bTemp[sizeof(OEMProfilerData) + sizeof(XSC1_ProfilerData)];
    OEMProfilerData   *pOEMData  = (OEMProfilerData*)bTemp;
    XSC1_ProfilerData *pXSC1Data = (XSC1_ProfilerData*)&(pOEMData->buf);

    // Populate the data buffer
    pOEMData->ra = ra;
    pOEMData->dwBufSize = sizeof(XSC1_ProfilerData);

    pXSC1Data->dwValCCNT      = ReadPMURegister(PMUREG_CCNT);
    pXSC1Data->dwOverflowCCNT = g_dwRolloverCCNT;
    pXSC1Data->dwValPMN0      = ReadPMURegister(PMUREG_PMN0);
    pXSC1Data->dwOverflowPMN0 = g_dwRolloverPMN0;
    pXSC1Data->dwValPMN1      = ReadPMURegister(PMUREG_PMN1);
    pXSC1Data->dwOverflowPMN1 = g_dwRolloverPMN1;

    ProfilerHitEx(pOEMData);
}


VOID CspPerfRegOverflowHandler(unsigned int ra)
{
    DWORD dwPMNC;             // PMU control register setting
    BOOL  fLoggedHit = FALSE; // Did we already send a hit to the kernel via ProfilerHitEx?

    // Determine which counter(s) (CCNT, PMN0, or PMN1) rolled over
    dwPMNC = ReadPMURegister(PMUREG_PMNC);

    if (dwPMNC & PMNC_BIT_CCNT_OVERFLOW) 
	{
        if (0 != g_PMUSettings.dwCCNTOverflowInterval)
    	{
	        // Send to kernel profiler
            if (!fLoggedHit) 
	    	{
                LogHit(ra);
                fLoggedHit = TRUE;
            }
            // Set the register up to overflow again
            WritePMURegister(PMUREG_CCNT, 0xFFFFFFFF - g_PMUSettings.dwCCNTOverflowInterval);
        } 
        else 
    	{
    		g_dwRolloverCCNT++;
        }
    }

    if (dwPMNC & PMNC_BIT_PMN0_OVERFLOW) 
	{
        if (0 != g_PMUSettings.dwPMN0OverflowInterval) 
    	{
            // Send to kernel profiler
            if (!fLoggedHit) 
        	{
                LogHit(ra);
                fLoggedHit = TRUE;
            }
            // Set the register up to overflow again
            WritePMURegister(PMUREG_PMN0, 0xFFFFFFFF - g_PMUSettings.dwPMN0OverflowInterval);
        } 
        else 
	   	{
            g_dwRolloverPMN0++;
        }
    }
    
    if (dwPMNC & PMNC_BIT_PMN1_OVERFLOW) 
	{
        if (0 != g_PMUSettings.dwPMN1OverflowInterval) 
    	{
            // Send to kernel profiler
            if (!fLoggedHit) 
        	{
                LogHit(ra);
                fLoggedHit = TRUE;
            }
            // Set the register up to overflow again
            WritePMURegister(PMUREG_PMN1, 0xFFFFFFFF - g_PMUSettings.dwPMN1OverflowInterval);
        } 
        else 
    	{
            g_dwRolloverPMN1++;
        }
    }


    // Xscale Dev. Manual lists bits 1 and 2 as being "read-unpredictable",
    // so we are manually setting these bits to "0" (no action)
    PMNC_BIT_P_DIS(dwPMNC);
    PMNC_BIT_C_DIS(dwPMNC);

    PMNC_BIT_RESERVED_CLEAR(dwPMNC);

    // To clear the bit, we write a 1 to the same bit that informs of overflow condition
    // since those bits are set (overflow indicators), we simply write back what we read (neat!)
    WritePMURegister(PMUREG_PMNC, dwPMNC);

}

#define WINCEMACRO 1

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -