2014-04-04 12:26:39

by Leif Lindholm

[permalink] [raw]
Subject: [PATCH 0/5] Non-ARM-specific EFI patches needed for ARM ports

This is the set of patches from the arm/arm64 UEFI support that are not
in fact architecture specific. This set depends on other EFI patches
already in linux-next.

H. Peter Anvin (1):
efi: x86: Improve cmdline conversion

Leif Lindholm (1):
efi: efi-stub-helper cleanup

Mark Salter (1):
efi: create memory map iteration helper

Roy Franz (2):
efi: Add shared printk wrapper for consistent prefixing
efi: Add get_dram_base() helper function

arch/x86/boot/compressed/eboot.c | 3 +-
drivers/firmware/efi/efi-stub-helper.c | 148 +++++++++++++++++++++++---------
include/linux/efi.h | 6 ++
3 files changed, 116 insertions(+), 41 deletions(-)

--
1.7.10.4


2014-04-04 12:26:55

by Leif Lindholm

[permalink] [raw]
Subject: [PATCH 3/5] efi: x86: Improve cmdline conversion

From: "H. Peter Anvin" <[email protected]>

Improve the conversion of the UTF-16 EFI command line
to UTF-8 for passing to the kernel.

Signed-off-by: Roy Franz <[email protected]>
Signed-off-by: H. Peter Anvin <[email protected]>
Signed-off-by: Leif Lindholm <[email protected]>
---
arch/x86/boot/compressed/eboot.c | 3 +-
drivers/firmware/efi/efi-stub-helper.c | 91 ++++++++++++++++++++++++--------
2 files changed, 70 insertions(+), 24 deletions(-)

diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 1e61461..255d2aa 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -1086,8 +1086,7 @@ struct boot_params *make_boot_params(struct efi_config *c)
hdr->type_of_loader = 0x21;

/* Convert unicode cmdline to ascii */
- cmdline_ptr = efi_convert_cmdline_to_ascii(sys_table, image,
- &options_size);
+ cmdline_ptr = efi_convert_cmdline(sys_table, image, &options_size);
if (!cmdline_ptr)
goto fail;
hdr->cmd_line_ptr = (unsigned long)cmdline_ptr;
diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 61230cb..3cc5ebe 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -503,52 +503,99 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
}

/*
- * Convert the unicode UEFI command line to ASCII to pass to kernel.
+ * Get the number of UTF-8 bytes corresponding to an UTF-16 character.
+ * This overestimates for surrogates, but that is okay.
+ */
+static int efi_utf8_bytes(u16 c)
+{
+ return 1 + (c >= 0x80) + (c >= 0x800);
+}
+
+/*
+ * Convert an UTF-16 string, not necessarily null terminated, to UTF-8.
+ */
+static u8 *efi_utf16_to_utf8(u8 *dst, const u16 *src, int n)
+{
+ unsigned int c;
+
+ while (n--) {
+ c = *src++;
+ if (n && c >= 0xd800 && c <= 0xdbff &&
+ *src >= 0xdc00 && *src <= 0xdfff) {
+ c = 0x10000 + ((c & 0x3ff) << 10) + (*src & 0x3ff);
+ src++;
+ n--;
+ }
+ if (c >= 0xd800 && c <= 0xdfff)
+ c = 0xfffd; /* Unmatched surrogate */
+ if (c < 0x80) {
+ *dst++ = c;
+ continue;
+ }
+ if (c < 0x800) {
+ *dst++ = 0xc0 + (c >> 6);
+ goto t1;
+ }
+ if (c < 0x10000) {
+ *dst++ = 0xe0 + (c >> 12);
+ goto t2;
+ }
+ *dst++ = 0xf0 + (c >> 18);
+ *dst++ = 0x80 + ((c >> 12) & 0x3f);
+t2:
+ *dst++ = 0x80 + ((c >> 6) & 0x3f);
+t1:
+ *dst++ = 0x80 + (c & 0x3f);
+ }
+
+ return dst;
+}
+
+/*
+ * Do proper conversion from UTF-16 to UTF-8
* Size of memory allocated return in *cmd_line_len.
* Returns NULL on error.
*/
-static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg,
- efi_loaded_image_t *image,
- int *cmd_line_len)
+static char *efi_convert_cmdline(efi_system_table_t *sys_table_arg,
+ efi_loaded_image_t *image,
+ int *cmd_line_len)
{
- u16 *s2;
+ const u16 *s2;
u8 *s1 = NULL;
unsigned long cmdline_addr = 0;
- int load_options_size = image->load_options_size / 2; /* ASCII */
- void *options = image->load_options;
- int options_size = 0;
+ int load_options_chars = image->load_options_size / 2; /* UTF-16 */
+ const u16 *options = image->load_options;
+ int options_bytes = 0; /* UTF-8 bytes */
+ int options_chars = 0; /* UTF-16 chars */
efi_status_t status;
- int i;
u16 zero = 0;

if (options) {
s2 = options;
- while (*s2 && *s2 != '\n' && options_size < load_options_size) {
- s2++;
- options_size++;
+ while (options_chars < load_options_chars
+ && *s2 && *s2 != '\n') {
+ options_bytes += efi_utf8_bytes(*s2++);
+ options_chars++;
}
}

- if (options_size == 0) {
- /* No command line options, so return empty string*/
- options_size = 1;
+ if (!options_chars) {
+ /* No command line options, so return empty string */
options = &zero;
}

- options_size++; /* NUL termination */
+ options_bytes++; /* NUL termination */

- status = efi_low_alloc(sys_table_arg, options_size, 0, &cmdline_addr);
+ status = efi_low_alloc(sys_table_arg, options_bytes, 0, &cmdline_addr);
if (status != EFI_SUCCESS)
return NULL;

s1 = (u8 *)cmdline_addr;
- s2 = (u16 *)options;
-
- for (i = 0; i < options_size - 1; i++)
- *s1++ = *s2++;
+ s2 = (const u16 *)options;

+ s1 = efi_utf16_to_utf8(s1, s2, options_chars);
*s1 = '\0';

- *cmd_line_len = options_size;
+ *cmd_line_len = options_bytes;
return (char *)cmdline_addr;
}
--
1.7.10.4

2014-04-04 12:27:01

by Leif Lindholm

[permalink] [raw]
Subject: [PATCH 2/5] efi: create memory map iteration helper

From: Mark Salter <[email protected]>

There are a lot of places in the kernel which iterate through an
EFI memory map. Most of these places use essentially the same
for-loop code. This patch adds a for_each_efi_memory_desc()
helper to clean up all of the existing duplicate code and avoid
more in the future.

Signed-off-by: Mark Salter <[email protected]>
Signed-off-by: Leif Lindholm <[email protected]>
---
include/linux/efi.h | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/include/linux/efi.h b/include/linux/efi.h
index 6c100ff..82d0abb 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -863,6 +863,12 @@ extern int efi_set_rtc_mmss(const struct timespec *now);
extern void efi_reserve_boot_services(void);
extern struct efi_memory_map memmap;

+/* Iterate through an efi_memory_map */
+#define for_each_efi_memory_desc(m, md) \
+ for ((md) = (m)->map; \
+ (md) <= (efi_memory_desc_t *)((m)->map_end - (m)->desc_size); \
+ (md) = (void *)(md) + (m)->desc_size)
+
/**
* efi_range_is_wc - check the WC bit on an address range
* @start: starting kvirt address
--
1.7.10.4

2014-04-04 12:27:05

by Leif Lindholm

[permalink] [raw]
Subject: [PATCH 5/5] efi: Add get_dram_base() helper function

From: Roy Franz <[email protected]>

Add the get_dram_base() function, shared by arm/arm64.

Signed-off-by: Roy Franz <[email protected]>
Signed-off-by: Leif Lindholm <[email protected]>
---
drivers/firmware/efi/efi-stub-helper.c | 30 ++++++++++++++++++++++++++++++
1 file changed, 30 insertions(+)

diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 183289c..998b884 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -11,6 +11,10 @@
*/
#define EFI_READ_CHUNK_SIZE (1024 * 1024)

+/* error code which can't be mistaken for valid address */
+#define EFI_ERROR (~0UL)
+
+
struct file_info {
efi_file_handle_t *handle;
u64 size;
@@ -83,6 +87,32 @@ fail:
return status;
}

+
+static unsigned long __init get_dram_base(efi_system_table_t *sys_table)
+{
+ efi_status_t status;
+ unsigned long map_size;
+ unsigned long membase = EFI_ERROR;
+ struct efi_memory_map map;
+ efi_memory_desc_t *md;
+
+ status = efi_get_memory_map(sys_table, (efi_memory_desc_t **)&map.map,
+ &map_size, &map.desc_size, NULL, NULL);
+ if (status != EFI_SUCCESS)
+ return membase;
+
+ map.map_end = map.map + map_size;
+
+ for_each_efi_memory_desc(&map, md)
+ if (md->attribute & EFI_MEMORY_WB)
+ if (membase > md->phys_addr)
+ membase = md->phys_addr;
+
+ efi_call_phys1(sys_table->boottime->free_pool, map.map);
+
+ return membase;
+}
+
/*
* Allocate at the highest possible address that is not above 'max'.
*/
--
1.7.10.4

2014-04-04 12:26:53

by Leif Lindholm

[permalink] [raw]
Subject: [PATCH 4/5] efi: Add shared printk wrapper for consistent prefixing

From: Roy Franz <[email protected]>

Add a wrapper for printk to standardize the prefix for informational and
error messages from the EFI stub.

Signed-off-by: Roy Franz <[email protected]>
Signed-off-by: Leif Lindholm <[email protected]>
---
drivers/firmware/efi/efi-stub-helper.c | 13 ++++++++-----
1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index 3cc5ebe..183289c 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -33,6 +33,9 @@ static void efi_printk(efi_system_table_t *sys_table_arg, char *str)
}
}

+#define pr_efi(sys_table, msg) efi_printk(sys_table, "EFI stub: "msg)
+#define pr_efi_err(sys_table, msg) efi_printk(sys_table, "EFI stub: ERROR: "msg)
+

static efi_status_t efi_get_memory_map(efi_system_table_t *sys_table_arg,
efi_memory_desc_t **map,
@@ -310,7 +313,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
status = efi_call_early(allocate_pool, EFI_LOADER_DATA,
nr_files * sizeof(*files), (void **)&files);
if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "Failed to alloc mem for file handle list\n");
+ pr_efi_err(sys_table_arg, "Failed to alloc mem for file handle list\n");
goto fail;
}

@@ -374,13 +377,13 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
status = efi_high_alloc(sys_table_arg, file_size_total, 0x1000,
&file_addr, max_addr);
if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "Failed to alloc highmem for files\n");
+ pr_efi_err(sys_table_arg, "Failed to alloc highmem for files\n");
goto close_handles;
}

/* We've run out of free low memory. */
if (file_addr > max_addr) {
- efi_printk(sys_table_arg, "We've run out of free low memory\n");
+ pr_efi_err(sys_table_arg, "We've run out of free low memory\n");
status = EFI_INVALID_PARAMETER;
goto free_file_total;
}
@@ -401,7 +404,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
&chunksize,
(void *)addr);
if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "Failed to read file\n");
+ pr_efi_err(sys_table_arg, "Failed to read file\n");
goto free_file_total;
}
addr += chunksize;
@@ -486,7 +489,7 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
&new_addr);
}
if (status != EFI_SUCCESS) {
- efi_printk(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n");
+ pr_efi_err(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n");
return status;
}

--
1.7.10.4

2014-04-04 12:28:37

by Leif Lindholm

[permalink] [raw]
Subject: [PATCH 1/5] efi: efi-stub-helper cleanup

An #ifdef CONFIG_ARM clause in efi-stub-helper.c got included with some
of the generic stub rework by Roy Franz. Drop it here to make subsequent
patches less confusing.

Also, In handle_cmdline_files(), fh is not initialized, and while the
overall logic around this handling appears safe, gcc does not always
pick this up. Initialize to NULL to remove the resulting warning.

Signed-off-by: Leif Lindholm <[email protected]>
---
drivers/firmware/efi/efi-stub-helper.c | 16 +++-------------
1 file changed, 3 insertions(+), 13 deletions(-)

diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
index ff50aee..61230cb 100644
--- a/drivers/firmware/efi/efi-stub-helper.c
+++ b/drivers/firmware/efi/efi-stub-helper.c
@@ -267,7 +267,7 @@ static efi_status_t handle_cmdline_files(efi_system_table_t *sys_table_arg,
struct file_info *files;
unsigned long file_addr;
u64 file_size_total;
- efi_file_handle_t *fh;
+ efi_file_handle_t *fh = NULL;
efi_status_t status;
int nr_files;
char *str;
@@ -536,18 +536,8 @@ static char *efi_convert_cmdline_to_ascii(efi_system_table_t *sys_table_arg,
}

options_size++; /* NUL termination */
-#ifdef CONFIG_ARM
- /*
- * For ARM, allocate at a high address to avoid reserved
- * regions at low addresses that we don't know the specfics of
- * at the time we are processing the command line.
- */
- status = efi_high_alloc(sys_table_arg, options_size, 0,
- &cmdline_addr, 0xfffff000);
-#else
- status = efi_low_alloc(sys_table_arg, options_size, 0,
- &cmdline_addr);
-#endif
+
+ status = efi_low_alloc(sys_table_arg, options_size, 0, &cmdline_addr);
if (status != EFI_SUCCESS)
return NULL;

--
1.7.10.4

2014-04-04 14:31:55

by Joe Perches

[permalink] [raw]
Subject: Re: [PATCH 4/5] efi: Add shared printk wrapper for consistent prefixing

On Fri, 2014-04-04 at 13:25 +0100, Leif Lindholm wrote:
> Add a wrapper for printk to standardize the prefix for informational and
> error messages from the EFI stub.
[]
> diff --git a/drivers/firmware/efi/efi-stub-helper.c b/drivers/firmware/efi/efi-stub-helper.c
[]
> @@ -33,6 +33,9 @@ static void efi_printk(efi_system_table_t *sys_table_arg, char *str)
[]
> +#define pr_efi(sys_table, msg) efi_printk(sys_table, "EFI stub: "msg)
> +#define pr_efi_err(sys_table, msg) efi_printk(sys_table, "EFI stub: ERROR: "msg)
[]
> @@ -486,7 +489,7 @@ static efi_status_t efi_relocate_kernel(efi_system_table_t *sys_table_arg,
> &new_addr);
> }
> if (status != EFI_SUCCESS) {
> - efi_printk(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n");
> + pr_efi_err(sys_table_arg, "ERROR: Failed to allocate usable memory for kernel.\n");

Author! Author! "ERROR: ERROR:"!

One too many "ERROR:" prefixes.

2014-04-07 13:19:25

by Matt Fleming

[permalink] [raw]
Subject: Re: [PATCH 3/5] efi: x86: Improve cmdline conversion

On Fri, 04 Apr, at 01:25:48PM, Leif Lindholm wrote:
> From: "H. Peter Anvin" <[email protected]>
>
> Improve the conversion of the UTF-16 EFI command line
> to UTF-8 for passing to the kernel.
>
> Signed-off-by: Roy Franz <[email protected]>
> Signed-off-by: H. Peter Anvin <[email protected]>
> Signed-off-by: Leif Lindholm <[email protected]>

This Signed-off-by chain looks a little wonky because it reads as though
the patch was sent by Roy to Peter, who sent it to Leif. Not only that,
I don't have a record of Peter using his zytor.com account to submit
this patch, only his linux.intel.com address.

*rummage* *rummage*.... this is what I have in my inbox,

From 7d6cf630c1adbb9787a24c2994230373c2b20a8f Mon Sep 17 00:00:00 2001
From: "H. Peter Anvin" <[email protected]>
Date: Fri, 20 Sep 2013 09:55:39 -0500
Subject: [PATCH] efi: Handle arbitrary Unicode characters

Instead of truncating UTF-16 assuming all characters is ASCII,
properly convert it to UTF-8.

Signed-off-by: H. Peter Anvin <[email protected]>
---
arch/x86/boot/compressed/eboot.c | 3 +-
drivers/firmware/efi/efi-stub-helper.c | 89 ++++++++++++++++++++++++++--------
2 files changed, 71 insertions(+), 21 deletions(-)

It looks like some unnecessary patch munging has gone on here. Now if
Roy has modified Peter's patch in some way, that's fine, but it needs to
be called out in the SoB chain, e.g.

Signed-off-by: H. Peter Anvin <[email protected]>
[ Add func foobar() and refactored code for XXX ]
Signed-off-by: Roy Franz <[email protected]>
Signed-off-by: Leif Lindholm <[email protected]>

Make sense?

--
Matt Fleming, Intel Open Source Technology Center

2014-04-07 13:23:04

by Matt Fleming

[permalink] [raw]
Subject: Re: [PATCH 0/5] Non-ARM-specific EFI patches needed for ARM ports

On Fri, 04 Apr, at 01:25:45PM, Leif Lindholm wrote:
> This is the set of patches from the arm/arm64 UEFI support that are not
> in fact architecture specific. This set depends on other EFI patches
> already in linux-next.
>
> H. Peter Anvin (1):
> efi: x86: Improve cmdline conversion
>
> Leif Lindholm (1):
> efi: efi-stub-helper cleanup
>
> Mark Salter (1):
> efi: create memory map iteration helper
>
> Roy Franz (2):
> efi: Add shared printk wrapper for consistent prefixing
> efi: Add get_dram_base() helper function
>
> arch/x86/boot/compressed/eboot.c | 3 +-
> drivers/firmware/efi/efi-stub-helper.c | 148 +++++++++++++++++++++++---------
> include/linux/efi.h | 6 ++
> 3 files changed, 116 insertions(+), 41 deletions(-)

Thanks Leif, I'll pick these up once the comments to PATCH 3 and PATCH 4
(from Joe) are addressed. Otherwise they look fine.

--
Matt Fleming, Intel Open Source Technology Center