aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/boot/compressed/eboot.c26
-rw-r--r--arch/x86/include/asm/efi.h9
-rw-r--r--arch/x86/kernel/setup.c3
-rw-r--r--arch/x86/platform/efi/efi.c5
-rw-r--r--drivers/firmware/efivars.c146
5 files changed, 166 insertions, 23 deletions
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index f8fa41190c35..c205035a6b96 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -19,23 +19,28 @@
19 19
20static efi_system_table_t *sys_table; 20static efi_system_table_t *sys_table;
21 21
22static void efi_char16_printk(efi_char16_t *str)
23{
24 struct efi_simple_text_output_protocol *out;
25
26 out = (struct efi_simple_text_output_protocol *)sys_table->con_out;
27 efi_call_phys2(out->output_string, out, str);
28}
29
22static void efi_printk(char *str) 30static void efi_printk(char *str)
23{ 31{
24 char *s8; 32 char *s8;
25 33
26 for (s8 = str; *s8; s8++) { 34 for (s8 = str; *s8; s8++) {
27 struct efi_simple_text_output_protocol *out;
28 efi_char16_t ch[2] = { 0 }; 35 efi_char16_t ch[2] = { 0 };
29 36
30 ch[0] = *s8; 37 ch[0] = *s8;
31 out = (struct efi_simple_text_output_protocol *)sys_table->con_out;
32
33 if (*s8 == '\n') { 38 if (*s8 == '\n') {
34 efi_char16_t nl[2] = { '\r', 0 }; 39 efi_char16_t nl[2] = { '\r', 0 };
35 efi_call_phys2(out->output_string, out, nl); 40 efi_char16_printk(nl);
36 } 41 }
37 42
38 efi_call_phys2(out->output_string, out, ch); 43 efi_char16_printk(ch);
39 } 44 }
40} 45}
41 46
@@ -709,7 +714,12 @@ static efi_status_t handle_ramdisks(efi_loaded_image_t *image,
709 if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16)) 714 if ((u8 *)p >= (u8 *)filename_16 + sizeof(filename_16))
710 break; 715 break;
711 716
712 *p++ = *str++; 717 if (*str == '/') {
718 *p++ = '\\';
719 *str++;
720 } else {
721 *p++ = *str++;
722 }
713 } 723 }
714 724
715 *p = '\0'; 725 *p = '\0';
@@ -737,7 +747,9 @@ static efi_status_t handle_ramdisks(efi_loaded_image_t *image,
737 status = efi_call_phys5(fh->open, fh, &h, filename_16, 747 status = efi_call_phys5(fh->open, fh, &h, filename_16,
738 EFI_FILE_MODE_READ, (u64)0); 748 EFI_FILE_MODE_READ, (u64)0);
739 if (status != EFI_SUCCESS) { 749 if (status != EFI_SUCCESS) {
740 efi_printk("Failed to open initrd file\n"); 750 efi_printk("Failed to open initrd file: ");
751 efi_char16_printk(filename_16);
752 efi_printk("\n");
741 goto close_handles; 753 goto close_handles;
742 } 754 }
743 755
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 28677c55113f..60c89f30c727 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -102,7 +102,14 @@ extern void efi_call_phys_epilog(void);
102extern void efi_unmap_memmap(void); 102extern void efi_unmap_memmap(void);
103extern void efi_memory_uc(u64 addr, unsigned long size); 103extern void efi_memory_uc(u64 addr, unsigned long size);
104 104
105#ifndef CONFIG_EFI 105#ifdef CONFIG_EFI
106
107static inline bool efi_is_native(void)
108{
109 return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT);
110}
111
112#else
106/* 113/*
107 * IF EFI is not configured, have the EFI calls return -ENOSYS. 114 * IF EFI is not configured, have the EFI calls return -ENOSYS.
108 */ 115 */
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index 9c857f05cef0..e89acdf6b77b 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -1196,8 +1196,7 @@ void __init setup_arch(char **cmdline_p)
1196 * mismatched firmware/kernel archtectures since there is no 1196 * mismatched firmware/kernel archtectures since there is no
1197 * support for runtime services. 1197 * support for runtime services.
1198 */ 1198 */
1199 if (efi_enabled(EFI_BOOT) && 1199 if (efi_enabled(EFI_BOOT) && !efi_is_native()) {
1200 IS_ENABLED(CONFIG_X86_64) != efi_enabled(EFI_64BIT)) {
1201 pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n"); 1200 pr_info("efi: Setup done, disabling due to 32/64-bit mismatch\n");
1202 efi_unmap_memmap(); 1201 efi_unmap_memmap();
1203 } 1202 }
diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c
index 5ae99f9160d9..5f2ecaf3f9d8 100644
--- a/arch/x86/platform/efi/efi.c
+++ b/arch/x86/platform/efi/efi.c
@@ -69,11 +69,6 @@ struct efi_memory_map memmap;
69static struct efi efi_phys __initdata; 69static struct efi efi_phys __initdata;
70static efi_system_table_t efi_systab __initdata; 70static efi_system_table_t efi_systab __initdata;
71 71
72static inline bool efi_is_native(void)
73{
74 return IS_ENABLED(CONFIG_X86_64) == efi_enabled(EFI_64BIT);
75}
76
77unsigned long x86_efi_facility; 72unsigned long x86_efi_facility;
78 73
79/* 74/*
diff --git a/drivers/firmware/efivars.c b/drivers/firmware/efivars.c
index fed08b661711..7320bf891706 100644
--- a/drivers/firmware/efivars.c
+++ b/drivers/firmware/efivars.c
@@ -79,6 +79,7 @@
79#include <linux/device.h> 79#include <linux/device.h>
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 83
83#include <linux/fs.h> 84#include <linux/fs.h>
84#include <linux/ramfs.h> 85#include <linux/ramfs.h>
@@ -908,6 +909,48 @@ static struct inode *efivarfs_get_inode(struct super_block *sb,
908 return inode; 909 return inode;
909} 910}
910 911
912/*
913 * Return true if 'str' is a valid efivarfs filename of the form,
914 *
915 * VariableName-12345678-1234-1234-1234-1234567891bc
916 */
917static bool efivarfs_valid_name(const char *str, int len)
918{
919 static const char dashes[GUID_LEN] = {
920 [8] = 1, [13] = 1, [18] = 1, [23] = 1
921 };
922 const char *s = str + len - GUID_LEN;
923 int i;
924
925 /*
926 * We need a GUID, plus at least one letter for the variable name,
927 * plus the '-' separator
928 */
929 if (len < GUID_LEN + 2)
930 return false;
931
932 /* GUID should be right after the first '-' */
933 if (s - 1 != strchr(str, '-'))
934 return false;
935
936 /*
937 * Validate that 's' is of the correct format, e.g.
938 *
939 * 12345678-1234-1234-1234-123456789abc
940 */
941 for (i = 0; i < GUID_LEN; i++) {
942 if (dashes[i]) {
943 if (*s++ != '-')
944 return false;
945 } else {
946 if (!isxdigit(*s++))
947 return false;
948 }
949 }
950
951 return true;
952}
953
911static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid) 954static void efivarfs_hex_to_guid(const char *str, efi_guid_t *guid)
912{ 955{
913 guid->b[0] = hex_to_bin(str[6]) << 4 | hex_to_bin(str[7]); 956 guid->b[0] = hex_to_bin(str[6]) << 4 | hex_to_bin(str[7]);
@@ -936,11 +979,7 @@ static int efivarfs_create(struct inode *dir, struct dentry *dentry,
936 struct efivar_entry *var; 979 struct efivar_entry *var;
937 int namelen, i = 0, err = 0; 980 int namelen, i = 0, err = 0;
938 981
939 /* 982 if (!efivarfs_valid_name(dentry->d_name.name, dentry->d_name.len))
940 * We need a GUID, plus at least one letter for the variable name,
941 * plus the '-' separator
942 */
943 if (dentry->d_name.len < GUID_LEN + 2)
944 return -EINVAL; 983 return -EINVAL;
945 984
946 inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0); 985 inode = efivarfs_get_inode(dir->i_sb, dir, mode, 0);
@@ -1012,6 +1051,84 @@ static int efivarfs_unlink(struct inode *dir, struct dentry *dentry)
1012 return -EINVAL; 1051 return -EINVAL;
1013}; 1052};
1014 1053
1054/*
1055 * Compare two efivarfs file names.
1056 *
1057 * An efivarfs filename is composed of two parts,
1058 *
1059 * 1. A case-sensitive variable name
1060 * 2. A case-insensitive GUID
1061 *
1062 * So we need to perform a case-sensitive match on part 1 and a
1063 * case-insensitive match on part 2.
1064 */
1065static int efivarfs_d_compare(const struct dentry *parent, const struct inode *pinode,
1066 const struct dentry *dentry, const struct inode *inode,
1067 unsigned int len, const char *str,
1068 const struct qstr *name)
1069{
1070 int guid = len - GUID_LEN;
1071
1072 if (name->len != len)
1073 return 1;
1074
1075 /* Case-sensitive compare for the variable name */
1076 if (memcmp(str, name->name, guid))
1077 return 1;
1078
1079 /* Case-insensitive compare for the GUID */
1080 return strncasecmp(name->name + guid, str + guid, GUID_LEN);
1081}
1082
1083static int efivarfs_d_hash(const struct dentry *dentry,
1084 const struct inode *inode, struct qstr *qstr)
1085{
1086 unsigned long hash = init_name_hash();
1087 const unsigned char *s = qstr->name;
1088 unsigned int len = qstr->len;
1089
1090 if (!efivarfs_valid_name(s, len))
1091 return -EINVAL;
1092
1093 while (len-- > GUID_LEN)
1094 hash = partial_name_hash(*s++, hash);
1095
1096 /* GUID is case-insensitive. */
1097 while (len--)
1098 hash = partial_name_hash(tolower(*s++), hash);
1099
1100 qstr->hash = end_name_hash(hash);
1101 return 0;
1102}
1103
1104/*
1105 * Retaining negative dentries for an in-memory filesystem just wastes
1106 * memory and lookup time: arrange for them to be deleted immediately.
1107 */
1108static int efivarfs_delete_dentry(const struct dentry *dentry)
1109{
1110 return 1;
1111}
1112
1113static struct dentry_operations efivarfs_d_ops = {
1114 .d_compare = efivarfs_d_compare,
1115 .d_hash = efivarfs_d_hash,
1116 .d_delete = efivarfs_delete_dentry,
1117};
1118
1119static struct dentry *efivarfs_alloc_dentry(struct dentry *parent, char *name)
1120{
1121 struct qstr q;
1122
1123 q.name = name;
1124 q.len = strlen(name);
1125
1126 if (efivarfs_d_hash(NULL, NULL, &q))
1127 return NULL;
1128
1129 return d_alloc(parent, &q);
1130}
1131
1015static int efivarfs_fill_super(struct super_block *sb, void *data, int silent) 1132static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
1016{ 1133{
1017 struct inode *inode = NULL; 1134 struct inode *inode = NULL;
@@ -1027,6 +1144,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
1027 sb->s_blocksize_bits = PAGE_CACHE_SHIFT; 1144 sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
1028 sb->s_magic = EFIVARFS_MAGIC; 1145 sb->s_magic = EFIVARFS_MAGIC;
1029 sb->s_op = &efivarfs_ops; 1146 sb->s_op = &efivarfs_ops;
1147 sb->s_d_op = &efivarfs_d_ops;
1030 sb->s_time_gran = 1; 1148 sb->s_time_gran = 1;
1031 1149
1032 inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0); 1150 inode = efivarfs_get_inode(sb, NULL, S_IFDIR | 0755, 0);
@@ -1067,7 +1185,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
1067 if (!inode) 1185 if (!inode)
1068 goto fail_name; 1186 goto fail_name;
1069 1187
1070 dentry = d_alloc_name(root, name); 1188 dentry = efivarfs_alloc_dentry(root, name);
1071 if (!dentry) 1189 if (!dentry)
1072 goto fail_inode; 1190 goto fail_inode;
1073 1191
@@ -1084,7 +1202,7 @@ static int efivarfs_fill_super(struct super_block *sb, void *data, int silent)
1084 1202
1085 mutex_lock(&inode->i_mutex); 1203 mutex_lock(&inode->i_mutex);
1086 inode->i_private = entry; 1204 inode->i_private = entry;
1087 i_size_write(inode, size+4); 1205 i_size_write(inode, size + sizeof(entry->var.Attributes));
1088 mutex_unlock(&inode->i_mutex); 1206 mutex_unlock(&inode->i_mutex);
1089 d_add(dentry, inode); 1207 d_add(dentry, inode);
1090 } 1208 }
@@ -1117,8 +1235,20 @@ static struct file_system_type efivarfs_type = {
1117 .kill_sb = efivarfs_kill_sb, 1235 .kill_sb = efivarfs_kill_sb,
1118}; 1236};
1119 1237
1238/*
1239 * Handle negative dentry.
1240 */
1241static struct dentry *efivarfs_lookup(struct inode *dir, struct dentry *dentry,
1242 unsigned int flags)
1243{
1244 if (dentry->d_name.len > NAME_MAX)
1245 return ERR_PTR(-ENAMETOOLONG);
1246 d_add(dentry, NULL);
1247 return NULL;
1248}
1249
1120static const struct inode_operations efivarfs_dir_inode_operations = { 1250static const struct inode_operations efivarfs_dir_inode_operations = {
1121 .lookup = simple_lookup, 1251 .lookup = efivarfs_lookup,
1122 .unlink = efivarfs_unlink, 1252 .unlink = efivarfs_unlink,
1123 .create = efivarfs_create, 1253 .create = efivarfs_create,
1124}; 1254};