summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSascha Hauer <s.hauer@pengutronix.de>2021-12-13 20:56:08 +0100
committerSascha Hauer <s.hauer@pengutronix.de>2021-12-13 23:37:32 +0100
commitf68a547deebdf6f63f2c89bf5097195f59dc4e7a (patch)
tree8fb42c953bf1d71d5439b3a0e2938caf98559fd6
parent2640f8973a068f0c14145835926271aaada618a3 (diff)
downloadbarebox-f68a547deebdf6f63f2c89bf5097195f59dc4e7a.tar.gz
barebox-f68a547deebdf6f63f2c89bf5097195f59dc4e7a.tar.xz
efi: add efi_device hook to be called before an image is started
boot_services::open_protocol supports opening protocols exclusively. A protocol that is opened exclusively can not be used anymore by an application that is called via boot_services::start_image. We want to open the SNP protocol exclusively in the next step. That would mean a chainloaded barebox could no longer use the SNP protocol because it's exclusively opened by the current barebox already. To work around this a efi_drv::dev_pause and efi_drv::dev_continue is introduced. The former is called before an application is started and the latter right after an application has exited. This will be used by the SNP network driver to enter/leave exclusive mode. Signed-off-by: Sascha Hauer <s.hauer@pengutronix.de>
-rw-r--r--common/efi/payload/image.c4
-rw-r--r--drivers/efi/efi-device.c28
-rw-r--r--include/efi/efi-device.h5
3 files changed, 37 insertions, 0 deletions
diff --git a/common/efi/payload/image.c b/common/efi/payload/image.c
index c1206cd6e2..e63da9ddf0 100644
--- a/common/efi/payload/image.c
+++ b/common/efi/payload/image.c
@@ -139,10 +139,14 @@ static int efi_execute_image(const char *file)
shutdown_barebox();
}
+ efi_pause_devices();
+
efiret = BS->start_image(handle, NULL, NULL);
if (EFI_ERROR(efiret))
pr_err("failed to StartImage: %s\n", efi_strerror(efiret));
+ efi_continue_devices();
+
if (!is_driver)
BS->unload_image(handle);
diff --git a/drivers/efi/efi-device.c b/drivers/efi/efi-device.c
index 79cdd2ef27..955899b2d0 100644
--- a/drivers/efi/efi-device.c
+++ b/drivers/efi/efi-device.c
@@ -466,6 +466,34 @@ static int efi_init_devices(void)
}
core_initcall(efi_init_devices);
+void efi_pause_devices(void)
+{
+ struct device_d *dev;
+
+ bus_for_each_device(&efi_bus, dev) {
+ struct driver_d *drv = dev->driver;
+ struct efi_device *efidev = to_efi_device(dev);
+ struct efi_driver *efidrv = to_efi_driver(drv);
+
+ if (efidrv->dev_pause)
+ efidrv->dev_pause(efidev);
+ }
+}
+
+void efi_continue_devices(void)
+{
+ struct device_d *dev;
+
+ bus_for_each_device(&efi_bus, dev) {
+ struct driver_d *drv = dev->driver;
+ struct efi_device *efidev = to_efi_device(dev);
+ struct efi_driver *efidrv = to_efi_driver(drv);
+
+ if (efidrv->dev_continue)
+ efidrv->dev_continue(efidev);
+ }
+}
+
static void efi_devpath(efi_handle_t handle)
{
efi_status_t efiret;
diff --git a/include/efi/efi-device.h b/include/efi/efi-device.h
index cd8a374c32..b9714ffb74 100644
--- a/include/efi/efi-device.h
+++ b/include/efi/efi-device.h
@@ -16,6 +16,8 @@ struct efi_driver {
struct driver_d driver;
int (*probe)(struct efi_device *efidev);
void (*remove)(struct efi_device *efidev);
+ int (*dev_pause)(struct efi_device *efidev);
+ int (*dev_continue)(struct efi_device *efidev);
efi_guid_t guid;
};
@@ -46,6 +48,9 @@ int efi_connect_all(void);
void efi_register_devices(void);
struct efi_device *efi_get_bootsource(void);
+void efi_pause_devices(void);
+void efi_continue_devices(void);
+
static inline bool efi_device_has_guid(struct efi_device *efidev, efi_guid_t guid)
{
int i;