mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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>
This commit is contained in:
		
							parent
							
								
									7791c8423f
								
							
						
					
					
						commit
						0635eb8a54
					
				
					 6 changed files with 89 additions and 62 deletions
				
			
		| 
						 | 
					@ -39,6 +39,7 @@ config FIRMWARE_MEMMAP
 | 
				
			||||||
config EFI_VARS
 | 
					config EFI_VARS
 | 
				
			||||||
	tristate "EFI Variable Support via sysfs"
 | 
						tristate "EFI Variable Support via sysfs"
 | 
				
			||||||
	depends on EFI
 | 
						depends on EFI
 | 
				
			||||||
 | 
						select UCS2_STRING
 | 
				
			||||||
	default n
 | 
						default n
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  If you say Y here, you are able to get EFI (Extensible Firmware
 | 
						  If you say Y here, you are able to get EFI (Extensible Firmware
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -80,6 +80,7 @@
 | 
				
			||||||
#include <linux/slab.h>
 | 
					#include <linux/slab.h>
 | 
				
			||||||
#include <linux/pstore.h>
 | 
					#include <linux/pstore.h>
 | 
				
			||||||
#include <linux/ctype.h>
 | 
					#include <linux/ctype.h>
 | 
				
			||||||
 | 
					#include <linux/ucs2_string.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/fs.h>
 | 
					#include <linux/fs.h>
 | 
				
			||||||
#include <linux/ramfs.h>
 | 
					#include <linux/ramfs.h>
 | 
				
			||||||
| 
						 | 
					@ -172,51 +173,6 @@ static void efivar_update_sysfs_entries(struct work_struct *);
 | 
				
			||||||
static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);
 | 
					static DECLARE_WORK(efivar_work, efivar_update_sysfs_entries);
 | 
				
			||||||
static bool efivar_wq_enabled = true;
 | 
					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
 | 
					static bool
 | 
				
			||||||
validate_device_path(struct efi_variable *var, int match, u8 *buffer,
 | 
					validate_device_path(struct efi_variable *var, int match, u8 *buffer,
 | 
				
			||||||
		     unsigned long len)
 | 
							     unsigned long len)
 | 
				
			||||||
| 
						 | 
					@ -268,7 +224,7 @@ validate_load_option(struct efi_variable *var, int match, u8 *buffer,
 | 
				
			||||||
	u16 filepathlength;
 | 
						u16 filepathlength;
 | 
				
			||||||
	int i, desclength = 0, namelen;
 | 
						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 */
 | 
						/* Either "Boot" or "Driver" followed by four digits of hex */
 | 
				
			||||||
	for (i = match; i < match+4; i++) {
 | 
						for (i = match; i < match+4; i++) {
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
						 * There's no stored length for the description, so it has to be
 | 
				
			||||||
	 * found by hand
 | 
						 * 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 */
 | 
						/* Each boot entry must have a descriptor */
 | 
				
			||||||
	if (!desclength)
 | 
						if (!desclength)
 | 
				
			||||||
| 
						 | 
					@ -581,7 +537,7 @@ efivar_store_raw(struct efivar_entry *entry, const char *buf, size_t count)
 | 
				
			||||||
	spin_lock_irq(&efivars->lock);
 | 
						spin_lock_irq(&efivars->lock);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	status = check_var_size_locked(efivars, new_var->Attributes,
 | 
						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)
 | 
						if (status == EFI_SUCCESS || status == EFI_UNSUPPORTED)
 | 
				
			||||||
		status = efivars->ops->set_variable(new_var->VariableName,
 | 
							status = efivars->ops->set_variable(new_var->VariableName,
 | 
				
			||||||
| 
						 | 
					@ -759,7 +715,7 @@ static ssize_t efivarfs_file_write(struct file *file,
 | 
				
			||||||
	 * QueryVariableInfo() isn't supported by the firmware.
 | 
						 * 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);
 | 
						status = check_var_size(efivars, attributes, varsize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (status != EFI_SUCCESS) {
 | 
						if (status != EFI_SUCCESS) {
 | 
				
			||||||
| 
						 | 
					@ -1211,7 +1167,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		inode = NULL;
 | 
							inode = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		len = utf16_strlen(entry->var.VariableName);
 | 
							len = ucs2_strlen(entry->var.VariableName);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		/* name, plus '-', plus GUID, plus NUL*/
 | 
							/* name, plus '-', plus GUID, plus NUL*/
 | 
				
			||||||
		name = kmalloc(len + 1 + GUID_LEN + 1, GFP_ATOMIC);
 | 
							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,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (efi_guidcmp(entry->var.VendorGuid, vendor))
 | 
							if (efi_guidcmp(entry->var.VendorGuid, vendor))
 | 
				
			||||||
			continue;
 | 
								continue;
 | 
				
			||||||
		if (utf16_strncmp(entry->var.VariableName, efi_name,
 | 
							if (ucs2_strncmp(entry->var.VariableName, efi_name,
 | 
				
			||||||
				  utf16_strlen(efi_name))) {
 | 
									  ucs2_strlen(efi_name))) {
 | 
				
			||||||
			/*
 | 
								/*
 | 
				
			||||||
			 * Check if an old format,
 | 
								 * Check if an old format,
 | 
				
			||||||
			 * which doesn't support holding
 | 
								 * which doesn't support holding
 | 
				
			||||||
| 
						 | 
					@ -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++)
 | 
								for (i = 0; i < DUMP_NAME_LEN; i++)
 | 
				
			||||||
				efi_name_old[i] = name_old[i];
 | 
									efi_name_old[i] = name_old[i];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
			if (utf16_strncmp(entry->var.VariableName, efi_name_old,
 | 
								if (ucs2_strncmp(entry->var.VariableName, efi_name_old,
 | 
				
			||||||
					  utf16_strlen(efi_name_old)))
 | 
										  ucs2_strlen(efi_name_old)))
 | 
				
			||||||
				continue;
 | 
									continue;
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1561,8 +1517,8 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
 | 
				
			||||||
	 * Does this variable already exist?
 | 
						 * Does this variable already exist?
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
 | 
						list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
 | 
				
			||||||
		strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024);
 | 
							strsize1 = ucs2_strsize(search_efivar->var.VariableName, 1024);
 | 
				
			||||||
		strsize2 = utf16_strsize(new_var->VariableName, 1024);
 | 
							strsize2 = ucs2_strsize(new_var->VariableName, 1024);
 | 
				
			||||||
		if (strsize1 == strsize2 &&
 | 
							if (strsize1 == strsize2 &&
 | 
				
			||||||
			!memcmp(&(search_efivar->var.VariableName),
 | 
								!memcmp(&(search_efivar->var.VariableName),
 | 
				
			||||||
				new_var->VariableName, strsize1) &&
 | 
									new_var->VariableName, strsize1) &&
 | 
				
			||||||
| 
						 | 
					@ -1578,7 +1534,7 @@ static ssize_t efivar_create(struct file *filp, struct kobject *kobj,
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	status = check_var_size_locked(efivars, new_var->Attributes,
 | 
						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) {
 | 
						if (status && status != EFI_UNSUPPORTED) {
 | 
				
			||||||
		spin_unlock_irq(&efivars->lock);
 | 
							spin_unlock_irq(&efivars->lock);
 | 
				
			||||||
| 
						 | 
					@ -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 */
 | 
						/* Create the entry in sysfs.  Locking is not required here */
 | 
				
			||||||
	status = efivar_create_sysfs_entry(efivars,
 | 
						status = efivar_create_sysfs_entry(efivars,
 | 
				
			||||||
					   utf16_strsize(new_var->VariableName,
 | 
										   ucs2_strsize(new_var->VariableName,
 | 
				
			||||||
							 1024),
 | 
												 1024),
 | 
				
			||||||
					   new_var->VariableName,
 | 
										   new_var->VariableName,
 | 
				
			||||||
					   &new_var->VendorGuid);
 | 
										   &new_var->VendorGuid);
 | 
				
			||||||
| 
						 | 
					@ -1632,8 +1588,8 @@ static ssize_t efivar_delete(struct file *filp, struct kobject *kobj,
 | 
				
			||||||
	 * Does this variable already exist?
 | 
						 * Does this variable already exist?
 | 
				
			||||||
	 */
 | 
						 */
 | 
				
			||||||
	list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
 | 
						list_for_each_entry_safe(search_efivar, n, &efivars->list, list) {
 | 
				
			||||||
		strsize1 = utf16_strsize(search_efivar->var.VariableName, 1024);
 | 
							strsize1 = ucs2_strsize(search_efivar->var.VariableName, 1024);
 | 
				
			||||||
		strsize2 = utf16_strsize(del_var->VariableName, 1024);
 | 
							strsize2 = ucs2_strsize(del_var->VariableName, 1024);
 | 
				
			||||||
		if (strsize1 == strsize2 &&
 | 
							if (strsize1 == strsize2 &&
 | 
				
			||||||
			!memcmp(&(search_efivar->var.VariableName),
 | 
								!memcmp(&(search_efivar->var.VariableName),
 | 
				
			||||||
				del_var->VariableName, strsize1) &&
 | 
									del_var->VariableName, strsize1) &&
 | 
				
			||||||
| 
						 | 
					@ -1679,9 +1635,9 @@ static bool variable_is_present(efi_char16_t *variable_name, efi_guid_t *vendor)
 | 
				
			||||||
	unsigned long strsize1, strsize2;
 | 
						unsigned long strsize1, strsize2;
 | 
				
			||||||
	bool found = false;
 | 
						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) {
 | 
						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 &&
 | 
							if (strsize1 == strsize2 &&
 | 
				
			||||||
			!memcmp(variable_name, &(entry->var.VariableName),
 | 
								!memcmp(variable_name, &(entry->var.VariableName),
 | 
				
			||||||
				strsize2) &&
 | 
									strsize2) &&
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										14
									
								
								include/linux/ucs2_string.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								include/linux/ucs2_string.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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_ */
 | 
				
			||||||
| 
						 | 
					@ -404,4 +404,7 @@ config OID_REGISTRY
 | 
				
			||||||
	help
 | 
						help
 | 
				
			||||||
	  Enable fast lookup object identifier registry.
 | 
						  Enable fast lookup object identifier registry.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					config UCS2_STRING
 | 
				
			||||||
 | 
					        tristate
 | 
				
			||||||
 | 
					
 | 
				
			||||||
endmenu
 | 
					endmenu
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -174,3 +174,5 @@ quiet_cmd_build_OID_registry = GEN     $@
 | 
				
			||||||
      cmd_build_OID_registry = perl $(srctree)/$(src)/build_OID_registry $< $@
 | 
					      cmd_build_OID_registry = perl $(srctree)/$(src)/build_OID_registry $< $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
clean-files	+= oid_registry_data.c
 | 
					clean-files	+= oid_registry_data.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-$(CONFIG_UCS2_STRING) += ucs2_string.o
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										51
									
								
								lib/ucs2_string.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								lib/ucs2_string.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -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);
 | 
				
			||||||
		Loading…
	
		Reference in a new issue