一般要在uefi中使用watchdog,会按照如下格式。
gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
XXXXXXXXXXXX
gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
即首先调用gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);来是指5分钟到期的watchdog,如果事情在5分钟之内做完,就调用
gBS->SetWatchdogTimer 来关掉watchdog
gBS->SetWatchdogTimer 其实指向的是WatchdogSetTimerPeriod这个函数.
EFI_STATUS
EFIAPI
WatchdogSetTimerPeriod (
IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
IN UINT64 TimerPeriod // In 100ns units
)
{
UINTN SystemCount;
EFI_STATUS Status;
if (TimerPeriod == 0) {
mNumTimerTicks = 0;
return WatchdogDisable ();
}
// Work out how many timer ticks will equate to TimerPeriod
mNumTimerTicks = (mTimerFrequencyHz * TimerPeriod) / TIME_UNITS_PER_SECOND;
//
// If the number of required ticks is greater than the max number the
// watchdog's offset register (WOR) can hold, we need to manually compute and
// set the compare register (WCV)
//
if (mNumTimerTicks > MAX_UINT32) {
//
// We need to enable the watchdog *before* writing to the compare register,
// because enabling the watchdog causes an "explicit refresh", which
// clobbers the compare register (WCV). In order to make sure this doesn't
// trigger an interrupt, set the offset to max.
//
Status = WatchdogWriteOffsetRegister (MAX_UINT32);
if (EFI_ERROR (Status)) {
return Status;
}
WatchdogEnable ();
SystemCount = ArmGenericTimerGetSystemCount ();
Status = WatchdogWriteCompareRegister (SystemCount + mNumTimerTicks);
} else {
Status = WatchdogWriteOffsetRegister ((UINT32)mNumTimerTicks);
WatchdogEnable ();
}
return Status;
}
可以看到,如果TimerPeriod==0,就调用WatchdogDisable 关掉watchdog.正常情况下设定的watchdog到期时间不会超过MAX_UINT32。因此首先调用将TimerPeriod 转成ticks
mNumTimerTicks = (mTimerFrequencyHz * TimerPeriod) / TIME_UNITS_PER_SECOND;
然后写寄存器
Status = WatchdogWriteOffsetRegister ((UINT32)mNumTimerTicks);
最后enable watchdog
WatchdogEnable ();
在dxemain.c 中
(EFI_SET_WATCHDOG_TIMER) CoreSetWatchdogTimer, // SetWatchdogTimer
会注册SetWatchdogTimer的回调函数为CoreSetWatchdogTimer
EFI_STATUS
EFIAPI
CoreSetWatchdogTimer (
IN UINTN Timeout,
IN UINT64 WatchdogCode,
IN UINTN DataSize,
IN CHAR16 *WatchdogData OPTIONAL
)
{
EFI_STATUS Status;
//
// Check our architectural protocol
//
if (gWatchdogTimer == NULL) {
return EFI_NOT_AVAILABLE_YET;
}
//
// Attempt to set the timeout
//
Status = gWatchdogTimer->SetTimerPeriod (gWatchdogTimer, MultU64x32 (Timeout, WATCHDOG_TIMER_CALIBRATE_PER_SECOND));
//
// Check for errors
//
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
所以后面调用gBS->SetWatchdogTimer 就相当于调用CoreSetWatchdogTimer。而在CoreSetWatchdogTimer 中是直接调用gWatchdogTimer->SetTimerPeriod
由于watchdog是在dxemain.c 中才注册的,也就是说只有dxe之后包括bds才可以使用watchdog函数.
gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
XXXXXXXXXXXX
gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
即首先调用gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);来是指5分钟到期的watchdog,如果事情在5分钟之内做完,就调用
gBS->SetWatchdogTimer 来关掉watchdog
gBS->SetWatchdogTimer 其实指向的是WatchdogSetTimerPeriod这个函数.
EFI_STATUS
EFIAPI
WatchdogSetTimerPeriod (
IN CONST EFI_WATCHDOG_TIMER_ARCH_PROTOCOL *This,
IN UINT64 TimerPeriod // In 100ns units
)
{
UINTN SystemCount;
EFI_STATUS Status;
if (TimerPeriod == 0) {
mNumTimerTicks = 0;
return WatchdogDisable ();
}
// Work out how many timer ticks will equate to TimerPeriod
mNumTimerTicks = (mTimerFrequencyHz * TimerPeriod) / TIME_UNITS_PER_SECOND;
//
// If the number of required ticks is greater than the max number the
// watchdog's offset register (WOR) can hold, we need to manually compute and
// set the compare register (WCV)
//
if (mNumTimerTicks > MAX_UINT32) {
//
// We need to enable the watchdog *before* writing to the compare register,
// because enabling the watchdog causes an "explicit refresh", which
// clobbers the compare register (WCV). In order to make sure this doesn't
// trigger an interrupt, set the offset to max.
//
Status = WatchdogWriteOffsetRegister (MAX_UINT32);
if (EFI_ERROR (Status)) {
return Status;
}
WatchdogEnable ();
SystemCount = ArmGenericTimerGetSystemCount ();
Status = WatchdogWriteCompareRegister (SystemCount + mNumTimerTicks);
} else {
Status = WatchdogWriteOffsetRegister ((UINT32)mNumTimerTicks);
WatchdogEnable ();
}
return Status;
}
可以看到,如果TimerPeriod==0,就调用WatchdogDisable 关掉watchdog.正常情况下设定的watchdog到期时间不会超过MAX_UINT32。因此首先调用将TimerPeriod 转成ticks
mNumTimerTicks = (mTimerFrequencyHz * TimerPeriod) / TIME_UNITS_PER_SECOND;
然后写寄存器
Status = WatchdogWriteOffsetRegister ((UINT32)mNumTimerTicks);
最后enable watchdog
WatchdogEnable ();
在dxemain.c 中
(EFI_SET_WATCHDOG_TIMER) CoreSetWatchdogTimer, // SetWatchdogTimer
会注册SetWatchdogTimer的回调函数为CoreSetWatchdogTimer
EFI_STATUS
EFIAPI
CoreSetWatchdogTimer (
IN UINTN Timeout,
IN UINT64 WatchdogCode,
IN UINTN DataSize,
IN CHAR16 *WatchdogData OPTIONAL
)
{
EFI_STATUS Status;
//
// Check our architectural protocol
//
if (gWatchdogTimer == NULL) {
return EFI_NOT_AVAILABLE_YET;
}
//
// Attempt to set the timeout
//
Status = gWatchdogTimer->SetTimerPeriod (gWatchdogTimer, MultU64x32 (Timeout, WATCHDOG_TIMER_CALIBRATE_PER_SECOND));
//
// Check for errors
//
if (EFI_ERROR (Status)) {
return EFI_DEVICE_ERROR;
}
return EFI_SUCCESS;
}
所以后面调用gBS->SetWatchdogTimer 就相当于调用CoreSetWatchdogTimer。而在CoreSetWatchdogTimer 中是直接调用gWatchdogTimer->SetTimerPeriod
由于watchdog是在dxemain.c 中才注册的,也就是说只有dxe之后包括bds才可以使用watchdog函数.