gdbmain.c 6.85 KB
/*---------------------------------------------------------------------*
 *  Copyright (C) 2004 BroadOn Communications Corp.
 *                 
 *  $RCSfile: gdbmain.c,v $ (derived from rmonmain.c)
 *  $Revision: 1.4 $
 *  $Date: 2004/02/18 02:59:00 $
 *---------------------------------------------------------------------*/

/* 
 * The GDB stub for the BBPlayer provides a mechanism for GDB to talk
 * to and debug programs on the BBPlayer.  The GDB stub is composed of
 * two threads: a main thread responsible to monitoring and handling
 * CPU break and fault, and a second thread responsible for communicating
 * with GDB using the GDB Remote Serial Protocol via RDB and USB.
 */

#include "ultragdb.h"
#include "osint.h"
#include "os_bb.h"

#ifndef _FINALROM

char  *gdb_module_name = "GDB Handler";

int gdbDebug = 0; /* GDB_DEBUG_SHOW_INFO | GDB_DEBUG_SHOW_ERROR */
int gdbShowAllThreadsFlag  = 1;
int gdbStopUserThreadsFlag = 1;
int gdbWaitToSendBreakFlag = 1;
int gdbReplaceEventMQs     = 0;

int __gdbActive = 0;		/* flag so others can know if gdb is alive */

static vu32 __gdbToDo;

/* GDB Main Message Queue */
static OSMesgQueue __gdbMQ;
static OSMesg gdbMsgs[8];

/* GDB IO Thread and stack */
static OSThread gdbIOThread;
static double gdbIOStack[0x800];

/* GDB Main Thread and stack */
static OSThread	gdbThread;
static u64      gdbStack[GDB_STACKSIZE/sizeof(u64)] __attribute__ ((aligned (8)));
static OSMesg gdbPiMsgs[8];
static OSMesgQueue gdbPiMQ;

extern __OSEventState __osEventStateTab[];

void gdbMain(void);

void gdbInit()
{
    /* If GDB is already running, simply return */
    if (__gdbActive) 
        return;

    /* Create and start GDB Main Thread */
    osCreateThread(&gdbThread, OS_TID_GDBMAIN, (VFUNPTR) gdbMain, (void *)0,
                   (void *)(gdbStack+GDB_STACKSIZE/sizeof(u64)),
                   (OSPri) OS_PRIORITY_GDB );
    osStartThread(&gdbThread);
}


/************************************************************************
Function: __gdbSetEventMesg
Args: OSEvent     e  - Event
      OSMesgQueue mq - Message Queue to associate with event
      OSMesg      m  - Message to associate with event
      int  replaceMQ - Whether to replace the existing message queue if 
                       there is already a message queue associated with
                       the event.
Purpose: This function associates a event with a message queue (like 
         osSetEventMesg) but also has an option of checking to see if the 
         event already has an message queue associated with it.
************************************************************************/
void __gdbSetEventMesg(OSEvent e, OSMesgQueue *mq, OSMesg m, int replaceMQ)
{
    u32 saveMask;

    /* Disable interrupts */
    saveMask = __osDisableInt();

    if (!replaceMQ)
    {
        /* We don't want to replace the message queue for this event if
           it has already be set */

        /* Make sure we have a valid event */
        if (e < OS_NUM_EVENTS) 
        {
            __OSEventState *es = &__osEventStateTab[e];

            /* If the event already has a message queue subscribed to it,
               let's just return */
            if (es->messageQueue) {
                /* Restore interrupts */
                __osRestoreInt(saveMask);
                return;
            }
        }
    }

    /* We do want to set the event */
    osSetEventMesg(e, mq, m);

    /* Restore interrupts */
    __osRestoreInt(saveMask);
}

/************************************************************************
Function: __gdbInitRest
Args: none
Type: void
Purpose: This function does the rest of the initialization for GDB
************************************************************************/
static void __gdbInitRest(void)
{
    /* Set up message queues */
    osCreateMesgQueue( &__gdbMQ, gdbMsgs, 8 );
    __gdbSetEventMesg( OS_EVENT_CPU_BREAK, &__gdbMQ, (OSMesg) MSG_BREAKPOINT, gdbReplaceEventMQs );
    __gdbSetEventMesg( OS_EVENT_SP_BREAK, &__gdbMQ, (OSMesg) MSG_SPBREAKPOINT, gdbReplaceEventMQs );
    __gdbSetEventMesg( OS_EVENT_FAULT, &__gdbMQ, (OSMesg) MSG_CPUFAULT, gdbReplaceEventMQs );
    __gdbSetEventMesg( OS_EVENT_THREADSTATUS, &__gdbMQ, (OSMesg) 0, gdbReplaceEventMQs );

    /* Create GDB IO Thread */
    osCreateThread( &gdbIOThread, OS_TID_GDBIO, (VFUNPTR) __gdbIOhandler, 0, 
                    &gdbIOStack[0x800], (OSPri) 255 );

    /*
      Note that Pi manager must start before IO manager, since the
      latter requests the former's command queue address at startup.
      It should be legal to start one, even if one is already 
      running (will just fail).
    */

    osCreatePiManager( (OSPri) OS_PRIORITY_PIMGR, &gdbPiMQ, gdbPiMsgs, 8 );
    osStartThread( &gdbIOThread );
}

/************************************************************************
 Function: gdbMain
 Args: none
 Type: void
 Purpose: This is the main loop of the gdb debugger. 
          It waits for and handles CPU breaks and faults.
************************************************************************/
void gdbMain( void )
{
    /* Check to see if a GDB thread is already active - if so just return */
    if (__gdbActive) return;

    __gdbActive = 1;
    __gdbInitRest();

    /*
     * Loop forever acquiring commands
     */
    __gdbToDo = 0;	
    while (1)
    {
        OSMesg work;
        
        if (gdbDebug & GDB_DEBUG_SHOW_INFO)
            GDB_PRINTF("%s: Waiting for break.\n", gdb_module_name);

        osRecvMesg( &__gdbMQ, &work, OS_MESG_BLOCK );
        __gdbToDo |= (u32) work;
        
        if ( __gdbToDo & MSG_BREAKPOINT )
        {
            if (gdbDebug & GDB_DEBUG_SHOW_INFO)
                GDB_PRINTF("%s: CPU Breakpoint\n", gdb_module_name);
            __gdbToDo &= ~MSG_BREAKPOINT;
            __gdbHitBreak();
        }
        
        if ( __gdbToDo & MSG_SPBREAKPOINT )
        {
            if (gdbDebug & GDB_DEBUG_SHOW_INFO)
                GDB_PRINTF("%s: RCP Breakpoint\n", gdb_module_name);
            __gdbToDo &= ~MSG_SPBREAKPOINT;
            /* NOT supported */
/*            __rmonHitSpBreak(); */
        }
        
        if ( __gdbToDo & MSG_CPUFAULT )
        {
            if (gdbDebug & GDB_DEBUG_SHOW_INFO)
                GDB_PRINTF("%s: CPU Fault\n", gdb_module_name);
            __gdbToDo &= ~MSG_CPUFAULT;
            __gdbHitCpuFault();
        }
        
        if ( __gdbToDo & MSG_THREADCREATE )
        {
            if (gdbDebug & GDB_DEBUG_SHOW_INFO)
                GDB_PRINTF("%s: Thread %d created\n", 
                           gdb_module_name, __gdbToDo >> 8);
            __gdbToDo &= ~(MSG_THREADCREATE | 0xffffff00);
        }
        
        if ( __gdbToDo & MSG_THREADDESTROY )
        {
            if (gdbDebug & GDB_DEBUG_SHOW_INFO)
                GDB_PRINTF("%s: Thread %d destroyed\n", 
                           gdb_module_name, __gdbToDo >> 8);
            __gdbToDo &= ~(MSG_THREADDESTROY | 0xffffff00);
        }
    }
}

#endif /* #ifndef _FINALROM */