/*static char *SCCSID = "@(#) perfcall.c 1.0 96/01/11";*/
#define SCCSID "@(#) perfcall.c 1.0 96/01/11"

#define INCL_TYPES                      // for basedef.h typedefs
#define INCL_ERROR_H                    // for error.h defines
#define INCL_ERROR2_H                   // for error2.h defines

#include <basemac.h>
#include <basedef.h>
#define FNO_NUM FNO_PERFCALL_C
#include <fnotask.h>
#include <osmac.h>
#include <ostypes.h>
#include <infoseg.h>
#include <osconst.h>
#include <bseerr.h>
#include <dossymc.h>
#include <seldesc.h>
#include <sigdef.h>
#include <except.h>
#include <mi.h>
#include <pgexport.h>
#include <vmexport.h>
#include <tkexport.h>
#include <sched.h>
#include <proc.h>
#include <sem.h>
#include <screen.h>
#include <curdir.h>
#include <dirent.h>
#include <find.h>
#include <tkptda.h>
#include <ldrxport.h>
#include <selxport.h>
#include <kmode.h>
#include <bsetib.h>
#include <tklocal.h>
#include <except32.h>
#include <sigxport.h>
#include <exmg.h>
#ifdef SMP
#include <..\memory\pglocal.h>
#include <tkmp.h>
#include <mplock.h>
#endif

#include <error.h>
#include <vmowner.h>
#include <perfcall.h>

#ifdef SMP
#include <tbheader.h>                    /* 153147 */
#endif


int cdecl InitPerfBuffer(unsigned long size);
int cdecl FreePerfBuffer();
int cdecl GetPerfBuffer(char * user_buffer, unsigned long size);
int cdecl GetPerfBufferHeaders(char * user_buffer, unsigned long size);
int cdecl InfoPerfBuffer(unsigned long * totalsize, unsigned long * num_proc);
int cdecl PerfDoSSTime(PULONG pulNumProcs);
int cdecl PerfGetSSTime(PULONG pulHigh, PULONG pulLow, PULONG pulProcNo);
extern void cdecl StartCPURating(void);				     	                        // 153280,153289
int cdecl PerfDoCPURating(PULONG pulNumProcs);				// F153289
int cdecl PerfGetCPURating(PULONG pulRate, PULONG pulProcNo);		// F153289
int cdecl SoftTraceOn(ULONG ulSize);
int cdecl SoftTraceOff(void);
int cdecl SoftTraceAllocBuffer(ULONG ulSize);
int cdecl SoftTraceFreeBuffer(void);
int cdecl SoftTraceGetBuffer(char * pBuffer, ULONG ulBufferSize, char * pszFileName);
int cdecl SoftTraceResetBuffer(void);
int cdecl SoftTraceQueryInfo(PULONG pulActive, PULONG pulSize, PULONG pulNumProcs);
int cdecl SoftTraceUserLog(ULONG ulMajorCode, ULONG  ulMinorCode, ULONG ulParm);
int cdecl SoftTracehook( ULONG ulType, ULONG  ulMajorCode, ULONG  ulMinorCode, ...);
int cdecl PerfKIEnable(void);                           /* F151122 */
int cdecl PerfKIDisable(void);                          /* F151122 */
int cdecl PerfKIRdCnt(char* cntbuf);                    /* F151122 */
int _stdcall a2n_getall_mte( char *buffer, unsigned long buf_size, unsigned long caller_type); /* 153147 */


int cdecl VR32IPerfSysCall(THUNKSEF sef, ULONG ulCommand, ULONG ulParm1, ULONG ulParm2, ULONG ulParm3);



#ifdef SMP
#else
struct PSAVAR
{
  unsigned long MP_PERF_DATA;
  unsigned long MP_PERF_SAVE;
  unsigned long MP_PERF_SSTIME_HIGH;
  unsigned long MP_PERF_SSTIME_LOW;
  unsigned long MP_PERF_CPU_RATE;
} PSAVARS;
struct PSAVAR *pPSA = &PSAVARS;
long cProcessors = 1;
ULONG curProcNum = 1;
#endif




/***    VR32IPerfSysCall - Worker function for DosPerfSysCall
 *
 *      ENTRY   ulCommand - command of function requested
 *              ulParm1   - command specific parameter
 *              ulParm2   - command specific parameter
 *              ulParm3   - command specific parameter
 *
 *      EXIT    return code of specific command
 */

int cdecl VR32IPerfSysCall( THUNKSEF sef, ULONG ulCommand, ULONG ulParm1, ULONG ulParm2, ULONG ulParm3)
{
  int rc = NO_ERROR;

  switch(ulCommand) {





     /*
        GENERIC Function(s)
     */

     case CMD_PERF_ALLOC:
        rc = InitPerfBuffer(
             ulParm1);             // Buffer size
        break;

     case CMD_PERF_FREE:
        rc = FreePerfBuffer();
        break;

     case CMD_PERF_GET:
        rc = GetPerfBuffer(
             (PCHAR) ulParm1,      // Pointer to user's buffer
             ulParm2);             // Buffer size (total)
        break;

     case CMD_PERF_GETHEADERS:
        rc = GetPerfBufferHeaders(
             (PCHAR) ulParm1,      // Pointer to user's buffer
             ulParm2);             // Buffer size (total)
        break;

     case CMD_PERF_INFO:
        rc = InfoPerfBuffer(
              (PULONG) ulParm1,    // Pointer to size
              (PULONG) ulParm2);   // Pointer to num. procs
        break;

#ifdef SMP

     case CMD_PERF_DOSSTIME:
        rc = PerfDoSSTime(
              (PULONG)ulParm1);
        break;

     case CMD_PERF_GETSSTIME:
        rc = PerfGetSSTime(
              (PULONG)ulParm1,     // pointer to high TS
              (PULONG)ulParm2,     // Pointer to low TS
              (PULONG)ulParm3);    // Pointer to Proc num
     break;

     case CMD_PERF_DOCPURATING:	  // F153289
        rc = PerfDoCPURating(		  // F153289
              (PULONG)ulParm1);    // F153289
        break;							  // F153289
                                   // F153289
     case CMD_PERF_GETCPURATING:	  // F153289
        rc = PerfGetCPURating(	  // F153289
              (PULONG)ulParm1,     // pointer to CPU rate (Hz)  // F153289
              (PULONG)ulParm2);    // Pointer to Proc num		  // F153289
     break;								  // F153289
                                   // F153289

     /*
        ICTRACE Function(s)
     */


#ifdef ICTRACE                                         /* 148959 */
     case CMD_ICTRACE_ON:                              /* 148959 */
        rc = ictrace_on(ulParm1, ulParm2, ulParm3);    /* 148959 */
        break;                                         /* 148959 */
                                                       /* 148959 */
     case CMD_ICTRACE_OFF:                             /* 148959 */
        rc = ictrace_off();                            /* 148959 */
        break;                                         /* 148959 */
                                                       /* 148959 */
     case CMD_ICTRACE_RESET:                           /* 148959 */
        rc = ictrace_reset();                          /* 148959 */
        break;                                         /* 148959 */
#endif                                                 /* 148959 */

     /*
        SOFTTRACE Function(s)
     */

     case CMD_SOFTTRACE_ON:
        rc = SoftTraceOn(
             (ULONG)ulParm1);      // Buffer size
        break;

     case CMD_SOFTTRACE_OFF:
        rc = SoftTraceOff();
        break;

     case CMD_SOFTTRACE_RESET:
        rc = SoftTraceResetBuffer();
        break;

     case CMD_SOFTTRACE_GET:
        rc = SoftTraceGetBuffer(
             (PBYTE) ulParm1,      // Pointer to user's buffer
             (ULONG) ulParm2,      // Buffer size
             (PSZ) ulParm3);       // Pointer to Log file name
        break;

     case CMD_SOFTTRACE_QUERY:
        rc = SoftTraceQueryInfo(
               (PULONG)ulParm1,    // Pointer to ulactive
               (PULONG)ulParm2,    // Pointer to ulSize
               (PULONG)ulParm3);   // Pointer to ulNumProc
        break;

     case CMD_SOFTTRACE_ALLOC:
        rc = SoftTraceAllocBuffer(
             (ULONG)ulParm1);      // buffer's size
        break;

     case CMD_SOFTTRACE_FREE:
        rc = SoftTraceFreeBuffer();
        break;

     case CMD_SOFTTRACE_LOG:
        rc = SoftTraceUserLog(
               ulParm1,            // Major code
               ulParm2,            // Minor code
               ulParm3);           // 1 32-bit output
        break;

     /*                                                                                  153147
        GETMTE Function                                                                  153147
     */                                                                               /* 153147 */

     case CMD_PERFGMTE:                                                               /* 153147 */
        rc = a2n_getall_mte( (char *)ulParm1, ulParm2, A2N_BUFFER_USER );             /* 153147 */
        break;                                                                        /* 153147 */

     /*
        THISBIG Function(s)
     */

     case CMD_THISBIG_ON:
        rc = ERROR_INVALID_FUNCTION;
        break;

     case CMD_THISBIG_OFF:
        rc = ERROR_INVALID_FUNCTION;
        break;

     case CMD_THISBIG_RESET:
        rc = ERROR_INVALID_FUNCTION;
        break;

     case CMD_THISBIG_RESUME:
        rc = ERROR_INVALID_FUNCTION;
        break;

     case CMD_THISBIG_SUM:
        rc = ERROR_INVALID_FUNCTION;
        break;
#endif
                                                                /* F151122 */
     /*                                                            F151122
        Kernel Idleness Measurement Function(s)                    F151122
     */                                                         /* F151122 */
                                                                /* F151122 */
     case CMD_KI_ENABLE:                                        /* F151122 */
        rc = PerfKIEnable();                                    /* F151122 */
        break;                                                  /* F151122 */
                                                                /* F151122 */
     case CMD_KI_DISABLE:                                       /* F151122 */
        rc = PerfKIDisable();                                   /* F151122 */
        break;                                                  /* F151122 */
                                                                /* F151122 */
     case CMD_KI_RDCNT:                                         /* F151122 */
        rc = PerfKIRdCnt(                                       /* F151122 */
               (PULONG) ulParm1);    // user buffer             /* F151122 */
        break;                                                  /* F151122 */


     default:
        rc = ERROR_INVALID_FUNCTION;
        break;

  } /* end case */

  return(rc);
  sef;
}



/***    InitPerfBuffer - Allocate DosPerfSysCall buffer
 *
 *      ENTRY   size - size of buffer/processor requested
 *
 *      EXIT    return code
 */

int cdecl InitPerfBuffer(unsigned long size)
{
    int rc = NO_ERROR, ix, jx;
    struct vmac_s ac[16];
    struct _PerfBuf *PerfBufPtr;                                     /* 153289 */
#ifdef SMP
    struct pcb_s *pPCB;
    PSAVARS *pPSA;
#endif



    /* Only allocate if memory is not already allocated */

#ifdef SMP
    pPSA = MPGetPSAAddr(0);
#endif

    if (pPSA->MP_PERF_DATA == 0) {

       if (size < 0x1000) size = 0x300000; /* 3 Meg */

       size += PERFSIZE;

       for (ix=0; ix < cProcessors; ix++){
          rc = VMAllocMem(size, size,
          VMAC_ARENASYS|VMAC_LOCANY|PG_RESIDENT|PG_W,
          HOBNULL, VMMINOWNER, 0, 0, 0, SSToDS(&ac[ix]));

          if (rc != NO_ERROR){
             /* need to free any allocated buffers */
             for (jx=0; jx < ix; jx++){
                      VMFreeMem(ac[jx].ac_va, HOBNULL, 0);
#ifdef SMP
                      pPSA = MPGetPSAAddr(jx);                                      /* kav extra */
#endif
                      pPSA->MP_PERF_DATA = 0;                                       /* kav extra */
             }
             return(rc);
          }

#ifdef SMP
          pPSA = MPGetPSAAddr(ix);
#endif
          pPSA->MP_PERF_DATA = (unsigned long) (ac[ix].ac_va);

          memset(pPSA->MP_PERF_DATA, 0, size);

          PerfBufPtr = (struct _PerfBuf *) pPSA->MP_PERF_DATA;                      /* 153289 */

          if (ix != 0){
              PerfBufPtr->buffer_next = (unsigned long) (ac[ix-1].ac_va);
          }

          PerfBufPtr->buffer_hts_start = pPSA->MP_PERF_SSTIME_HIGH;
          PerfBufPtr->buffer_lts_start = pPSA->MP_PERF_SSTIME_LOW;
          PerfBufPtr->buffer_size = size;
          PerfBufPtr->buffer_end = (unsigned long) PerfBufPtr + size;
          PerfBufPtr->buffer_cpunum = (unsigned short) ix;


          PerfBufPtr->buffer_start = (unsigned long) PerfBufPtr + PERFSIZE;
          PerfBufPtr->buffer_current = (unsigned long) PerfBufPtr + PERFSIZE;
#ifdef SMP
          pPCB = (struct pcb_s *)pPSA->pPCBCur;
          PerfBufPtr->buffer_gdtbase = pPCB->PCBGDTLaddr;
#else
          PerfBufPtr->buffer_gdtbase = SELGDTLaddr;
#endif
       }
       PerfBufPtr = (struct _PerfBuf *) (ac[0].ac_va);   /* back to 1st buffer */      /* 153289 */
       PerfBufPtr->buffer_next = (unsigned long) (ac[cProcessors-1].ac_va); /* first points to last*/


#ifdef SMP
       if (pPSA->MP_PERF_CPU_RATE == 0) {       // F153289
          StartCPURating();		               // F153289
       }                                        // F153289
#endif

    }

    return(rc);

}

/***    FreePerfBuffer - Free DosPerfSysCall buffer
 *
 *      ENTRY   none
 *
 *      EXIT    return code
 */

int cdecl FreePerfBuffer()
{
       int rc = NO_ERROR, ix;
#ifdef SMP
       PSAVARS *pPSA;
#endif

    for (ix=0; ix < cProcessors; ix++){
#ifdef SMP
             pPSA = MPGetPSAAddr(ix);
#endif
             rc = VMFreeMem(pPSA->MP_PERF_DATA, HOBNULL, 0);
             pPSA->MP_PERF_DATA = 0;
    }

    return(rc);
}

/***    GetPerfBuffer - Get copy of DosPerfSysCall buffer(s)
 *
 *      ENTRY   user_buffer - pointer to user allocate memory
 *                        for buffer copy
 *              size - size of user allocated buffer
 *
 *      EXIT    *user_buffer copy of buffer
 *              return code - size of buffer copied
 */

int cdecl GetPerfBuffer(char * user_buffer, unsigned long size)
{
    int rc = NO_ERROR, ix;
    unsigned long buffer_size;
#ifdef SMP
    PSAVARS *pPSA;
#endif
    struct _PerfBuf *PerfBufPtr;             /* 153289 */

#ifdef SMP
    pPSA = MPGetPSAAddr(0);
#endif
    PerfBufPtr = (struct _PerfBuf *) pPSA->MP_PERF_DATA;  /* 153289 */

    if (PerfBufPtr == 0){
        return(0);
    }

    buffer_size = PerfBufPtr->buffer_size;

    if (size < (buffer_size * cProcessors)){
       return (ERROR_INVALID_PARAMETER);
    }

    for (ix=0; ix < cProcessors; ix++){
#ifdef SMP
       pPSA = MPGetPSAAddr(ix);
#endif

       PerfBufPtr = (struct _PerfBuf *) pPSA->MP_PERF_DATA;   /* 153289 */
       PerfBufPtr->buffer_hts_end = pPSA->MP_PERF_SSTIME_HIGH;
       PerfBufPtr->buffer_lts_end = pPSA->MP_PERF_SSTIME_LOW;
       PerfBufPtr->ulCPURating = pPSA->MP_PERF_CPU_RATE;      // 153289

       rc = TKSuBuff ((char *)user_buffer, (char *)pPSA->MP_PERF_DATA, (int)buffer_size, (int)TK_UM_FATAL);
       if (rc != NO_ERROR){
          return(rc);
       }

       user_buffer += buffer_size;
    }

    return(buffer_size * cProcessors);
}


/***    GetPerfBufferHeaders - Get copy of DosPerfSysCall buffer(s) headers
 *
 *      ENTRY   user_buffer - pointer to user allocate memory
 *                        for buffer copy
 *              size - size of user allocated buffer
 *
 *      EXIT    *user_buffer copy of buffer headers
 *              return code - size of buffer copied
 */

int cdecl GetPerfBufferHeaders(char * user_buffer, unsigned long size)
{
    int rc = NO_ERROR, ix;
#ifdef SMP
    PSAVARS *pPSA;
#endif
    int sizecopied = 0;
    struct _PerfBuf *PerfBufPtr;    /* 153289 */

#ifdef SMP
    pPSA = MPGetPSAAddr(0);
#endif
    PerfBufPtr = (struct _PerfBuf *) pPSA->MP_PERF_DATA;   /* 153289 */

    if (PerfBufPtr == 0){
        return(0);
    }

    if (size < (ULONG)(PERFSIZE * cProcessors)){                /* 153289 */
       return (ERROR_INVALID_PARAMETER);
    }

    for (ix=0; ix < cProcessors; ix++){
#ifdef SMP
       pPSA = MPGetPSAAddr(ix);
#endif

       PerfBufPtr = (struct _PerfBuf *) pPSA->MP_PERF_DATA;     /* 153289 */
       PerfBufPtr->buffer_hts_end = pPSA->MP_PERF_SSTIME_HIGH;
       PerfBufPtr->buffer_lts_end = pPSA->MP_PERF_SSTIME_LOW;
       PerfBufPtr->ulCPURating = pPSA->MP_PERF_CPU_RATE;      // 153289

       rc = TKSuBuff ((char *)user_buffer, (char *)pPSA->MP_PERF_DATA, (int)PERFSIZE, (int)TK_UM_FATAL);
       if (rc != NO_ERROR){
          return(rc);
       }

       sizecopied  += PERFSIZE;
       user_buffer += PERFSIZE;
    }

    return(sizecopied);
}

/***    InfoPerfBuffer - Get information about DosPerfSysCall buffer(s)
 *
 *      ENTRY   totalsize - pointer to buffer size used by DosPerfSysCall
 *              num_proc - pointer to number of processors
 *
 *      EXIT    *totalsize - buffer size used by DosPerfSysCall
 *              *num_proc - number of processors
 *              return code
 */

int cdecl InfoPerfBuffer(unsigned long * totalsize, unsigned long * num_proc)
{
    int rc = NO_ERROR;
    unsigned long size;
#ifdef SMP
    PSAVARS *pPSA;
#endif
    struct _PerfBuf *PerfBufPtr;    /* 153289 */

#ifdef SMP
    pPSA = MPGetPSAAddr(0);
#endif
    PerfBufPtr = (struct _PerfBuf *) pPSA->MP_PERF_DATA;    /* 153289 */

    if (PerfBufPtr == 0){
        size = 0;
    }
    else{
        size = PerfBufPtr->buffer_size * cProcessors;
    }

    rc = TKSuDWord(size, totalsize);

    if (rc != NO_ERROR){
       return(rc);
    }

    rc = TKSuDWord(cProcessors, num_proc);

    return(rc);
}

