📄 watchdog.c
字号:
/* peripheral.c - Memory veneer that implements RPS peripheral counter.
* Copyright (C) ARM Limited, 1998-1999. All rights reserved.
*
* RCS $Revision: 1.5.2.4.18.1 $
* Checkin $Date: 2002/12/16 15:32:50 $
* Revising $Author: gevans $
*/
#include <string.h> /* for memset */
#include "minperip.h"
#include "armul_cnf.h"
#include "armul_types.h" /* for ARMTime */
#include "armul_access.h"
#define ARMulCnf_KeyValue (tag_t)"KEYVALUE"
#define ARMulCnf_WatchPeriod (tag_t)"WATCHPERIOD"
#define ARMulCnf_IRQPeriod (tag_t)"IRQPERIOD"
#define ARMulCnf_IntNumber (tag_t)"INTNUMBER"
#define ARMulCnf_StartOnReset (tag_t)"STARTONRESET"
#define ARMulCnf_RunAfterBark (tag_t)"RUNAFTERBARK"
/* for acc_MREQ, acc_READ, acc_ACCOUNT */
#define acc_MREQ(a) (!( (a) & ACCESS_IDLE))
#define acc_READ(a) ACCESS_IS_READ(a)
#define acc_ACCOUNT(a) ACCESS_IS_REAL(a)
typedef ARMul_TimedCallBackProc armul_EventProc;
typedef struct {
unsigned long KeyValue; /* register 0x00 */
unsigned long WatchPeriod; /* register 0x04 */
unsigned long WatchPeriod2; /* register 0x08 */
ARMTime nextEventTime; /* In case we need to remove it!! */
void *nextEvent_killhandle;
armul_EventProc *fn; /* ptr to timeout function */
ARMTime nextIRQEventTime; /* In case we need to remove IRQ event */
void *nextIRQEvent_killhandle;
armul_EventProc *irqfn; /* ptr to irq timeout function */
int continueOnTimeout; /* Do we continue on timeout */
int inCountdown; /* Are we in normal count(0) or
* IRQ countdown (1) */
int runOnStartup; /* Do we start running on startup */
int interruptNumber; /* The interrupt signal number for this timer */
} peripheral;
BEGIN_STATE_DECL(Watchdog) /* was WatchdogState */
GenericAccessCallback **intcInterface;
ARMul_BusPeripAccessRegistration my_bpar;
peripheral peripheral1; /* peripheral 1 structure */
int warn; /* Warn users about invalid register accesses*/
int waits; /* Number of idle cycles before access */
int waitStates; /* stored number of wait states */
int accessState; /* Current access state */
END_STATE_DECL(Watchdog)
static void DO_INTCTRL(GenericAccessCallback **intc1, ARMword srcN,
ARMword v2)
{
if (intc1)
{
GenericAccessCallback *intc1a = *intc1;
if (intc1a)
{
intc1a->func(intc1a,srcN,&v2,0);
}
}
}
/* See note 4 */
/* ******************* */
/* Static declarations */
/* ******************* */
typedef unsigned ARMul_acc;
static void WatchdogIRQTimeout(void *handle);
static int RDI_info(void *handle, unsigned type, ARMword *arg1, ARMword *arg2);
static int RegisterAccess(WatchdogState *ts,ARMword addr,ARMword *word,
unsigned /* was ARMul_acc */ acc);
/*
* Return: 1 for failure, 0 for success
*/
static int iCheckIntcIf(WatchdogState *ts)
{
int endcondition;
if (ts->intcInterface == NULL)
{
/* No we don't have it installed yet.
By the time we have started running code the intc WILL have been
installed if it exists - so we can try again to install it
*/
ts->intcInterface = ARMulif_GetInterruptController(&ts->coredesc);
if (ts->intcInterface == NULL || *ts->intcInterface == NULL)
{
endcondition = RDIError_Reset;
}
}
return 0;
}
/* This function is to be called when the first timer times out.
Its job is to start the second timer - which does nasty shutdowns */
static void WatchdogTimeout(void *handle)
{
WatchdogState *ts = (WatchdogState*)handle;
peripheral *myWDog = &ts->peripheral1;
unsigned long delay;
delay = ts->peripheral1.WatchPeriod2;
/* Check that we have the intc interface installed */
if (iCheckIntcIf(ts))
{
return /*0*/;
}
Hostif_ConsolePrint(ts->hostif,
"Starting second timer and signalling IRQ\n");
/* Set that we are in countdown to doom */
myWDog->inCountdown = 1;
/* Start timer */
{ ARMTime Now = ARMulif_Time(&ts->coredesc);
ARMTime when = Now + delay;
ts->peripheral1.nextIRQEventTime = when;
ts->peripheral1.nextIRQEvent_killhandle =
ARMulif_ScheduleNewTimedCallback(
&ts->coredesc, WatchdogIRQTimeout, ts, when, 0);
}
/* Signal interrupt */
{ uint32 one = 1;
DO_INTCTRL(ts->intcInterface,myWDog->interruptNumber,one);
}
}
static void WatchdogIRQTimeout(void *handle)
{
WatchdogState *ts = (WatchdogState*)handle;
/* ARMul_State *state = (ARMul_State*)ts->state; */
peripheral *myWDog = &ts->peripheral1;
int endcondition;
Hostif_ConsolePrint(
ts->hostif, "Fatal System Error: Watchdog timed out at %lu!!\n",
(unsigned long)ARMulif_Time(&ts->coredesc));
Hostif_ConsolePrint(ts->hostif,"Halting System to allow debug.\n");
/* Make a call to halt execution - indicate that the target has stopped.*/
if ( myWDog->continueOnTimeout)
{
endcondition = RDIError_BreakpointReached;
ARMulif_StopExecution(&ts->coredesc, endcondition);
Hostif_PrettyPrint(ts->hostif,ts->config,
"Watchdog has halted emulation.\n");
Hostif_PrettyPrint(ts->hostif,ts->config,
"You may continue executing, but watchdog is halted now.\n");
}
else
{
endcondition = RDIError_Reset;
ARMulif_StopExecution(&ts->coredesc, endcondition);
Hostif_PrettyPrint(ts->hostif,ts->config,
"Watchdog has halted emulation and reset the target.\n");
}
}
/*
* ARMulator callbacks
*/
static int RDI_info(void *handle, unsigned type, ARMword *arg1, ARMword *arg2)
{
UNUSEDARG(handle);
UNUSEDARG(arg2);
UNUSEDARG(arg1);
UNUSEDARG(type);
return RDIError_UnimplementedMessage;
}
/*
Function Name: RegisterAccess
Parameters: WatchdogState *ts, -WatchdogState pointer
ARMword addr, - access address
ARMword *word, - pointer to data word
ARMul_acc acc - access type information
Return: int 1 = success, -2 = failed to decode address.
Description: Called from MemAccess. This meory model is called from the switch
because partial address decoding identified this as a memory that could
fully decode the address. This function continues the address decoding
trying to identify individual registers. For each decoded address
an action is carried out. For any addressed that aren't decoded -2 is
returned indicating failure to decode. In the case of failure to decode
then the access is passed on to the next level of memory by switch.
*/
static int RegisterAccess(WatchdogState *ts, ARMword addr, ARMword *word,
ARMul_acc acc)
{
/* ARMul_State *state = (ARMul_State*)ts->state; */
unsigned long maskedAddress = addr & 0x000000FF;
/* Is it a memory access? */
if (acc_MREQ(acc) )
{
/* Yes it is a memory access - now is it a read or a write? */
if ( acc_READ(acc) )
{
/* Read from registers */
switch ( maskedAddress)
{
case 0x00:
*word = ts->peripheral1.KeyValue;
break;
case 0x04:
*word = ts->peripheral1.WatchPeriod;
break;
case 0x08:
*word = ts->peripheral1.WatchPeriod2;
break;
case 0x0c: /* Reserved */
*word = 0;
if ( ts->warn == TRUE) {
Hostif_ConsolePrint(ts->hostif,
"Warning - accessed Reserved WDOG register address %08x\n",
addr);
}
break;
default:
return PERIP_NODECODE; /* Failed to decode address */
}
}
else
{
/* Write to registers */
switch ( maskedAddress)
{
/* >>>>>>>>>>>>Modify Me<<<<<<<<<<<<< */
/* See note 9 */
case 0x00:
/* Key update register written to */
if ( ts->peripheral1.KeyValue == *word )
{
/* The KEY value written matches the stored check value reset 'bark' */
unsigned long delay;
delay = ts->peripheral1.WatchPeriod;
if (ts->peripheral1.inCountdown == 1)
{
ts->peripheral1.inCountdown = 0;
/* Clear out the count to doom */
ARMulif_DescheduleTimedFunction(&ts->coredesc,
ts->peripheral1.nextIRQEvent_killhandle);
/* Clear the interrupt source */
/* Check that we have the intc interface installed */
if (iCheckIntcIf(ts))
{
return 0;
}
{ uint32 zero = 0;
DO_INTCTRL(ts->intcInterface,
ts->peripheral1.interruptNumber,zero);
}
/* Restart the main counter */
/* Record event time in case we need to remove it
* prematurely and schedule the event */
{ ARMTime Now = ARMulif_Time(&ts->coredesc);
ARMTime when = Now + delay;
ts->peripheral1.nextEventTime = when;
ts->peripheral1.nextEvent_killhandle =
ARMulif_ScheduleNewTimedCallback(
&ts->coredesc, WatchdogTimeout, ts, when, 0);
}
}
else
{
/* err - we're not in countdown to doom */
Hostif_ConsolePrint(ts->hostif,"Watchdog received KEYVALUE update, BUT NOT expecting it yet.\n");
Hostif_ConsolePrint(ts->hostif,"So, Watchdog is ignoring this write.\n");
}
}
break;
case 0x04:
if ( *word < 5000 )
{
/* Disallow excessively short watchdog periods */
ts->peripheral1.WatchPeriod = 5000;
if ( ts->warn == TRUE) {
Hostif_ConsolePrint(ts->hostif,"Warning - Attempt to write value < 5000 as watchdog timeout period\n");
Hostif_ConsolePrint(ts->hostif,"Defaulted to 5000 as timeout period.\n");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -