summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2019-09-21 07:31:23 -0400
committerTom Rini <trini@konsulko.com>2019-09-21 07:31:23 -0400
commit390183b58179ddaf986422f4d9446c596660f7e0 (patch)
treed2401285ea91806eeac338eeaf721d855c896f4b
parentd6c7309f561ac832c080e5ec07b0af9c8da319a8 (diff)
parent79907a4f8429aef161add59b3d026cf2c734c1aa (diff)
downloadu-boot-WIP/21Sep2019.tar.gz
Merge tag 'efi-2019-10-rc4-5' of https://gitlab.denx.de/u-boot/custodians/u-boot-efiWIP/21Sep2019
Pull request for UEFI sub-system for v2019.10-rc4 (5) This patch set fixes errors in the UEFI sub-system and adds a function to compare u16 strings which is prerequisite for further patches.
-rw-r--r--include/charset.h15
-rw-r--r--include/efi_loader.h8
-rw-r--r--lib/charset.c25
-rw-r--r--lib/efi_loader/efi_boottime.c26
-rw-r--r--lib/efi_loader/efi_device_path.c33
-rw-r--r--lib/efi_loader/efi_variable.c70
-rw-r--r--lib/efi_selftest/efi_selftest_variables.c20
-rw-r--r--test/unicode_ut.c13
8 files changed, 171 insertions, 39 deletions
diff --git a/include/charset.h b/include/charset.h
index 020f8a90df..fde6bddbc2 100644
--- a/include/charset.h
+++ b/include/charset.h
@@ -168,6 +168,21 @@ s32 utf_to_lower(const s32 code);
*/
s32 utf_to_upper(const s32 code);
+/*
+ * u16_strncmp() - compare two u16 string
+ *
+ * @s1: first string to compare
+ * @s2: second string to compare
+ * @n: maximum number of u16 to compare
+ * Return: 0 if the first n u16 are the same in s1 and s2
+ * < 0 if the first different u16 in s1 is less than the
+ * corresponding u16 in s2
+ * > 0 if the first different u16 in s1 is greater than the
+ * corresponding u16 in s2
+ */
+int u16_strncmp(const u16 *s1, const u16 *s2, size_t n);
+#define u16_strcmp(s1, s2) u16_strncmp((s1), (s2), SIZE_MAX)
+
/**
* u16_strlen - count non-zero words
*
diff --git a/include/efi_loader.h b/include/efi_loader.h
index dd24a2746c..53b369945b 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -24,6 +24,10 @@
#define U_BOOT_GUID \
EFI_GUID(0xe61d73b9, 0xa384, 0x4acc, \
0xae, 0xab, 0x82, 0xe8, 0x28, 0xf3, 0x62, 0x8b)
+/* GUID used as host device on sandbox */
+#define U_BOOT_HOST_DEV_GUID \
+ EFI_GUID(0xbbe4e671, 0x5773, 0x4ea1, \
+ 0x9a, 0xab, 0x3a, 0x7d, 0xbf, 0x40, 0xc4, 0x82)
/* Root node */
extern efi_handle_t efi_root;
@@ -121,6 +125,10 @@ uint16_t *efi_dp_str(struct efi_device_path *dp);
/* GUID of the U-Boot root node */
extern const efi_guid_t efi_u_boot_guid;
+#ifdef CONFIG_SANDBOX
+/* GUID of U-Boot host device on sandbox */
+extern const efi_guid_t efi_guid_host_dev;
+#endif
/* GUID of the EFI_BLOCK_IO_PROTOCOL */
extern const efi_guid_t efi_block_io_guid;
extern const efi_guid_t efi_global_variable_guid;
diff --git a/lib/charset.c b/lib/charset.c
index 72d745da4f..1c6a7f693d 100644
--- a/lib/charset.c
+++ b/lib/charset.c
@@ -335,6 +335,31 @@ s32 utf_to_upper(const s32 code)
return ret;
}
+/*
+ * u16_strncmp() - compare two u16 string
+ *
+ * @s1: first string to compare
+ * @s2: second string to compare
+ * @n: maximum number of u16 to compare
+ * Return: 0 if the first n u16 are the same in s1 and s2
+ * < 0 if the first different u16 in s1 is less than the
+ * corresponding u16 in s2
+ * > 0 if the first different u16 in s1 is greater than the
+ * corresponding u16 in s2
+ */
+int u16_strncmp(const u16 *s1, const u16 *s2, size_t n)
+{
+ int ret = 0;
+
+ for (; n; --n, ++s1, ++s2) {
+ ret = *s1 - *s2;
+ if (ret || !*s1)
+ break;
+ }
+
+ return ret;
+}
+
size_t u16_strlen(const void *in)
{
const char *pos = in;
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index b9bff894cb..493d906c64 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -3499,7 +3499,6 @@ static efi_status_t EFIAPI efi_disconnect_controller(
efi_handle_t *child_handle_buffer = NULL;
size_t number_of_children = 0;
efi_status_t r;
- size_t stop_count = 0;
struct efi_object *efiobj;
EFI_ENTRY("%p, %p, %p", controller_handle, driver_image_handle,
@@ -3539,32 +3538,35 @@ static efi_status_t EFIAPI efi_disconnect_controller(
(void **)&binding_protocol,
driver_image_handle, NULL,
EFI_OPEN_PROTOCOL_GET_PROTOCOL));
- if (r != EFI_SUCCESS)
+ if (r != EFI_SUCCESS) {
+ r = EFI_INVALID_PARAMETER;
goto out;
+ }
/* Remove the children */
if (number_of_children) {
r = EFI_CALL(binding_protocol->stop(binding_protocol,
controller_handle,
number_of_children,
child_handle_buffer));
- if (r == EFI_SUCCESS)
- ++stop_count;
+ if (r != EFI_SUCCESS) {
+ r = EFI_DEVICE_ERROR;
+ goto out;
+ }
}
/* Remove the driver */
- if (!child_handle)
+ if (!child_handle) {
r = EFI_CALL(binding_protocol->stop(binding_protocol,
controller_handle,
0, NULL));
- if (r == EFI_SUCCESS)
- ++stop_count;
+ if (r != EFI_SUCCESS) {
+ r = EFI_DEVICE_ERROR;
+ goto out;
+ }
+ }
EFI_CALL(efi_close_protocol(driver_image_handle,
&efi_guid_driver_binding_protocol,
driver_image_handle, NULL));
-
- if (stop_count)
- r = EFI_SUCCESS;
- else
- r = EFI_NOT_FOUND;
+ r = EFI_SUCCESS;
out:
if (!child_handle)
free(child_handle_buffer);
diff --git a/lib/efi_loader/efi_device_path.c b/lib/efi_loader/efi_device_path.c
index ea39f13b73..86297bb7c1 100644
--- a/lib/efi_loader/efi_device_path.c
+++ b/lib/efi_loader/efi_device_path.c
@@ -12,8 +12,13 @@
#include <mmc.h>
#include <efi_loader.h>
#include <part.h>
+#include <sandboxblockdev.h>
#include <asm-generic/unaligned.h>
+#ifdef CONFIG_SANDBOX
+const efi_guid_t efi_guid_host_dev = U_BOOT_HOST_DEV_GUID;
+#endif
+
/* template END node: */
static const struct efi_device_path END = {
.type = DEVICE_PATH_TYPE_END,
@@ -446,6 +451,16 @@ static unsigned dp_size(struct udevice *dev)
return dp_size(dev->parent) +
sizeof(struct efi_device_path_sd_mmc_path);
#endif
+#ifdef CONFIG_SANDBOX
+ case UCLASS_ROOT:
+ /*
+ * Sandbox's host device will be represented
+ * as vendor device with extra one byte for
+ * device number
+ */
+ return dp_size(dev->parent)
+ + sizeof(struct efi_device_path_vendor) + 1;
+#endif
default:
return dp_size(dev->parent);
}
@@ -505,6 +520,24 @@ static void *dp_fill(void *buf, struct udevice *dev)
#ifdef CONFIG_BLK
case UCLASS_BLK:
switch (dev->parent->uclass->uc_drv->id) {
+#ifdef CONFIG_SANDBOX
+ case UCLASS_ROOT: {
+ /* stop traversing parents at this point: */
+ struct efi_device_path_vendor *dp = buf;
+ struct blk_desc *desc = dev_get_uclass_platdata(dev);
+
+ dp_fill(buf, dev->parent);
+ dp = buf;
+ ++dp;
+ dp->dp.type = DEVICE_PATH_TYPE_HARDWARE_DEVICE;
+ dp->dp.sub_type = DEVICE_PATH_SUB_TYPE_VENDOR;
+ dp->dp.length = sizeof(*dp) + 1;
+ memcpy(&dp->guid, &efi_guid_host_dev,
+ sizeof(efi_guid_t));
+ dp->vendor_data[0] = desc->devnum;
+ return &dp->vendor_data[1];
+ }
+#endif
#ifdef CONFIG_IDE
case UCLASS_IDE: {
struct efi_device_path_atapi *dp =
diff --git a/lib/efi_loader/efi_variable.c b/lib/efi_loader/efi_variable.c
index 6687b69a40..48ee255f87 100644
--- a/lib/efi_loader/efi_variable.c
+++ b/lib/efi_loader/efi_variable.c
@@ -424,17 +424,17 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
efi_uintn_t data_size, const void *data)
{
char *native_name = NULL, *val = NULL, *s;
+ const char *old_val;
+ size_t old_size;
efi_status_t ret = EFI_SUCCESS;
u32 attr;
EFI_ENTRY("\"%ls\" %pUl %x %zu %p", variable_name, vendor, attributes,
data_size, data);
- /* TODO: implement APPEND_WRITE */
if (!variable_name || !*variable_name || !vendor ||
((attributes & EFI_VARIABLE_RUNTIME_ACCESS) &&
- !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS)) ||
- (attributes & EFI_VARIABLE_APPEND_WRITE)) {
+ !(attributes & EFI_VARIABLE_BOOTSERVICE_ACCESS))) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
@@ -445,35 +445,51 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
#define ACCESS_ATTR (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)
- if ((data_size == 0) || !(attributes & ACCESS_ATTR)) {
- /* delete the variable: */
- env_set(native_name, NULL);
- ret = EFI_SUCCESS;
- goto out;
- }
+ old_val = env_get(native_name);
+ if (old_val) {
+ old_val = parse_attr(old_val, &attr);
- val = env_get(native_name);
- if (val) {
- parse_attr(val, &attr);
-
- /* We should not free val */
- val = NULL;
+ /* check read-only first */
if (attr & READ_ONLY) {
ret = EFI_WRITE_PROTECTED;
goto out;
}
- /*
- * attributes won't be changed
- * TODO: take care of APPEND_WRITE once supported
- */
- if (attr != attributes) {
+ if ((data_size == 0) || !(attributes & ACCESS_ATTR)) {
+ /* delete the variable: */
+ env_set(native_name, NULL);
+ ret = EFI_SUCCESS;
+ goto out;
+ }
+
+ /* attributes won't be changed */
+ if (attr != (attributes & ~EFI_VARIABLE_APPEND_WRITE)) {
ret = EFI_INVALID_PARAMETER;
goto out;
}
+
+ if (attributes & EFI_VARIABLE_APPEND_WRITE) {
+ if (!prefix(old_val, "(blob)")) {
+ return EFI_DEVICE_ERROR;
+ goto out;
+ }
+ old_size = strlen(old_val);
+ } else {
+ old_size = 0;
+ }
+ } else {
+ if ((data_size == 0) || !(attributes & ACCESS_ATTR) ||
+ (attributes & EFI_VARIABLE_APPEND_WRITE)) {
+ /* delete, but nothing to do */
+ ret = EFI_NOT_FOUND;
+ goto out;
+ }
+
+ old_size = 0;
}
- val = malloc(2 * data_size + strlen("{ro,run,boot,nv}(blob)") + 1);
+ val = malloc(old_size + 2 * data_size
+ + strlen("{ro,run,boot,nv}(blob)") + 1);
if (!val) {
ret = EFI_OUT_OF_RESOURCES;
goto out;
@@ -481,10 +497,7 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
s = val;
- /*
- * store attributes
- * TODO: several attributes are not supported
- */
+ /* store attributes */
attributes &= (EFI_VARIABLE_NON_VOLATILE |
EFI_VARIABLE_BOOTSERVICE_ACCESS |
EFI_VARIABLE_RUNTIME_ACCESS);
@@ -505,8 +518,13 @@ efi_status_t EFIAPI efi_set_variable(u16 *variable_name,
}
s += sprintf(s, "}");
+ if (old_size)
+ /* APPEND_WRITE */
+ s += sprintf(s, old_val);
+ else
+ s += sprintf(s, "(blob)");
+
/* store payload: */
- s += sprintf(s, "(blob)");
s = bin2hex(s, data, data_size);
*s = '\0';
diff --git a/lib/efi_selftest/efi_selftest_variables.c b/lib/efi_selftest/efi_selftest_variables.c
index 06c1a032dd..a6b41d1f00 100644
--- a/lib/efi_selftest/efi_selftest_variables.c
+++ b/lib/efi_selftest/efi_selftest_variables.c
@@ -21,6 +21,9 @@ static const efi_guid_t guid_vendor0 =
static const efi_guid_t guid_vendor1 =
EFI_GUID(0xff629290, 0x1fc1, 0xd73f,
0x8f, 0xb1, 0x32, 0xf9, 0x0c, 0xa0, 0x42, 0xea);
+static const efi_guid_t guid_global =
+ EFI_GUID(0x8be4df61, 0x93ca, 0x11d2,
+ 0xaa, 0x0d, 0x00, 0xe0, 0x98, 0x03, 0x2b, 0x8c);
/*
* Setup unit test.
@@ -116,7 +119,7 @@ static int execute(void)
EFI_VARIABLE_APPEND_WRITE,
7, v + 8);
if (ret != EFI_SUCCESS) {
- efi_st_todo("SetVariable(APPEND_WRITE) failed\n");
+ efi_st_error("SetVariable(APPEND_WRITE) failed\n");
} else {
len = EFI_ST_MAX_DATA_SIZE;
ret = runtime->get_variable(L"efi_st_var1", &guid_vendor1,
@@ -131,6 +134,21 @@ static int execute(void)
if (memcmp(data, v, len))
efi_st_todo("GetVariable returned wrong value\n");
}
+ /* Append variable 2 */
+ ret = runtime->set_variable(L"efi_none", &guid_vendor1,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_APPEND_WRITE,
+ 15, v);
+ if (ret != EFI_NOT_FOUND)
+ efi_st_error("SetVariable(APPEND_WRITE) with size 0 to non-existent variable returns wrong code\n");
+ /* Append variable 3 */
+ ret = runtime->set_variable(L"PlatformLangCodes", &guid_global,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS |
+ EFI_VARIABLE_RUNTIME_ACCESS |
+ EFI_VARIABLE_APPEND_WRITE,
+ 15, v);
+ if (ret != EFI_WRITE_PROTECTED)
+ efi_st_todo("SetVariable(APPEND_WRITE) to read-only variable returns wrong code\n");
/* Enumerate variables */
boottime->set_mem(&guid, 16, 0);
*varname = 0;
diff --git a/test/unicode_ut.c b/test/unicode_ut.c
index 1ccd36e7c9..8875cdc6b2 100644
--- a/test/unicode_ut.c
+++ b/test/unicode_ut.c
@@ -567,6 +567,19 @@ static int unicode_test_utf_to_upper(struct unit_test_state *uts)
}
UNICODE_TEST(unicode_test_utf_to_upper);
+static int unicode_test_u16_strncmp(struct unit_test_state *uts)
+{
+ ut_assert(u16_strncmp(L"abc", L"abc", 3) == 0);
+ ut_assert(u16_strncmp(L"abcdef", L"abcghi", 3) == 0);
+ ut_assert(u16_strncmp(L"abcdef", L"abcghi", 6) < 0);
+ ut_assert(u16_strncmp(L"abcghi", L"abcdef", 6) > 0);
+ ut_assert(u16_strcmp(L"abc", L"abc") == 0);
+ ut_assert(u16_strcmp(L"abcdef", L"deghi") < 0);
+ ut_assert(u16_strcmp(L"deghi", L"abcdef") > 0);
+ return 0;
+}
+UNICODE_TEST(unicode_test_u16_strncmp);
+
int do_ut_unicode(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
struct unit_test *tests = ll_entry_start(struct unit_test, unicode_test);