summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/boards/efi.rst35
-rw-r--r--arch/x86/configs/efi_defconfig3
-rw-r--r--common/efi-devicepath.c222
-rw-r--r--common/efi/efi-image.c2
-rw-r--r--common/efi/efi.c9
-rw-r--r--drivers/block/efi-block-io.c2
-rw-r--r--drivers/clocksource/efi_x86.c4
-rw-r--r--drivers/efi/efi-device.c2
-rw-r--r--drivers/net/efi-snp.c2
-rw-r--r--drivers/watchdog/Kconfig6
-rw-r--r--drivers/watchdog/Makefile1
-rw-r--r--drivers/watchdog/efi_wdt.c64
-rw-r--r--fs/efi.c2
-rw-r--r--fs/efivarfs.c2
-rw-r--r--include/efi.h5
15 files changed, 129 insertions, 232 deletions
diff --git a/Documentation/boards/efi.rst b/Documentation/boards/efi.rst
index f59bb1d5ba..3da2daac99 100644
--- a/Documentation/boards/efi.rst
+++ b/Documentation/boards/efi.rst
@@ -216,7 +216,6 @@ has a device parameter ``devpath`` which contains its device path:
barebox:/ echo ${handle-00000000d0012198.devpath}
pci_root(0)/Pci(0x1d,0x0)/Usb(0x1,0x0)/Usb(0x2,0x0)
-
EFI variables
-------------
@@ -327,3 +326,37 @@ compile EDK2.
mov %fs, %rax
pushq %rax
+(U)EFI Watchdog
+---------------
+
+(U)EFI provides basic watchdog support. Depending on the system implementation
+it can be a software or hardware watchdog. Within the (U)EFI specification it
+is described as follows:
+
+.. epigraph::
+
+ If the watchdog timer expires, the event is logged by the firmware. The system
+ may then either reset with the Runtime Service ResetSystem(), or perform a
+ platform specific action that must eventually cause the platform to be reset.
+ The watchdog timer is armed before the firmware's boot manager invokes an EFI
+ boot option. The watchdog must be set to a period of 5 minutes. The EFI Image
+ may reset or disable the watchdog timer as needed. If control is returned to
+ the firmware's boot manager, the watchdog timer must be disabled. The watchdog
+ timer is only used during boot services. On successful completion of
+ ExitBootServices() the watchdog timer is disabled.
+
+See page 186:
+https://uefi.org/sites/default/files/resources/UEFI_Spec_2_1_D.pdf
+
+Current linux kernel (v5.0) will execute ExitBootServices() during the early
+boot stage and thus will automatically disable the (U)EFI watchdog. Since it is
+a proper behavior according to the (U)EFI specification, it is impossible to
+protect full boot chain by using this watchdog only. It is recommended to use
+an alternative hardware watchdog, preferably started before the bootloader. If (U)EFI
+firmware lacks this feature, the bootloader should be able to start an alternative
+hardware watchdog on its own. Before implementing this kind of workaround
+please make sure (U)EFI watchdog is not using the same hardware as the alternative
+watchdog.
+
+Nevertheless, barebox provides access to the (U)EFI SetWatchdogTimer()
+interface over its internal watchdog framework.
diff --git a/arch/x86/configs/efi_defconfig b/arch/x86/configs/efi_defconfig
index fdf092e9ba..f489770eba 100644
--- a/arch/x86/configs/efi_defconfig
+++ b/arch/x86/configs/efi_defconfig
@@ -56,6 +56,7 @@ CONFIG_CMD_MM=y
CONFIG_CMD_DETECT=y
CONFIG_CMD_FLASH=y
CONFIG_CMD_POWEROFF=y
+CONFIG_CMD_WD=y
CONFIG_CMD_2048=y
CONFIG_CMD_BAREBOX_UPDATE=y
CONFIG_CMD_OF_NODE=y
@@ -71,6 +72,8 @@ CONFIG_DRIVER_SERIAL_NS16550=y
CONFIG_DRIVER_NET_EFI_SNP=y
# CONFIG_SPI is not set
CONFIG_DISK=y
+CONFIG_WATCHDOG=y
+CONFIG_WATCHDOG_EFI=y
CONFIG_FS_EXT4=y
CONFIG_FS_TFTP=y
CONFIG_FS_NFS=y
diff --git a/common/efi-devicepath.c b/common/efi-devicepath.c
index 54c2f4e3c5..24722284b4 100644
--- a/common/efi-devicepath.c
+++ b/common/efi-devicepath.c
@@ -453,34 +453,6 @@ struct efi_device_path end_instance_device_path = {
.length = END_DEVICE_PATH_LENGTH,
};
-unsigned long
-device_path_size(struct efi_device_path *dev_path)
-{
- struct efi_device_path *Start;
-
- Start = dev_path;
- while (!is_device_path_end(dev_path))
- dev_path = next_device_path_node(dev_path);
-
- return ((unsigned long) dev_path - (unsigned long) Start) +
- sizeof (struct efi_device_path);
-}
-
-struct efi_device_path *
-duplicate_device_path(struct efi_device_path *dev_path)
-{
- struct efi_device_path *new_dev_path;
- unsigned long Size;
-
- Size = device_path_size(dev_path);
-
- new_dev_path = malloc(Size);
- if (new_dev_path)
- memcpy(new_dev_path, dev_path, Size);
-
- return new_dev_path;
-}
-
struct efi_device_path *
device_path_from_handle(efi_handle_t Handle)
{
@@ -495,134 +467,7 @@ device_path_from_handle(efi_handle_t Handle)
return device_path;
}
-struct efi_device_path *
-device_path_instance(struct efi_device_path **device_path, unsigned long *Size)
-{
- struct efi_device_path *Start, *Next, *dev_path;
- unsigned long Count;
-
- dev_path = *device_path;
- Start = dev_path;
-
- if (!dev_path)
- return NULL;
-
- for (Count = 0;; Count++) {
- Next = next_device_path_node(dev_path);
-
- if (is_device_path_end_type(dev_path))
- break;
-
- dev_path = Next;
- }
-
- if (dev_path->sub_type == END_ENTIRE_DEVICE_PATH_SUBTYPE)
- Next = NULL;
-
- *device_path = Next;
-
- *Size = ((u8 *) dev_path) - ((u8 *) Start);
-
- return Start;
-}
-
-unsigned long
-device_path_instance_count(struct efi_device_path *device_path)
-{
- unsigned long Count, Size;
-
- Count = 0;
- while (device_path_instance(&device_path, &Size)) {
- Count += 1;
- }
-
- return Count;
-}
-
-struct efi_device_path *
-append_device_path(struct efi_device_path *Src1, struct efi_device_path *Src2)
-/*
- * Src1 may have multiple "instances" and each instance is appended
- * Src2 is appended to each instance is Src1. (E.g., it's possible
- * to append a new instance to the complete device path by passing
- * it in Src2)
- */
-{
- unsigned long src1_size, src1_inst, src2_size, Size;
- struct efi_device_path *Dst, *Inst;
- u8 *dst_pos;
-
- if (!Src1)
- return duplicate_device_path(Src2);
-
- if (!Src2) {
- return duplicate_device_path(Src1);
- }
-
- src1_size = device_path_size(Src1);
- src1_inst = device_path_instance_count(Src1);
- src2_size = device_path_size(Src2);
- Size = src1_size * src1_inst + src2_size;
-
- Dst = malloc(Size);
- if (Dst) {
- dst_pos = (u8 *) Dst;
-
- /* Copy all device path instances */
-
- while ((Inst = device_path_instance(&Src1, &Size))) {
-
- memcpy(dst_pos, Inst, Size);
- dst_pos += Size;
-
- memcpy(dst_pos, Src2, src2_size);
- dst_pos += src2_size;
-
- memcpy(dst_pos, &end_instance_device_path,
- sizeof (struct efi_device_path));
- dst_pos += sizeof (struct efi_device_path);
- }
-
- /* Change last end marker */
- dst_pos -= sizeof (struct efi_device_path);
- memcpy(dst_pos, &end_device_path,
- sizeof (struct efi_device_path));
- }
-
- return Dst;
-}
-
-struct efi_device_path *
-append_device_path_node(struct efi_device_path *Src1,
- struct efi_device_path *Src2)
-/*
- * Src1 may have multiple "instances" and each instance is appended
- * Src2 is a signal device path node (without a terminator) that is
- * appended to each instance is Src1.
- */
-{
- struct efi_device_path *Temp, *Eop;
- unsigned long length;
-
- /* Build a Src2 that has a terminator on it */
-
- length = Src2->length;
- Temp = malloc(length + sizeof (struct efi_device_path));
- if (!Temp)
- return NULL;
-
- memcpy(Temp, Src2, length);
- Eop = next_device_path_node(Temp);
- set_device_path_end_node(Eop);
-
- /* Append device paths */
-
- Src1 = append_device_path(Src1, Temp);
- free(Temp);
- return Src1;
-}
-
-struct efi_device_path *
+static struct efi_device_path *
unpack_device_path(struct efi_device_path *dev_path)
{
struct efi_device_path *Src, *Dest, *new_path;
@@ -665,71 +510,6 @@ unpack_device_path(struct efi_device_path *dev_path)
return new_path;
}
-struct efi_device_path *
-append_device_path_instance(struct efi_device_path *Src,
- struct efi_device_path *Instance)
-{
- u8 *Ptr;
- struct efi_device_path *dev_path;
- unsigned long src_size;
- unsigned long instance_size;
-
- if (Src == NULL)
- return duplicate_device_path(Instance);
-
- src_size = device_path_size(Src);
- instance_size = device_path_size(Instance);
- Ptr = malloc(src_size + instance_size);
- dev_path = (struct efi_device_path *) Ptr;
-
- memcpy(Ptr, Src, src_size);
-
- while (!is_device_path_end(dev_path))
- dev_path = next_device_path_node(dev_path);
-
- /*
- * Convert the End to an End Instance, since we are
- * appending another instacne after this one its a good
- * idea.
- */
- dev_path->sub_type = END_INSTANCE_DEVICE_PATH_SUBTYPE;
-
- dev_path = next_device_path_node(dev_path);
- memcpy(dev_path, Instance, instance_size);
-
- return (struct efi_device_path *) Ptr;
-}
-
-efi_status_t
-lib_device_path_to_interface(efi_guid_t * Protocol,
- struct efi_device_path *file_path,
- void **Interface)
-{
- efi_status_t Status;
- efi_handle_t Device;
-
- Status = BS->locate_device_path(Protocol, &file_path, &Device);
-
- if (!EFI_ERROR(Status)) {
-
- /* If we didn't get a direct match return not found */
- Status = EFI_NOT_FOUND;
-
- if (is_device_path_end(file_path)) {
-
- /* It was a direct match, lookup the protocol interface */
-
- Status =
- BS->handle_protocol(Device, Protocol, Interface);
- }
- }
-
- if (EFI_ERROR(Status))
- *Interface = NULL;
-
- return Status;
-}
-
static void
dev_path_pci(struct string *str, void *dev_path)
{
diff --git a/common/efi/efi-image.c b/common/efi/efi-image.c
index 885348da45..939663a6e2 100644
--- a/common/efi/efi-image.c
+++ b/common/efi/efi-image.c
@@ -88,7 +88,7 @@ struct linux_kernel_header {
uint32_t handover_offset; /** */
} __attribute__ ((packed));
-int efi_load_image(const char *file, efi_loaded_image_t **loaded_image,
+static int efi_load_image(const char *file, efi_loaded_image_t **loaded_image,
efi_handle_t *h)
{
void *exe;
diff --git a/common/efi/efi.c b/common/efi/efi.c
index 1f451a157e..a7b25cbbe2 100644
--- a/common/efi/efi.c
+++ b/common/efi/efi.c
@@ -367,8 +367,15 @@ efi_status_t efi_main(efi_handle_t image, efi_system_table_t *sys_table)
static int efi_core_init(void)
{
- struct device_d *dev = device_alloc("efi-cs", DEVICE_ID_SINGLE);
+ struct device_d *dev;
+ int ret;
+
+ dev = device_alloc("efi-cs", DEVICE_ID_SINGLE);
+ ret = platform_device_register(dev);
+ if (ret)
+ return ret;
+ dev = device_alloc("efi-wdt", DEVICE_ID_SINGLE);
return platform_device_register(dev);
}
core_initcall(efi_core_init);
diff --git a/drivers/block/efi-block-io.c b/drivers/block/efi-block-io.c
index 2bbeb99e69..d167d814c2 100644
--- a/drivers/block/efi-block-io.c
+++ b/drivers/block/efi-block-io.c
@@ -142,7 +142,7 @@ static int is_bio_usbdev(struct efi_device *efidev)
return 0;
}
-int efi_bio_probe(struct efi_device *efidev)
+static int efi_bio_probe(struct efi_device *efidev)
{
int ret;
struct efi_bio_priv *priv;
diff --git a/drivers/clocksource/efi_x86.c b/drivers/clocksource/efi_x86.c
index 4d2657ea1d..f8d3ff8a43 100644
--- a/drivers/clocksource/efi_x86.c
+++ b/drivers/clocksource/efi_x86.c
@@ -6,7 +6,7 @@
#include <clock.h>
#ifdef __x86_64__
-uint64_t ticks_read(void)
+static uint64_t ticks_read(void)
{
uint64_t a, d;
@@ -15,7 +15,7 @@ uint64_t ticks_read(void)
return (d << 32) | a;
}
#else
-uint64_t ticks_read(void)
+static uint64_t ticks_read(void)
{
uint64_t val;
diff --git a/drivers/efi/efi-device.c b/drivers/efi/efi-device.c
index 5cc68fb781..305d337aab 100644
--- a/drivers/efi/efi-device.c
+++ b/drivers/efi/efi-device.c
@@ -32,7 +32,7 @@
#include <efi/efi-device.h>
#include <linux/err.h>
-int efi_locate_handle(enum efi_locate_search_type search_type,
+static int efi_locate_handle(enum efi_locate_search_type search_type,
efi_guid_t *protocol,
void *search_key,
unsigned long *no_handles,
diff --git a/drivers/net/efi-snp.c b/drivers/net/efi-snp.c
index 4e32513739..def2714bee 100644
--- a/drivers/net/efi-snp.c
+++ b/drivers/net/efi-snp.c
@@ -231,7 +231,7 @@ static int efi_snp_set_ethaddr(struct eth_device *edev, const unsigned char *adr
return 0;
}
-int efi_snp_probe(struct efi_device *efidev)
+static int efi_snp_probe(struct efi_device *efidev)
{
struct eth_device *edev;
struct efi_snp_priv *priv;
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index 27e9f6d8b4..96e91fc2ce 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -22,6 +22,12 @@ config WATCHDOG_AR9344
help
Add support for watchdog on the QCA AR9344 SoC.
+config WATCHDOG_EFI
+ bool "Generic EFI Watchdog Driver"
+ depends on EFI_BOOTUP
+ help
+ Add support for the EFI watchdog.
+
config WATCHDOG_DAVINCI
bool "TI Davinci"
depends on ARCH_DAVINCI
diff --git a/drivers/watchdog/Makefile b/drivers/watchdog/Makefile
index faf06110a3..69189ba1f3 100644
--- a/drivers/watchdog/Makefile
+++ b/drivers/watchdog/Makefile
@@ -1,5 +1,6 @@
obj-$(CONFIG_WATCHDOG) += wd_core.o
obj-$(CONFIG_WATCHDOG_AR9344) += ar9344_wdt.o
+obj-$(CONFIG_WATCHDOG_EFI) += efi_wdt.o
obj-$(CONFIG_WATCHDOG_DAVINCI) += davinci_wdt.o
obj-$(CONFIG_WATCHDOG_OMAP) += omap_wdt.o
obj-$(CONFIG_WATCHDOG_MXS28) += im28wd.o
diff --git a/drivers/watchdog/efi_wdt.c b/drivers/watchdog/efi_wdt.c
new file mode 100644
index 0000000000..8e3e51b7a9
--- /dev/null
+++ b/drivers/watchdog/efi_wdt.c
@@ -0,0 +1,64 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2019 Oleksij Rempel <o.rempel@pengutronix.de>, Pengutronix
+ */
+
+#include <common.h>
+#include <init.h>
+#include <driver.h>
+#include <efi.h>
+#include <efi/efi.h>
+#include <watchdog.h>
+
+struct efi_wdt_priv {
+ struct watchdog wd;
+ struct device_d *dev;
+};
+
+#define to_efi_wdt(h) container_of(h, struct efi_wdt_priv, wd)
+
+static int efi_wdt_set_timeout(struct watchdog *wd, unsigned timeout)
+{
+ struct efi_wdt_priv *priv = to_efi_wdt(wd);
+ efi_status_t efiret;
+
+ efiret = BS->set_watchdog_timer(timeout, 0, 0, NULL);
+ if (EFI_ERROR(efiret)) {
+ dev_err(priv->dev, "filed to set EFI watchdog: %lx\n", efiret);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int efi_wdt_probe(struct device_d *dev)
+{
+ struct efi_wdt_priv *priv;
+ int ret;
+
+ priv = xzalloc(sizeof(*priv));
+
+ priv->wd.set_timeout = efi_wdt_set_timeout;
+ priv->wd.hwdev = dev;
+ priv->dev = dev;
+
+ dev->priv = priv;
+
+ priv->wd.timeout_max = U32_MAX;
+
+ ret = watchdog_register(&priv->wd);
+ if (ret)
+ goto on_error;
+
+ return 0;
+
+on_error:
+ free(priv);
+ return ret;
+}
+
+static struct driver_d efi_wdt_driver = {
+ .name = "efi-wdt",
+ .probe = efi_wdt_probe,
+};
+device_platform_driver(efi_wdt_driver);
diff --git a/fs/efi.c b/fs/efi.c
index 81c1ffe078..944d6aac7a 100644
--- a/fs/efi.c
+++ b/fs/efi.c
@@ -513,7 +513,7 @@ coredevice_initcall(efifs_init);
static int index;
-int efi_fs_probe(struct efi_device *efidev)
+static int efi_fs_probe(struct efi_device *efidev)
{
char *path, *device;
int ret;
diff --git a/fs/efivarfs.c b/fs/efivarfs.c
index a911eac3bf..1e80493621 100644
--- a/fs/efivarfs.c
+++ b/fs/efivarfs.c
@@ -67,7 +67,7 @@ static int read_byte_str(const char *str, u8 *out)
return 0;
}
-int efi_guid_parse(const char *str, efi_guid_t *guid)
+static int efi_guid_parse(const char *str, efi_guid_t *guid)
{
int i, ret;
u8 idx[] = { 3, 2, 1, 0, 5, 4, 7, 6, 8, 9, 10, 11, 12, 13, 14, 15 };
diff --git a/include/efi.h b/include/efi.h
index 7cc5fe05fa..218333f824 100644
--- a/include/efi.h
+++ b/include/efi.h
@@ -234,7 +234,10 @@ typedef struct {
efi_status_t (EFIAPI *exit_boot_services)(efi_handle_t, unsigned long);
void *get_next_monotonic_count;
efi_status_t (EFIAPI *stall)(unsigned long usecs);
- void *set_watchdog_timer;
+ efi_status_t (EFIAPI *set_watchdog_timer)(unsigned long timeout,
+ uint64_t watchdog_code,
+ unsigned long data_size,
+ s16 *watchdog_data);
efi_status_t(EFIAPI *connect_controller)(efi_handle_t controller_handle,
efi_handle_t *driver_image_handle,
struct efi_device_path *remaining_device_path,