From 7999733764b18ff74471255bc780c2f913d8fb73 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 16 Oct 2019 09:21:35 +0200 Subject: efi: Fix typo in description string s/Conosle/Console/ Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- common/efi-guid.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/common/efi-guid.c b/common/efi-guid.c index 1e45ccf4d2..2bf2395e85 100644 --- a/common/efi-guid.c +++ b/common/efi-guid.c @@ -52,7 +52,7 @@ const char *efi_guid_string(efi_guid_t *g) EFI_GUID_STRING(EFI_ISA_IO_PROTOCOL_GUID, "ISA IO Protocol", "ISA IO Protocol"); EFI_GUID_STRING(EFI_STANDARD_ERROR_DEVICE_GUID, "Standard Error Device Guid", "EFI Standard Error Device Guid"); EFI_GUID_STRING(EFI_CONSOLE_OUT_DEVICE_GUID, "Console Out Device Guid", "EFI Console Out Device Guid"); - EFI_GUID_STRING(EFI_CONSOLE_IN_DEVICE_GUID, "Console In Device Guid", "EFI Conosle In Device Guid"); + EFI_GUID_STRING(EFI_CONSOLE_IN_DEVICE_GUID, "Console In Device Guid", "EFI Console In Device Guid"); EFI_GUID_STRING(EFI_SIMPLE_TEXT_OUT_PROTOCOL_GUID, "Simple Text Out Protocol", "EFI 1.0 Simple Text Out Protocol"); EFI_GUID_STRING(EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID, "Simple Text Input Ex Protocol", "UEFI 2.1 Simple Text Input Ex Protocol"); EFI_GUID_STRING(EFI_SIMPLE_TEXT_IN_PROTOCOL_GUID, "Simple Text In Protocol", "EFI 1.0 Simple Text In Protocol"); -- cgit v1.2.3 From edf901bf6b0a0f2bd2d9d1ec9ec366140aa24489 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 16 Oct 2019 09:21:36 +0200 Subject: efi: retire efi_compare_guid in favor of efi_guidcmp Both functions wrap the same memcmp except that one uses pointers to GUIDs and the other passes the GUIDs by value. The function is static inline, so it doesn't really matter which one we keep. We'll drop efi_compare_guid because it's been used once only in the code base so far. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- common/efi-devicepath.c | 2 +- include/efi.h | 5 ----- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/common/efi-devicepath.c b/common/efi-devicepath.c index 24722284b4..3db2cea061 100644 --- a/common/efi-devicepath.c +++ b/common/efi-devicepath.c @@ -572,7 +572,7 @@ dev_path_vendor(struct string *str, void *dev_path) } cprintf(str, "Ven%s(%pU", type, &Vendor->Guid); - if (efi_compare_guid(&Vendor->Guid, &efi_unknown_device_guid) == 0) { + if (efi_guidcmp(Vendor->Guid, efi_unknown_device_guid) == 0) { /* GUID used by EFI to enumerate an EDD 1.1 device */ unknown_dev_path = (struct unknown_device_vendor_device_path *) Vendor; diff --git a/include/efi.h b/include/efi.h index 218333f824..166803a58f 100644 --- a/include/efi.h +++ b/include/efi.h @@ -664,11 +664,6 @@ typedef union { efi_ipv6_address v6; } efi_ip_address; -static inline int efi_compare_guid(efi_guid_t *a, efi_guid_t *b) -{ - return memcmp(a, b, sizeof(efi_guid_t)); -} - struct efi_device_path *device_path_from_handle(efi_handle_t Handle); char *device_path_to_str(struct efi_device_path *dev_path); u8 device_path_to_type(struct efi_device_path *dev_path); -- cgit v1.2.3 From 0fc1f8ef52847364224f87323c70bfcd43d8eaf6 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 16 Oct 2019 09:21:37 +0200 Subject: efi: use efi_guidcmp helper where appropriate We have a helper for it. Let's use it. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- drivers/efi/efi-device.c | 2 +- fs/efivarfs.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/efi/efi-device.c b/drivers/efi/efi-device.c index 305d337aab..68d81caf01 100644 --- a/drivers/efi/efi-device.c +++ b/drivers/efi/efi-device.c @@ -311,7 +311,7 @@ static int efi_bus_match(struct device_d *dev, struct driver_d *drv) int i; for (i = 0; i < efidev->num_guids; i++) { - if (!memcmp(&efidrv->guid, &efidev->guids[i], sizeof(efi_guid_t))) { + if (!efi_guidcmp(efidrv->guid, efidev->guids[i])) { BS->handle_protocol(efidev->handle, &efidev->guids[i], &efidev->protocol); return 0; diff --git a/fs/efivarfs.c b/fs/efivarfs.c index 1e80493621..9eadda4121 100644 --- a/fs/efivarfs.c +++ b/fs/efivarfs.c @@ -145,7 +145,7 @@ static int efivars_create(struct device_d *dev, const char *pathname, mode_t mod if (ret) return -ENOENT; - if (memcmp(&vendor, &EFI_BAREBOX_VENDOR_GUID, sizeof(efi_guid_t))) + if (efi_guidcmp(vendor, EFI_BAREBOX_VENDOR_GUID)) return -EPERM; inode = xzalloc(sizeof(*inode)); -- cgit v1.2.3 From f51c1cec2581aab869ab4fba313898fc2f436f77 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 16 Oct 2019 09:21:38 +0200 Subject: x86: include: add asmlinkage 'storage class' We've a number of C functions with external linkage that are only called from assembly. -Wmissing-prototypes warns about these unless they have a prototype that goes unused. Let's standardize on using the asmlinkage 'storage class' to mark such declarations. As defines asmlinkage to naught unless does, it's sufficient to add an empty header to make this usable on x86 as well. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- arch/x86/include/asm/linkage.h | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 arch/x86/include/asm/linkage.h diff --git a/arch/x86/include/asm/linkage.h b/arch/x86/include/asm/linkage.h new file mode 100644 index 0000000000..a8d1bdb7de --- /dev/null +++ b/arch/x86/include/asm/linkage.h @@ -0,0 +1,6 @@ +#ifndef __ASM_LINKAGE_H +#define __ASM_LINKAGE_H + +/* referenced by */ + +#endif -- cgit v1.2.3 From c64a4a4ccf9bc60385f9c3ba07886d7024503444 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Wed, 16 Oct 2019 09:21:39 +0200 Subject: efi: silence warning about un-prototyped assembly-called functions Both _relocate and efi_main are only called from assembly, but -Wmissing-prototypes doesn't know that and warns about them. Pre-declare prototypes to silence the warnings. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- arch/x86/mach-efi/reloc_x86_64.c | 3 +++ common/efi/efi.c | 3 +++ 2 files changed, 6 insertions(+) diff --git a/arch/x86/mach-efi/reloc_x86_64.c b/arch/x86/mach-efi/reloc_x86_64.c index 1db72f5dbc..e83bacb302 100644 --- a/arch/x86/mach-efi/reloc_x86_64.c +++ b/arch/x86/mach-efi/reloc_x86_64.c @@ -35,11 +35,14 @@ SUCH DAMAGE. */ +#include #include #include #include +asmlinkage efi_status_t _relocate (long, Elf64_Dyn *, efi_handle_t, efi_system_table_t *); + efi_status_t _relocate (long ldbase, Elf64_Dyn *dyn, efi_handle_t image, efi_system_table_t *systab) { long relsz = 0, relent = 0; diff --git a/common/efi/efi.c b/common/efi/efi.c index a7b25cbbe2..73cea37036 100644 --- a/common/efi/efi.c +++ b/common/efi/efi.c @@ -17,6 +17,7 @@ * */ +#include #include #include #include @@ -318,6 +319,8 @@ static int efi_init(void) } device_initcall(efi_init); +asmlinkage efi_status_t efi_main(efi_handle_t, efi_system_table_t *); + /** * efi-main - Entry point for EFI images */ -- cgit v1.2.3 From a3b0c7f17290d86e261bd35211e8f322ac97e749 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 21 Oct 2019 11:23:40 +0200 Subject: serial: efi-stdio: replace globals with handles in priv struct Despite assigning efi_sys_table->{con_in,con_out} to priv->{in,out}, some functions still use the global efi_sys_table->{con_in,con_out}. Let's restrict globals access to the probe function and have the priv struct completely describe input and output used in the callbacks. No functional change. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- drivers/serial/efi-stdio.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/drivers/serial/efi-stdio.c b/drivers/serial/efi-stdio.c index 2ca89fa4f8..a8cc967b32 100644 --- a/drivers/serial/efi-stdio.c +++ b/drivers/serial/efi-stdio.c @@ -116,7 +116,7 @@ static int efi_read_key(struct efi_console_priv *priv, bool wait) if (wait) BS->wait_for_event(1, priv->in->wait_for_key, &index); - efiret = priv->in->read_key_stroke(efi_sys_table->con_in, &k); + efiret = priv->in->read_key_stroke(priv->in, &k); if (EFI_ERROR(efiret)) return -efi_errno(efiret); @@ -133,7 +133,8 @@ static int efi_read_key(struct efi_console_priv *priv, bool wait) static void efi_console_putc(struct console_device *cdev, char c) { uint16_t str[2] = {}; - struct efi_simple_text_output_protocol *con_out = efi_sys_table->con_out; + struct efi_console_priv *priv = to_efi(cdev); + struct efi_simple_text_output_protocol *con_out = priv->out; str[0] = c; -- cgit v1.2.3 From 438f80e986586ddb1288caac4b9e1b0e6498e0cc Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Mon, 21 Oct 2019 11:23:41 +0200 Subject: serial: efi-stdio: Add simple_text_input_ex_protocol backend EFI implementations differ in how simple_text_input_protocol treats ctrl+alpha combinations. OVMF (used with QEMU) returns a Unicode control character, the UEFI on the Dell Latitude 7490 on the other hand ignores the ctrl completely and returns just the letter rendering utilities like barebox edit unusable. To fix this, the simple_text_input_ex_protocol can be leveraged as it additionally provides the state of modifier keys. Extend efi-stdio to use it where possible. Cc: Michael Olbrich Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- drivers/serial/efi-stdio.c | 75 +++++++++++++++++++++++++++++++++++++++------- drivers/serial/efi-stdio.h | 58 +++++++++++++++++++++++++++++++++++ 2 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 drivers/serial/efi-stdio.h diff --git a/drivers/serial/efi-stdio.c b/drivers/serial/efi-stdio.c index a8cc967b32..9e825181e6 100644 --- a/drivers/serial/efi-stdio.c +++ b/drivers/serial/efi-stdio.c @@ -26,6 +26,8 @@ #include #include #include +#include +#include "efi-stdio.h" #define EFI_SHIFT_STATE_VALID 0x80000000 #define EFI_RIGHT_CONTROL_PRESSED 0x00000004 @@ -71,6 +73,7 @@ struct efi_console_priv { struct efi_simple_text_output_protocol *out; struct efi_simple_input_interface *in; + struct efi_simple_text_input_ex_protocol *inex; struct console_device cdev; int lastkey; u16 efi_console_buffer[CONFIG_CBSIZE]; @@ -105,29 +108,65 @@ static struct efi_ctrlkey ctrlkeys[] = { { 0x17, 27 /* escape key */ }, }; +static int xlate_keypress(struct efi_input_key *k) +{ + int i; + + /* 32 bit modifier keys + 16 bit scan code + 16 bit unicode */ + for (i = 0; i < ARRAY_SIZE(ctrlkeys); i++) { + if (ctrlkeys[i].scan_code == k->scan_code) + return ctrlkeys[i].bb_key; + + } + + return k->unicode_char & 0xff; +} + static int efi_read_key(struct efi_console_priv *priv, bool wait) { unsigned long index; efi_status_t efiret; - struct efi_input_key k; - int i; + struct efi_key_data kd; /* wait until key is pressed */ if (wait) BS->wait_for_event(1, priv->in->wait_for_key, &index); - efiret = priv->in->read_key_stroke(priv->in, &k); - if (EFI_ERROR(efiret)) - return -efi_errno(efiret); + if (priv->inex) { + efiret = priv->inex->read_key_stroke_ex(priv->inex, &kd); - /* 32 bit modifier keys + 16 bit scan code + 16 bit unicode */ - for (i = 0; i < ARRAY_SIZE(ctrlkeys); i++) { - if (ctrlkeys[i].scan_code == k.scan_code) - return ctrlkeys[i].bb_key; + if (efiret == EFI_NOT_READY) + return -EAGAIN; + + if (!EFI_ERROR(efiret)) { + if ((kd.state.shift_state & EFI_SHIFT_STATE_VALID) && + (kd.state.shift_state & EFI_CONTROL_PRESSED)) { + int ch = tolower(kd.key.unicode_char & 0xff); + + if (isalpha(ch)) + return CHAR_CTRL(ch); + if (ch == '\0') /* ctrl is pressed on its own */ + return -EAGAIN; + } + if (kd.key.unicode_char || kd.key.scan_code) + return xlate_keypress(&kd.key); + + /* Some broken firmwares offer simple_text_input_ex_protocol, + * but never handle any key. Treat those as if + * read_key_stroke_ex failed and fall through + * to the basic simple_text_input_protocol. + */ + dev_dbg(priv->cdev.dev, "Falling back to simple_text_input_protocol\n"); + } } - return k.unicode_char & 0xff; + efiret = priv->in->read_key_stroke(priv->in, &kd.key); + + if (EFI_ERROR(efiret)) + return -efi_errno(efiret); + + return xlate_keypress(&kd.key); } static void efi_console_putc(struct console_device *cdev, char c) @@ -332,8 +371,12 @@ static void efi_set_mode(struct efi_console_priv *priv) static int efi_console_probe(struct device_d *dev) { + efi_guid_t inex_guid = EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL_GUID; + struct efi_simple_text_input_ex_protocol *inex; struct console_device *cdev; struct efi_console_priv *priv; + efi_status_t efiret; + int i; priv = xzalloc(sizeof(*priv)); @@ -341,6 +384,18 @@ static int efi_console_probe(struct device_d *dev) priv->out = efi_sys_table->con_out; priv->in = efi_sys_table->con_in; + efiret = BS->open_protocol((void *)efi_sys_table->con_in_handle, + &inex_guid, + (void **)&inex, + efi_parent_image, + 0, + EFI_OPEN_PROTOCOL_GET_PROTOCOL); + + if (!EFI_ERROR(efiret)) { + priv->inex = inex; + dev_dbg(dev, "Using simple_text_input_ex_protocol\n"); + } + priv->current_color = EFI_WHITE; efi_set_mode(priv); diff --git a/drivers/serial/efi-stdio.h b/drivers/serial/efi-stdio.h new file mode 100644 index 0000000000..1fa417c706 --- /dev/null +++ b/drivers/serial/efi-stdio.h @@ -0,0 +1,58 @@ +#ifndef EFI_STDIO_H_ +#define EFI_STDIO_H_ + +#include + +struct efi_simple_text_input_ex_protocol; + +typedef efi_status_t (EFIAPI *efi_input_reset_ex)( + struct efi_simple_text_input_ex_protocol *this, + efi_bool_t extended_verification +); + +struct efi_key_state { + u32 shift_state; + u8 toggle_state; +}; + +struct efi_key_data { + struct efi_input_key key; + struct efi_key_state state; +}; + +typedef efi_status_t (EFIAPI *efi_input_read_key_ex)( + struct efi_simple_text_input_ex_protocol *this, + struct efi_key_data *keydata +); + +typedef efi_status_t (EFIAPI *efi_set_state)( + struct efi_simple_text_input_ex_protocol *this, + u8 *key_toggle_state +); + +typedef efi_status_t (EFIAPI *efi_key_notify_function)( + struct efi_key_data *keydata +); + +typedef efi_status_t (EFIAPI *efi_register_keystroke_notify)( + struct efi_simple_text_input_ex_protocol *this, + struct efi_key_data keydata, + efi_key_notify_function key_notification_function, + void **notify_handle +); + +typedef efi_status_t (EFIAPI *efi_unregister_keystroke_notify)( + struct efi_simple_text_input_ex_protocol *this, + void *notification_handle +); + +struct efi_simple_text_input_ex_protocol { + efi_input_reset_ex reset; + efi_input_read_key_ex read_key_stroke_ex; + void *wait_for_key_ex; + efi_set_state set_state; + efi_register_keystroke_notify register_key_notify; + efi_unregister_keystroke_notify unregister_key_notify; +}; + +#endif -- cgit v1.2.3 From 6ab809a3d5b6ddec6e0dd12096fd0ce6bab66006 Mon Sep 17 00:00:00 2001 From: Ahmad Fatoum Date: Thu, 24 Oct 2019 08:21:37 +0200 Subject: efi: populate boot source instance We already determine the boot source variable at core init level, but so far we didn't populate the instance because the numbering of the block devices isn't known that early. Introduce a helper to check if a block device is the boot source and if it is, have the block device driver populate the missing boot source instance. Signed-off-by: Ahmad Fatoum Signed-off-by: Sascha Hauer --- drivers/block/efi-block-io.c | 17 +++++++++++++---- drivers/efi/efi-device.c | 8 +++++++- include/efi/efi-device.h | 1 + 3 files changed, 21 insertions(+), 5 deletions(-) diff --git a/drivers/block/efi-block-io.c b/drivers/block/efi-block-io.c index d167d814c2..39dbfb0f7a 100644 --- a/drivers/block/efi-block-io.c +++ b/drivers/block/efi-block-io.c @@ -14,6 +14,7 @@ #include #include #include +#include #define EFI_BLOCK_IO_PROTOCOL_REVISION2 0x00020001 #define EFI_BLOCK_IO_PROTOCOL_REVISION3 ((2<<16) | (31)) @@ -145,6 +146,7 @@ static int is_bio_usbdev(struct efi_device *efidev) static int efi_bio_probe(struct efi_device *efidev) { int ret; + int instance; struct efi_bio_priv *priv; struct efi_block_io_media *media; @@ -159,10 +161,14 @@ static int efi_bio_probe(struct efi_device *efidev) efi_bio_print_info(priv); priv->dev = &efidev->dev; - if (is_bio_usbdev(efidev)) - priv->blk.cdev.name = xasprintf("usbdisk%d", cdev_find_free_index("usbdisk")); - else - priv->blk.cdev.name = xasprintf("disk%d", cdev_find_free_index("disk")); + if (is_bio_usbdev(efidev)) { + instance = cdev_find_free_index("usbdisk"); + priv->blk.cdev.name = xasprintf("usbdisk%d", instance); + } else { + instance = cdev_find_free_index("disk"); + priv->blk.cdev.name = xasprintf("disk%d", instance); + } + priv->blk.blockbits = ffs(media->block_size) - 1; priv->blk.num_blocks = media->last_block + 1; priv->blk.ops = &efi_bio_ops; @@ -174,6 +180,9 @@ static int efi_bio_probe(struct efi_device *efidev) if (ret) return ret; + if (efi_get_bootsource() == efidev) + bootsource_set_instance(instance); + parse_partition_table(&priv->blk); return 0; diff --git a/drivers/efi/efi-device.c b/drivers/efi/efi-device.c index 68d81caf01..a1aac2dd31 100644 --- a/drivers/efi/efi-device.c +++ b/drivers/efi/efi-device.c @@ -398,13 +398,19 @@ static int is_bio_usbdev(struct efi_device *efidev) return 0; } +static struct efi_device *bootdev; + +struct efi_device *efi_get_bootsource(void) +{ + return bootdev; +} + static void efi_set_bootsource(void) { enum bootsource src = BOOTSOURCE_UNKNOWN; int instance = BOOTSOURCE_INSTANCE_UNKNOWN; efi_handle_t *efi_parent; - struct efi_device *bootdev; if (!efi_loaded_image->parent_handle) goto out; diff --git a/include/efi/efi-device.h b/include/efi/efi-device.h index 15c293bb1b..5eaf1f260d 100644 --- a/include/efi/efi-device.h +++ b/include/efi/efi-device.h @@ -43,5 +43,6 @@ static inline int efi_driver_register(struct efi_driver *efidrv) int efi_connect_all(void); void efi_register_devices(void); +struct efi_device *efi_get_bootsource(void); #endif /* __EFI_EFI_DEVICE_H */ -- cgit v1.2.3