Skip to content
This repository has been archived by the owner on Aug 27, 2022. It is now read-only.

Commit

Permalink
Move utf16 functions to kernel core and rename
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Matthew Garrett authored and Matt Fleming committed Apr 15, 2013
1 parent 7791c84 commit 0635eb8
Show file tree
Hide file tree
Showing 6 changed files with 89 additions and 62 deletions.
1 change: 1 addition & 0 deletions drivers/firmware/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ config FIRMWARE_MEMMAP
config EFI_VARS
tristate "EFI Variable Support via sysfs"
depends on EFI
select UCS2_STRING
default n
help
If you say Y here, you are able to get EFI (Extensible Firmware
Expand Down
80 changes: 18 additions & 62 deletions drivers/firmware/efivars.c
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@
#include <linux/slab.h>
#include <linux/pstore.h>
#include <linux/ctype.h>
#include <linux/ucs2_string.h>

#include <linux/fs.h>
#include <linux/ramfs.h>
Expand Down Expand Up @@ -172,51 +173,6 @@ static void efivar_update_sysfs_entries(struct work_struct *);
static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);
static bool efivar_wq_enabled = true;

/* Return the number of unicode characters in data */
static unsigned long
utf16_strnlen(efi_char16_t *s, size_t maxlength)
{
unsigned long length = 0;

while (*s++ != 0 && length < maxlength)
length++;
return length;
}

static inline unsigned long
utf16_strlen(efi_char16_t *s)
{
return utf16_strnlen(s, ~0UL);
}

/*
* Return the number of bytes is the length of this string
* Note: this is NOT the same as the number of unicode characters
*/
static inline unsigned long
utf16_strsize(efi_char16_t *data, unsigned long maxlength)
{
return utf16_strnlen(data, maxlength/sizeof(efi_char16_t)) * sizeof(efi_char16_t);
}

static inline int
utf16_strncmp(const efi_char16_t *a, const efi_char16_t *b, size_t len)
{
while (1) {
if (len == 0)
return 0;
if (*a < *b)
return -1;
if (*a > *b)
return 1;
if (*a == 0) /* implies *b == 0 */
return 0;
a++;
b++;
len--;
}
}

static bool
validate_device_path(struct efi_variable *var, int match, u8 *buffer,
unsigned long len)
Expand Down Expand Up @@ -268,7 +224,7 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer,
u16 filepathlength;
int i, desclength = 0, namelen;

namelen = utf16_strnlen(var->VariableName, sizeof(var->VariableName));
namelen = ucs2_strnlen(var->VariableName, sizeof(var->VariableName));

/* Either "Boot" or "Driver" followed by four digits of hex */
for (i = match; i < match+4; i++) {
Expand All @@ -291,7 +247,7 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer,
* There's no stored length for the description, so it has to be
* found by hand
*/
desclength = utf16_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2;
desclength = ucs2_strsize((efi_char16_t *)(buffer + 6), len - 6) + 2;

/* Each boot entry must have a descriptor */
if (!desclength)
Expand Down Expand Up @@ -581,7 +537,7 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
spin_lock_irq(&efivars->lock);

status = check_var_size_locked(efivars, new_var->Attributes,
new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
new_var->DataSize + ucs2_strsize(new_var->VariableName, 1024));

if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED)
status = efivars->ops->set_variable(new_var->VariableName,
Expand Down Expand Up @@ -759,7 +715,7 @@ static ssize_t efivarfs_file_write(struct file *file,
* QueryVariableInfo() isn't supported by the firmware.
*/

varsize = datasize + utf16_strsize(var->var.VariableName, 1024);
varsize = datasize + ucs2_strsize(var->var.VariableName, 1024);
status = check_var_size(efivars, attributes, varsize);

if (status != EFI_SUCCESS) {
Expand Down Expand Up @@ -1211,7 +1167,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)

inode = NULL;

len = utf16_strlen(entry->var.VariableName);
len = ucs2_strlen(entry->var.VariableName);

/* name, plus '-', plus GUID, plus NUL*/
name = kmalloc(len + 1 + GUID_LEN + 1, GFP_ATOMIC);
Expand Down Expand Up @@ -1469,8 +1425,8 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,

if (efi_guidcmp(entry->var.VendorGuid, vendor))
continue;
if (utf16_strncmp(entry->var.VariableName, efi_name,
utf16_strlen(efi_name))) {
if (ucs2_strncmp(entry->var.VariableName, efi_name,
ucs2_strlen(efi_name))) {
/*
* Check if an old format,
* which doesn't support holding
Expand All @@ -1482,8 +1438,8 @@ static int efi_pstore_erase(enum pstore_type_id type, u64 id, int count,
for (i = 0; i < DUMP_NAME_LEN; i++)
efi_name_old[i] = name_old[i];

if (utf16_strncmp(entry->var.VariableName, efi_name_old,
utf16_strlen(efi_name_old)))
if (ucs2_strncmp(entry->var.VariableName, efi_name_old,
ucs2_strlen(efi_name_old)))
continue;
}

Expand Down Expand Up @@ -1561,8 +1517,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
* Does this variable already exist?
*/
list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024);
strsize2 = utf16_strsize(new_var->VariableName, 1024);
strsize1 = ucs2_strsize(search_efivar->var.VariableName, 1024);
strsize2 = ucs2_strsize(new_var->VariableName, 1024);
if (strsize1 == strsize2 &&
!memcmp(&(search_efivar->var.VariableName),
new_var->VariableName, strsize1) &&
Expand All @@ -1578,7 +1534,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
}

status = check_var_size_locked(efivars, new_var->Attributes,
new_var->DataSize + utf16_strsize(new_var->VariableName, 1024));
new_var->DataSize + ucs2_strsize(new_var->VariableName, 1024));

if (status && status != EFI_UNSUPPORTED) {
spin_unlock_irq(&efivars->lock);
Expand All @@ -1602,7 +1558,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,

/* Create the entry in sysfs. Locking is not required here */
status = efivar_create_sysfs_entry(efivars,
utf16_strsize(new_var->VariableName,
ucs2_strsize(new_var->VariableName,
1024),
new_var->VariableName,
&new_var->VendorGuid);
Expand Down Expand Up @@ -1632,8 +1588,8 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
* Does this variable already exist?
*/
list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024);
strsize2 = utf16_strsize(del_var->VariableName, 1024);
strsize1 = ucs2_strsize(search_efivar->var.VariableName, 1024);
strsize2 = ucs2_strsize(del_var->VariableName, 1024);
if (strsize1 == strsize2 &&
!memcmp(&(search_efivar->var.VariableName),
del_var->VariableName, strsize1) &&
Expand Down Expand Up @@ -1679,9 +1635,9 @@ static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor)
unsigned long strsize1, strsize2;
bool found = false;

strsize1 = utf16_strsize(variable_name, 1024);
strsize1 = ucs2_strsize(variable_name, 1024);
list_for_each_entry_safe(entry, n, &efivars->list, list) {
strsize2 = utf16_strsize(entry->var.VariableName, 1024);
strsize2 = ucs2_strsize(entry->var.VariableName, 1024);
if (strsize1 == strsize2 &&
!memcmp(variable_name, &(entry->var.VariableName),
strsize2) &&
Expand Down
14 changes: 14 additions & 0 deletions include/linux/ucs2_string.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
#ifndef _LINUX_UCS2_STRING_H_
#define _LINUX_UCS2_STRING_H_

#include <linux/types.h> /* for size_t */
#include <linux/stddef.h> /* for NULL */

typedef u16 ucs2_char_t;

unsigned long ucs2_strnlen(const ucs2_char_t *s, size_t maxlength);
unsigned long ucs2_strlen(const ucs2_char_t *s);
unsigned long ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength);
int ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len);

#endif /* _LINUX_UCS2_STRING_H_ */
3 changes: 3 additions & 0 deletions lib/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -404,4 +404,7 @@ config OID_REGISTRY
help
Enable fast lookup object identifier registry.

config UCS2_STRING
tristate

endmenu
2 changes: 2 additions & 0 deletions lib/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -174,3 +174,5 @@ quiet_cmd_build_OID_registry = GEN $@
cmd_build_OID_registry = perl $(srctree)/$(src)/build_OID_registry $< $@

clean-files += oid_registry_data.c

obj-$(CONFIG_UCS2_STRING) += ucs2_string.o
51 changes: 51 additions & 0 deletions lib/ucs2_string.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#include <linux/ucs2_string.h>
#include <linux/module.h>

/* Return the number of unicode characters in data */
unsigned long
ucs2_strnlen(const ucs2_char_t *s, size_t maxlength)
{
unsigned long length = 0;

while (*s++ != 0 && length < maxlength)
length++;
return length;
}
EXPORT_SYMBOL(ucs2_strnlen);

unsigned long
ucs2_strlen(const ucs2_char_t *s)
{
return ucs2_strnlen(s, ~0UL);
}
EXPORT_SYMBOL(ucs2_strlen);

/*
* Return the number of bytes is the length of this string
* Note: this is NOT the same as the number of unicode characters
*/
unsigned long
ucs2_strsize(const ucs2_char_t *data, unsigned long maxlength)
{
return ucs2_strnlen(data, maxlength/sizeof(ucs2_char_t)) * sizeof(ucs2_char_t);
}
EXPORT_SYMBOL(ucs2_strsize);

int
ucs2_strncmp(const ucs2_char_t *a, const ucs2_char_t *b, size_t len)
{
while (1) {
if (len == 0)
return 0;
if (*a < *b)
return -1;
if (*a > *b)
return 1;
if (*a == 0) /* implies *b == 0 */
return 0;
a++;
b++;
len--;
}
}
EXPORT_SYMBOL(ucs2_strncmp);

0 comments on commit 0635eb8

Please sign in to comment.