From e38bf6503439734c76193c469ac5101f6b284613 Mon Sep 17 00:00:00 2001 From: Yi-Yo Chiang Date: Fri, 8 Aug 2025 15:20:04 +0800 Subject: [PATCH] [lib][uefi] Default implementation of BootService.SetWatchdogTimer() The platform_watchdog_ methods are optional features that the target platform can choose to implement. If they are implemented, then BootService.SetWatchdogTimer() would call them to setup the hardware watchdog. If they are not implemented (for example presubmit targets), then BootService.SetWatchdogTimer() would test the WEAK symbol against a NULL pointer and error out. To use BootService.SetWatchdogTimer(), platforms can choose to either implement platform_watchdog_init and platform_watchdog_set_enabled, or override the entire BootService.SetWatchdogTimer() method. --- lib/uefi/boot_service_provider.cpp | 1 + lib/uefi/rules.mk | 8 +++-- lib/uefi/uefi_platform.cpp | 45 +++++++++++++++++++++++++++++ lib/uefi/uefi_platform.h | 6 +++- lib/watchdog/include/lib/watchdog.h | 5 ++++ 5 files changed, 62 insertions(+), 3 deletions(-) diff --git a/lib/uefi/boot_service_provider.cpp b/lib/uefi/boot_service_provider.cpp index 041dd5e2..f00ae05c 100644 --- a/lib/uefi/boot_service_provider.cpp +++ b/lib/uefi/boot_service_provider.cpp @@ -393,4 +393,5 @@ void setup_boot_service_table(EfiBootService *service) { service->stall = stall; service->raise_tpl = raise_tpl; service->restore_tpl = restore_tpl; + service->set_watchdog_timer = set_watchdog_timer; } diff --git a/lib/uefi/rules.mk b/lib/uefi/rules.mk index fc2df6bc..4eaa2b7b 100644 --- a/lib/uefi/rules.mk +++ b/lib/uefi/rules.mk @@ -2,10 +2,14 @@ LOCAL_DIR := $(GET_LOCAL_DIR) MODULE := $(LOCAL_DIR) -MODULE_INCLUDES += $(LOCAL_DIR)/local/include - MODULE_DEFINES=MSPACES=1 +MODULE_INCLUDES += \ + lib/watchdog/include \ + +MODULE_DEPS += \ + lib/libcpp \ + MODULE_SRCS += \ $(LOCAL_DIR)/uefi.cpp \ $(LOCAL_DIR)/relocation.cpp \ diff --git a/lib/uefi/uefi_platform.cpp b/lib/uefi/uefi_platform.cpp index fa39d152..2fb92c88 100644 --- a/lib/uefi/uefi_platform.cpp +++ b/lib/uefi/uefi_platform.cpp @@ -18,7 +18,10 @@ #include "uefi_platform.h" #include +#include #include +#include +#include #include #include #include @@ -27,6 +30,8 @@ #include "defer.h" +#define LOCAL_TRACE 0 + __WEAK EFI_STATUS efi_dt_fixup(struct EfiDtFixupProtocol *self, void *fdt, size_t *buffer_size, uint32_t flags) { auto offset = fdt_subnode_offset(fdt, 0, "chosen"); @@ -111,6 +116,46 @@ __WEAK EfiStatus get_timestamp_properties(EfiTimestampProperties *properties) { return SUCCESS; } +__BEGIN_CDECLS + +// Redeclaring these as WEAK has two effects: +// 1. Since we are also including lib/watchdog.h, the compiler would ensure +// that the declarations had matching prototypes. +// 2. If the platform did not provide these methods, then these symbols would +// resolve to NULL, and can be checked at runtime. +extern __WEAK status_t platform_watchdog_init( + lk_time_t target_timeout, lk_time_t* recommended_pet_period); +extern __WEAK void platform_watchdog_set_enabled(bool enabled); + +__END_CDECLS + +__WEAK EfiStatus set_watchdog_timer(size_t timeout, uint64_t watchdog_code, + size_t data_size, char16_t* watchdog_data) { + if (platform_watchdog_init == nullptr || platform_watchdog_set_enabled == nullptr) { + TRACEF( + "unimplemented: platform_watchdog_init = %p " + "platform_watchdog_set_enabled = %p\n", + platform_watchdog_init, platform_watchdog_set_enabled); + return UNSUPPORTED; + } + if (timeout != 0) { + lk_time_t ignored = 0; + status_t ret = platform_watchdog_init(timeout * 1000, &ignored); + LTRACEF("platform_watchdog_init() ret=%d\n", ret); + if (ret == ERR_INVALID_ARGS) { + return INVALID_PARAMETER; + } else if (ret != NO_ERROR) { + return UNSUPPORTED; + } + platform_watchdog_set_enabled(true); + LTRACEF("enabled hw watchdog\n"); + } else { + platform_watchdog_set_enabled(false); + LTRACEF("disabled hw watchdog\n"); + } + return SUCCESS; +} + namespace { const char *GetImageType(const char16_t *ImageType) { diff --git a/lib/uefi/uefi_platform.h b/lib/uefi/uefi_platform.h index 863542ea..7b6ebe4e 100644 --- a/lib/uefi/uefi_platform.h +++ b/lib/uefi/uefi_platform.h @@ -47,6 +47,10 @@ uint64_t get_timestamp(); EfiStatus get_timestamp_properties(EfiTimestampProperties *properties); +// timeout unit is in seconds. +EfiStatus set_watchdog_timer(size_t timeout, uint64_t watchdog_code, + size_t data_size, char16_t* watchdog_data); + // alloc_page/free_pages is implemented in memory_protocols.cpp void *alloc_page(void *addr, size_t size, size_t align_log2 = PAGE_SIZE_SHIFT); @@ -71,4 +75,4 @@ void setup_heap(); // Caled by LK once after executing UEFI application to tear down the heap void reset_heap(); -#endif \ No newline at end of file +#endif diff --git a/lib/watchdog/include/lib/watchdog.h b/lib/watchdog/include/lib/watchdog.h index d127ede3..1bbff9da 100644 --- a/lib/watchdog/include/lib/watchdog.h +++ b/lib/watchdog/include/lib/watchdog.h @@ -7,6 +7,7 @@ */ #pragma once +#include #include #include #include @@ -14,6 +15,8 @@ #define WATCHDOG_MAGIC 'wdog' +__BEGIN_CDECLS + typedef struct watchdog { uint32_t magic; const char *name; @@ -64,3 +67,5 @@ extern void platform_watchdog_pet(void); status_t watchdog_hw_init(lk_time_t timeout); void watchdog_hw_set_enabled(bool enabled); + +__END_CDECLS