diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/charset.c | 25 | ||||
-rw-r--r-- | lib/efi_loader/efi_boottime.c | 26 | ||||
-rw-r--r-- | lib/efi_loader/efi_device_path.c | 33 | ||||
-rw-r--r-- | lib/efi_loader/efi_variable.c | 70 | ||||
-rw-r--r-- | lib/efi_selftest/efi_selftest_variables.c | 20 |
5 files changed, 135 insertions, 39 deletions
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; |