log.c 4.91 KB
/*====================================================================
 * log.c
 *
 * Copyright 1995, Silicon Graphics, Inc.
 * All Rights Reserved.
 *
 * This is UNPUBLISHED PROPRIETARY SOURCE CODE of Silicon Graphics,
 * Inc.; the contents of this file may not be disclosed to third
 * parties, copied or duplicated in any form, in whole or in part,
 * without the prior written permission of Silicon Graphics, Inc.
 *
 * RESTRICTED RIGHTS LEGEND:
 * Use, duplication or disclosure by the Government is subject to
 * restrictions as set forth in subdivision (c)(1)(ii) of the Rights
 * in Technical Data and Computer Software clause at DFARS
 * 252.227-7013, and/or in similar or successor clauses in the FAR,
 * DOD or NASA FAR Supplement. Unpublished - rights reserved under the
 * Copyright Laws of the United States.
 *====================================================================*/

#include <stdarg.h>
#include <os.h>
#include <os_internal.h>
#include <ultralog.h>
#include <ultraerror.h>
#include <rdb.h>

#ifndef _FINALROM   /* Logging should never be included in final rom */

#ifndef MIN
#define MIN(a,b) (((a)<(b))?(a):(b))
#endif

static u32  __osLogOKtoWrite = 1;
static u32  __osLogInitialized = 0;

static OSMesgQueue  __osLogDoneMsgQ;
static OSMesg       __osLogMsgBuf;

void __osLogWrite(OSLog *, s16, s16, va_list);

void osCreateLog(OSLog *log, u32 *base, s32 byteLen) 
{
    log->magic  = OS_LOG_MAGIC;
    log->base   = base;
    log->len    = byteLen;

#ifdef _ULTRA64
    log->startCount  = osGetCount();
#else
    log->startCount  = 0;
#endif
    log->writeOffset = 0;
}

void osLogEvent(OSLog *log, s16 code, s16 numArgs, ...)
{
    va_list     argPtr;

    if (numArgs > OS_LOG_MAX_ARGS)
        return;
    
    va_start(argPtr, numArgs);

    __osLogWrite(log, code, numArgs, argPtr);

    va_end(argPtr);
}

/* 
 * Indy application must have opened /dev/u64_logging for reading before this is
 * called, or else data will be dropped, and osFlush will lock waiting for a
 * response that data was received
 */
void osFlushLog(OSLog *log)
{
    u32         mask;
    u32         sent;
    u32         count,subcount;
    u8          *base;
    u8          dCount[3];


    if(!__osLogInitialized)
    {
	osCreateMesgQueue(&__osLogDoneMsgQ, &__osLogMsgBuf, 1);
	osSetEventMesg(OS_EVENT_RDB_LOG_DONE, &__osLogDoneMsgQ, NULL);
	__osLogInitialized = 1;
    }

    /*
     * Disable interrupts, to protect access to log->writeOffset, and
     * __osLogOKtoWrite. 
     */
    mask = __osDisableInt();
    __osLogOKtoWrite = 0;                   /* turn off writing to log */
    base = (u8*)log->base;                  /* get the base */
    count = log->writeOffset * sizeof(u32); /* calc number of bytes to send */
    __osRestoreInt(mask);                  

    /*
     * Need to have interrupts enabled for loop with osRdbSend
     * to work. But must be sure that no new events get written 
     * to the buffer.
     */

    while(count)  /* break transfer into blocks */
    {
	/* send a signal telling how many bytes before, expecting an ack */
	subcount = MIN(count,RDB_LOG_MAX_BLOCK_SIZE);
	dCount[0] = (subcount & 0x00FF0000) >> 16;
	dCount[1] = (subcount & 0x0000FF00) >> 8;
	dCount[2] = subcount & 0x000000FF;
	
	sent = 0;
	while(sent < 3)
	    sent += __osRdbSend(&dCount[sent],3-sent,RDB_TYPE_GtoH_LOG_CT);

	/* now send the data */
	sent = 0;
	while(sent < subcount)
	    sent += __osRdbSend(&base[sent], subcount-sent, RDB_TYPE_GtoH_LOG);

	/* update variables, and block for signal from kernal saying read complete */
	count -= subcount;
	base += subcount;
	osRecvMesg(&__osLogDoneMsgQ,NULL,OS_MESG_BLOCK);
    }
    
    mask = __osDisableInt();
    log->writeOffset = 0;    /* reset counter */
    __osLogOKtoWrite = 1;    /* turn on writing to log */
    __osRestoreInt(mask);

}

void __osLogWrite(OSLog *log, s16 code, s16 numArgs, va_list argPtr)
{
    int		i;
    u32		saveEnable;
    u32		buf[OS_LOG_MAX_ARGS + (sizeof(OSLogItem)/sizeof(u32))];
    u32		*bufp = buf;
    OSLogItem	*hdr  = (OSLogItem *)buf;
    u32		*args = &buf[sizeof(OSLogItem)/sizeof(u32)];
    u32		*dest;
    int		numLongs = numArgs + (sizeof(OSLogItem)/sizeof(u32));

    saveEnable = __osDisableInt(); /* disable interrupts to protect variables */
    
    hdr->magic = log->magic;
#ifdef _ULTRA64
    hdr->timeStamp = osGetCount() - log->startCount;
#else
    hdr->timeStamp = 0 - log->startCount;
#endif
    hdr->argCount = numArgs;
    hdr->eventID = code;

    for (i = 0; i < numArgs; i++)
	*args++ = va_arg(argPtr, u32);
	
    if(__osLogOKtoWrite)  /* if in the process of a flush, don't copy into buf */
    {
	if ((log->writeOffset + numLongs) < (log->len/sizeof(u32))) 
	{
	    dest = log->base + log->writeOffset;
	    
	    for (i = 0; i < numLongs; i++) 
		*dest++ = *bufp++;

	    log->writeOffset += numLongs;
	}
	else  /* have used up all buffer, turn off log until flush */
	    __osLogOKtoWrite = 0;
	    
    }
    __osRestoreInt(saveEnable);
}


#endif  /* ifndef _FINALROM */