diff options
| author | Matthew Garrett <matthew.garrett@nebula.com> | 2013-04-15 16:09:45 -0400 |
|---|---|---|
| committer | Matt Fleming <matt.fleming@intel.com> | 2013-04-15 16:23:03 -0400 |
| commit | 0635eb8a54cf0fea64b174bb68bc36b9c3d622db (patch) | |
| tree | 9430096d286e5da9044ab7e6cb85bdaca07c9717 | |
| parent | 7791c8423f1f7f4dad94e753bae67461d5b80be8 (diff) | |
Move utf16 functions to kernel core and rename
We want to be able to use the utf16 functions that are currently present
in the EFI variables code in platform-specific code as well. Move them to
the kernel core, and in the process rename them to accurately describe what
they do - they don't handle UTF16, only UCS2.
Signed-off-by: Matthew Garrett <matthew.garrett@nebula.com>
Signed-off-by: Matt Fleming <matt.fleming@intel.com>
| -rw-r--r-- | drivers/firmware/Kconfig | 1 | ||||
| -rw-r--r-- | drivers/firmware/efivars.c | 80 | ||||
| -rw-r--r-- | include/linux/ucs2_string.h | 14 | ||||
| -rw-r--r-- | lib/Kconfig | 3 | ||||
| -rw-r--r-- | lib/Makefile | 2 | ||||
| -rw-r--r-- | lib/ucs2_string.c | 51 |
6 files changed, 89 insertions, 62 deletions
diff --git a/drivers/firmware/Kconfig b/drivers/firmware/Kconfig index 42c759a4d047..3e532002e4d1 100644 --- a/drivers/firmware/Kconfig +++ b/drivers/firmware/Kconfig | |||
| @@ -39,6 +39,7 @@ config FIRMWARE_MEMMAP | |||
| 39 | config EFI_VARS | 39 | config EFI_VARS |
| 40 | tristate "EFI Variable Support via sysfs" | 40 | tristate "EFI Variable Support via sysfs" |
| 41 | depends on EFI | 41 | depends on EFI |
| 42 | select UCS2_STRING | ||
| 42 | default n | 43 | default n |
| 43 | help | 44 | help |
| 44 | If you say Y here, you are able to get EFI (Extensible Firmware | 45 | If you say Y here, you are able to get EFI (Extensible Firmware |
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c index bf15d81d74e1..182ce9471175 100644 --- a/drivers/firmware/efivars.c +++ b/drivers/firmware/efivars.c | |||
| @@ -80,6 +80,7 @@ | |||
| 80 | #include <linux/slab.h> | 80 | #include <linux/slab.h> |
| 81 | #include <linux/pstore.h> | 81 | #include <linux/pstore.h> |
| 82 | #include <linux/ctype.h> | 82 | #include <linux/ctype.h> |
| 83 | #include <linux/ucs2_string.h> | ||
| 83 | 84 | ||
| 84 | #include <linux/fs.h> | 85 | #include <linux/fs.h> |
| 85 | #include <linux/ramfs.h> | 86 | #include <linux/ramfs.h> |
| @@ -172,51 +173,6 @@ static void efivar_update_sysfs_entries(struct work_struct *); | |||
| 172 | static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries); | 173 | static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries); |
| 173 | static bool efivar_wq_enabled = true; | 174 | static bool efivar_wq_enabled = true; |
| 174 | 175 | ||
| 175 | /* Return the number of unicode characters in data */ | ||
| 176 | static unsigned long | ||
| 177 | utf16_strnlen(efi_char16_t *s, size_t maxlength) | ||
| 178 | { | ||
| 179 | unsigned long length = 0; | ||
| 180 | |||
| 181 | while (*s++ != 0 && length < maxlength) | ||
| 182 | length++; | ||
| 183 | return length; | ||
| 184 | } | ||
| 185 | |||
| 186 | static inline unsigned long | ||
| 187 | utf16_strlen(efi_char16_t *s) | ||
| 188 | { | ||
| 189 | return utf16_strnlen(s, ~0UL); | ||
| 190 | } | ||
| 191 | |||
| 192 | /* | ||
| 193 | * Return the number of bytes is the length of this string | ||
| 194 | * Note: this is NOT the same as the number of unicode characters | ||
| 195 | */ | ||
| 196 | static inline unsigned long | ||
| 197 | utf16_strsize(efi_char16_t *data, unsigned long maxlength) | ||
| 198 | { | ||
| 199 | return utf16_strnlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t); | ||
| 200 | } | ||
| 201 | |||
| 202 | static inline int | ||
| 203 | utf16_strncmp(const efi_char16_t *a, const efi_char16_t *b, size_t len) | ||
| 204 | { | ||
| 205 | while (1) { | ||
| 206 | if (len == 0) | ||
| 207 | return 0; | ||
| 208 | if (*a < *b) | ||
| 209 | return -1; | ||
| 210 | if (*a > *b) | ||
| 211 | return 1; | ||
| 212 | if (*a == 0) /* implies *b == 0 */ | ||
| 213 | return 0; | ||
| 214 | a++; | ||
| 215 | b++; | ||
| 216 | len--; | ||
| 217 | } | ||
| 218 | } | ||
| 219 | |||
| 220 | static bool | 176 | static bool |
| 221 | validate_device_path(struct efi_variable *var, int match, u8 *buffer, | 177 | validate_device_path(struct efi_variable *var, int match, u8 *buffer, |
| 222 | unsigned long len) | 178 | unsigned long len) |
| @@ -268,7 +224,7 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer, | |||
| 268 | u16 filepathlength; | 224 | u16 filepathlength; |
| 269 | int i, desclength = 0, namelen; | 225 | int i, desclength = 0, namelen; |
| 270 | 226 | ||
| 271 | namelen = utf16_strnlen(var->VariableName, sizeof(var->VariableName)); | 227 | namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName)); |
| 272 | 228 | ||
| 273 | /* Either "Boot" or "Driver" followed by four digits of hex */ | 229 | /* Either "Boot" or "Driver" followed by four digits of hex */ |
| 274 | for (i = match; i < match+4; i++) { | 230 | for (i = match; i < match+4; i++) { |
| @@ -291,7 +247,7 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer, | |||
| 291 | * There's no stored length for the description, so it has to be | 247 | * There's no stored length for the description, so it has to be |
| 292 | * found by hand | 248 | * found by hand |
| 293 | */ | 249 | */ |
| 294 | desclength = utf16_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2; | 250 | desclength = ucs2_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2; |
| 295 | 251 | ||
| 296 | /* Each boot entry must have a descriptor */ | 252 | /* Each boot entry must have a descriptor */ |
| 297 | if (!desclength) | 253 | if (!desclength) |
| @@ -581,7 +537,7 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count) | |||
| 581 | spin_lock_irq(&efivars->lock); | 537 | spin_lock_irq(&efivars->lock); |
| 582 | 538 | ||
| 583 | status = check_var_size_locked(efivars, new_var->Attributes, | 539 | status = check_var_size_locked(efivars, new_var->Attributes, |
| 584 | new_var->DataSize + utf16_strsize(new_var->VariableName, 1024)); | 540 | new_var->DataSize + ucs2_strsize(new_var->VariableName, 1024)); |
| 585 | 541 | ||
| 586 | if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED) | 542 | if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED) |
| 587 | status = efivars->ops->set_variable(new_var->VariableName, | 543 | status = efivars->ops->set_variable(new_var->VariableName, |
| @@ -759,7 +715,7 @@ static ssize_t efivarfs_file_write(struct file *file, | |||
| 759 | * QueryVariableInfo() isn't supported by the firmware. | 715 | * QueryVariableInfo() isn't supported by the firmware. |
| 760 | */ | 716 | */ |
| 761 | 717 | ||
| 762 | varsize = datasize + utf16_strsize(var->var.VariableName, 1024); | 718 | varsize = datasize + ucs2_strsize(var->var.VariableName, 1024); |
| 763 | status = check_var_size(efivars, attributes, varsize); | 719 | status = check_var_size(efivars, attributes, varsize); |
| 764 | 720 | ||
| 765 | if (status != EFI_SUCCESS) { | 721 | if (status != EFI_SUCCESS) { |
| @@ -1211,7 +1167,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) | |||
| 1211 | 1167 | ||
| 1212 | inode = NULL; | 1168 | inode = NULL; |
| 1213 | 1169 | ||
| 1214 | len = utf16_strlen(entry->var.VariableName); | 1170 | len = ucs2_strlen(entry->var.VariableName); |
| 1215 | 1171 | ||
| 1216 | /* name, plus '-', plus GUID, plus NUL*/ | 1172 | /* name, plus '-', plus GUID, plus NUL*/ |
| 1217 | name = kmalloc(len + 1 + GUID_LEN + 1, GFP_ATOMIC); | 1173 | name = kmalloc(len + 1 + GUID_LEN + 1, GFP_ATOMIC); |
| @@ -1469,8 +1425,8 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | |||
| 1469 | 1425 | ||
| 1470 | if (efi_guidcmp(entry->var.VendorGuid, vendor)) | 1426 | if (efi_guidcmp(entry->var.VendorGuid, vendor)) |
| 1471 | continue; | 1427 | continue; |
| 1472 | if (utf16_strncmp(entry->var.VariableName, efi_name, | 1428 | if (ucs2_strncmp(entry->var.VariableName, efi_name, |
| 1473 | utf16_strlen(efi_name))) { | 1429 | ucs2_strlen(efi_name))) { |
| 1474 | /* | 1430 | /* |
| 1475 | * Check if an old format, | 1431 | * Check if an old format, |
| 1476 | * which doesn't support holding | 1432 | * which doesn't support holding |
| @@ -1482,8 +1438,8 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count, | |||
| 1482 | for (i = 0; i < DUMP_NAME_LEN; i++) | 1438 | for (i = 0; i < DUMP_NAME_LEN; i++) |
| 1483 | efi_name_old[i] = name_old[i]; | 1439 | efi_name_old[i] = name_old[i]; |
| 1484 | 1440 | ||
| 1485 | if (utf16_strncmp(entry->var.VariableName, efi_name_old, | 1441 | if (ucs2_strncmp(entry->var.VariableName, efi_name_old, |
| 1486 | utf16_strlen(efi_name_old))) | 1442 | ucs2_strlen(efi_name_old))) |
| 1487 | continue; | 1443 | continue; |
| 1488 | } | 1444 | } |
| 1489 | 1445 | ||
| @@ -1561,8 +1517,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | |||
| 1561 | * Does this variable already exist? | 1517 | * Does this variable already exist? |
| 1562 | */ | 1518 | */ |
| 1563 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { | 1519 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { |
| 1564 | strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); | 1520 | strsize1 = ucs2_strsize(search_efivar->var.VariableName, 1024); |
| 1565 | strsize2 = utf16_strsize(new_var->VariableName, 1024); | 1521 | strsize2 = ucs2_strsize(new_var->VariableName, 1024); |
| 1566 | if (strsize1 == strsize2 && | 1522 | if (strsize1 == strsize2 && |
| 1567 | !memcmp(&(search_efivar->var.VariableName), | 1523 | !memcmp(&(search_efivar->var.VariableName), |
| 1568 | new_var->VariableName, strsize1) && | 1524 | new_var->VariableName, strsize1) && |
| @@ -1578,7 +1534,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | |||
| 1578 | } | 1534 | } |
| 1579 | 1535 | ||
| 1580 | status = check_var_size_locked(efivars, new_var->Attributes, | 1536 | status = check_var_size_locked(efivars, new_var->Attributes, |
| 1581 | new_var->DataSize + utf16_strsize(new_var->VariableName, 1024)); | 1537 | new_var->DataSize + ucs2_strsize(new_var->VariableName, 1024)); |
| 1582 | 1538 | ||
| 1583 | if (status && status != EFI_UNSUPPORTED) { | 1539 | if (status && status != EFI_UNSUPPORTED) { |
| 1584 | spin_unlock_irq(&efivars->lock); | 1540 | spin_unlock_irq(&efivars->lock); |
| @@ -1602,7 +1558,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj, | |||
| 1602 | 1558 | ||
| 1603 | /* Create the entry in sysfs. Locking is not required here */ | 1559 | /* Create the entry in sysfs. Locking is not required here */ |
| 1604 | status = efivar_create_sysfs_entry(efivars, | 1560 | status = efivar_create_sysfs_entry(efivars, |
| 1605 | utf16_strsize(new_var->VariableName, | 1561 | ucs2_strsize(new_var->VariableName, |
| 1606 | 1024), | 1562 | 1024), |
| 1607 | new_var->VariableName, | 1563 | new_var->VariableName, |
| 1608 | &new_var->VendorGuid); | 1564 | &new_var->VendorGuid); |
| @@ -1632,8 +1588,8 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj, | |||
| 1632 | * Does this variable already exist? | 1588 | * Does this variable already exist? |
| 1633 | */ | 1589 | */ |
| 1634 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { | 1590 | list_for_each_entry_safe(search_efivar, n, &efivars->list, list) { |
| 1635 | strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024); | 1591 | strsize1 = ucs2_strsize(search_efivar->var.VariableName, 1024); |
| 1636 | strsize2 = utf16_strsize(del_var->VariableName, 1024); | 1592 | strsize2 = ucs2_strsize(del_var->VariableName, 1024); |
| 1637 | if (strsize1 == strsize2 && | 1593 | if (strsize1 == strsize2 && |
| 1638 | !memcmp(&(search_efivar->var.VariableName), | 1594 | !memcmp(&(search_efivar->var.VariableName), |
| 1639 | del_var->VariableName, strsize1) && | 1595 | del_var->VariableName, strsize1) && |
| @@ -1679,9 +1635,9 @@ static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor) | |||
| 1679 | unsigned long strsize1, strsize2; | 1635 | unsigned long strsize1, strsize2; |
| 1680 | bool found = false; | 1636 | bool found = false; |
| 1681 | 1637 | ||
| 1682 | strsize1 = utf16_strsize(variable_name, 1024); | 1638 | strsize1 = ucs2_strsize(variable_name, 1024); |
| 1683 | list_for_each_entry_safe(entry, n, &efivars->list, list) { | 1639 | list_for_each_entry_safe(entry, n, &efivars->list, list) { |
| 1684 | strsize2 = utf16_strsize(entry->var.VariableName, 1024); | 1640 | strsize2 = ucs2_strsize(entry->var.VariableName, 1024); |
| 1685 | if (strsize1 == strsize2 && | 1641 | if (strsize1 == strsize2 && |
| 1686 | !memcmp(variable_name, &(entry->var.VariableName), | 1642 | !memcmp(variable_name, &(entry->var.VariableName), |
| 1687 | strsize2) && | 1643 | strsize2) && |
diff --git a/include/linux/ucs2_string.h b/include/linux/ucs2_string.h new file mode 100644 index 000000000000..cbb20afdbc01 --- /dev/null +++ b/include/linux/ucs2_string.h | |||
| @@ -0,0 +1,14 @@ | |||
| 1 | #ifndef _LINUX_UCS2_STRING_H_ | ||
| 2 | #define _LINUX_UCS2_STRING_H_ | ||
| 3 | |||
| 4 | #include <linux/types.h> /* for size_t */ | ||
| 5 | #include <linux/stddef.h> /* for NULL */ | ||
| 6 | |||
| 7 | typedef u16 ucs2_char_t; | ||
| 8 | |||
| 9 | unsigned long ucs2_strnlen(const ucs2_char_t *s, size_t maxlength); | ||
| 10 | unsigned long ucs2_strlen(const ucs2_char_t *s); | ||
| 11 | unsigned long ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength); | ||
| 12 | int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len); | ||
| 13 | |||
| 14 | #endif /* _LINUX_UCS2_STRING_H_ */ | ||
diff --git a/lib/Kconfig b/lib/Kconfig index 3958dc4389f9..fe01d418b09a 100644 --- a/lib/Kconfig +++ b/lib/Kconfig | |||
| @@ -404,4 +404,7 @@ config OID_REGISTRY | |||
| 404 | help | 404 | help |
| 405 | Enable fast lookup object identifier registry. | 405 | Enable fast lookup object identifier registry. |
| 406 | 406 | ||
| 407 | config UCS2_STRING | ||
| 408 | tristate | ||
| 409 | |||
| 407 | endmenu | 410 | endmenu |
diff --git a/lib/Makefile b/lib/Makefile index d7946ff75b2e..6e2cc561f761 100644 --- a/lib/Makefile +++ b/lib/Makefile | |||
| @@ -174,3 +174,5 @@ quiet_cmd_build_OID_registry = GEN $@ | |||
| 174 | cmd_build_OID_registry = perl $(srctree)/$(src)/build_OID_registry $< $@ | 174 | cmd_build_OID_registry = perl $(srctree)/$(src)/build_OID_registry $< $@ |
| 175 | 175 | ||
| 176 | clean-files += oid_registry_data.c | 176 | clean-files += oid_registry_data.c |
| 177 | |||
| 178 | obj-$(CONFIG_UCS2_STRING) += ucs2_string.o | ||
diff --git a/lib/ucs2_string.c b/lib/ucs2_string.c new file mode 100644 index 000000000000..6f500ef2301d --- /dev/null +++ b/lib/ucs2_string.c | |||
| @@ -0,0 +1,51 @@ | |||
| 1 | #include <linux/ucs2_string.h> | ||
| 2 | #include <linux/module.h> | ||
| 3 | |||
| 4 | /* Return the number of unicode characters in data */ | ||
| 5 | unsigned long | ||
| 6 | ucs2_strnlen(const ucs2_char_t *s, size_t maxlength) | ||
| 7 | { | ||
| 8 | unsigned long length = 0; | ||
| 9 | |||
| 10 | while (*s++ != 0 && length < maxlength) | ||
| 11 | length++; | ||
| 12 | return length; | ||
| 13 | } | ||
| 14 | EXPORT_SYMBOL(ucs2_strnlen); | ||
| 15 | |||
| 16 | unsigned long | ||
| 17 | ucs2_strlen(const ucs2_char_t *s) | ||
| 18 | { | ||
| 19 | return ucs2_strnlen(s, ~0UL); | ||
| 20 | } | ||
| 21 | EXPORT_SYMBOL(ucs2_strlen); | ||
| 22 | |||
| 23 | /* | ||
| 24 | * Return the number of bytes is the length of this string | ||
| 25 | * Note: this is NOT the same as the number of unicode characters | ||
| 26 | */ | ||
| 27 | unsigned long | ||
| 28 | ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength) | ||
| 29 | { | ||
| 30 | return ucs2_strnlen(data, maxlength/sizeof(ucs2_char_t)) * sizeof(ucs2_char_t); | ||
| 31 | } | ||
| 32 | EXPORT_SYMBOL(ucs2_strsize); | ||
| 33 | |||
| 34 | int | ||
| 35 | ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len) | ||
| 36 | { | ||
| 37 | while (1) { | ||
| 38 | if (len == 0) | ||
| 39 | return 0; | ||
| 40 | if (*a < *b) | ||
| 41 | return -1; | ||
| 42 | if (*a > *b) | ||
| 43 | return 1; | ||
| 44 | if (*a == 0) /* implies *b == 0 */ | ||
| 45 | return 0; | ||
| 46 | a++; | ||
| 47 | b++; | ||
| 48 | len--; | ||
| 49 | } | ||
| 50 | } | ||
| 51 | EXPORT_SYMBOL(ucs2_strncmp); | ||
