diff options
author | Sascha Hauer <s.hauer@pengutronix.de> | 2019-03-07 14:23:37 +0100 |
---|---|---|
committer | Sascha Hauer <s.hauer@pengutronix.de> | 2019-03-07 14:23:37 +0100 |
commit | 5c126a1d540cc1cc3985c14dfd45fa5b5024b15b (patch) | |
tree | f67b99ff9a7001fd6e1d8a11e5c6748a208deea6 | |
parent | ba8dccda5bd5a1d7ca0fc70612f9bfc06110312d (diff) | |
parent | ec1ab412ee0fc4eb433394878db3c444e86e95c1 (diff) | |
download | barebox-5c126a1d540cc1cc3985c14dfd45fa5b5024b15b.tar.gz barebox-5c126a1d540cc1cc3985c14dfd45fa5b5024b15b.tar.xz |
Merge branch 'for-next/efi'
-rw-r--r-- | Documentation/boards/efi.rst | 35 | ||||
-rw-r--r-- | arch/x86/configs/efi_defconfig | 3 | ||||
-rw-r--r-- | common/efi-devicepath.c | 222 | ||||
-rw-r--r-- | common/efi/efi-image.c | 2 | ||||
-rw-r--r-- | common/efi/efi.c | 9 | ||||
-rw-r--r-- | drivers/block/efi-block-io.c | 2 | ||||
-rw-r--r-- | drivers/clocksource/efi_x86.c | 4 | ||||
-rw-r--r-- | drivers/efi/efi-device.c | 2 | ||||
-rw-r--r-- | drivers/net/efi-snp.c | 2 | ||||
-rw-r--r-- | drivers/watchdog/Kconfig | 6 | ||||
-rw-r--r-- | drivers/watchdog/Makefile | 1 | ||||
-rw-r--r-- | drivers/watchdog/efi_wdt.c | 64 | ||||
-rw-r--r-- | fs/efi.c | 2 | ||||
-rw-r--r-- | fs/efivarfs.c | 2 | ||||
-rw-r--r-- | include/efi.h | 5 |
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); @@ -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, |