event0.c 2.9 KB
#include <os.h>
#include <rmon.h>
#include "corefunc.h"

/*
 * event0
 *
 * Tests for:
 *	osSetEventMesg
 *
 * Assumed working:
 *	osGetIntMask
 *	osSetIntMask
 *	osCreateMesgQueue
 *	osRecvMesg
 *	osCreateThread
 *	osStartThread
 *	osInvalICache
 *
 * Description:
 *	Check that an OS_EVENT_CPU_BREAK event message is correctly sent when
 *		the processor executes a break instruction.
 */

static void		slave(void *);

static OSThread		slaveThread;
static char		slaveStack[STACKSIZE];

static OSMesgQueue	slaveMesgQueue;
static OSMesg		slaveMesgBuf[1];

static OSMesgQueue	breakMesgQueue;
static OSMesg		breakMesgBuf[1];

int
event0(void)
{
    OSIntMask savedMask, currentMask;
    OSMesg actualMesg, expectedMesg;
    unsigned int oldinst;
    int addFailures, numFailures = 0;
    
    savedMask = osSetIntMask(OS_IM_NONE);

    /*
     * Set master (current) thread priority to a higher priority than slave.
     */
    osSetThreadPri(NULL, 20);

    /*
     * Create a slave thread who will execute a break instruction.
     */
    osCreateMesgQueue(&slaveMesgQueue, slaveMesgBuf, 1);
    osCreateThread(&slaveThread, 100, slave, (void *)0,
		   slaveStack+STACKSIZE, 10);
    osStartThread(&slaveThread);

    /*
     * Create a message queue and associate it with a OS_EVENT_CPU_BREAK event.
     */
    osCreateMesgQueue(&breakMesgQueue, breakMesgBuf, 1);
    expectedMesg = (OSMesg)0xaaaaaaaa;
    osSetEventMesg(OS_EVENT_CPU_BREAK, &breakMesgQueue, expectedMesg);

    /*
     * Block for the message, which will allow the slave to run.
     */
    (void)osRecvMesg(&breakMesgQueue, &actualMesg, OS_MESG_BLOCK);
    if (expectedMesg != actualMesg) {
	osSyncPrintf("event0: expected message 0x%x, actual 0x%x\n",
		expectedMesg, actualMesg);
	numFailures++;
    }

    /*
     * Put a nop instruction in where the break was.
     */
    oldinst = *(unsigned int *)doBreak;

    *(unsigned int *)doBreak = 0; /* mips NOP */

    osWritebackDCache(doBreak, sizeof(unsigned int));
    osInvalICache(doBreak, sizeof(unsigned int));

    /*
     * Wait for the slave to complete and exit.
     */
    (void)osRecvMesg(&slaveMesgQueue, (OSMesg *)&addFailures, OS_MESG_BLOCK);
    numFailures += addFailures;

    /*
     * Restore the old instruction there for sanity's sake.
     */
    *(unsigned int *)doBreak = oldinst;

    osWritebackDCache(doBreak, sizeof(unsigned int));
    osInvalICache(doBreak, sizeof(unsigned int));

    /*
     * Restore original interrupt mask and check it once more.
     */
    currentMask = osSetIntMask(savedMask);
    if (currentMask != OS_IM_NONE) {
	osSyncPrintf("event0: expected interrupt mask 0x%x, actual 0x%x\n",
		OS_IM_NONE, currentMask);
	numFailures++;
    }
    return(numFailures);
}

static void
slave(void *arg)
{
    int numFailures = 0;

    /*
     * Execute a break instruction (later replaced by a nop) and return.
     */
    doBreak();

    osSendMesg(&slaveMesgQueue, (OSMesg)numFailures, OS_MESG_BLOCK);
}