aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArd Biesheuvel <ard.biesheuvel@linaro.org>2016-07-15 15:36:31 -0400
committerMatt Fleming <matt@codeblueprint.co.uk>2016-09-09 11:08:43 -0400
commitdce48e351c0d42014e5fb16ac3eb099e11b7e716 (patch)
tree97ec1bf70a8269d40598b5d1ed12f60d51ec18b4
parent21b3ddd39feecd2f4d6c52bcd30f0a4fa14f125a (diff)
efi: Replace runtime services spinlock with semaphore
The purpose of the efi_runtime_lock is to prevent concurrent calls into the firmware. There is no need to use spinlocks here, as long as we ensure that runtime service invocations from an atomic context (i.e., EFI pstore) cannot block. So use a semaphore instead, and use down_trylock() in the nonblocking case. We don't use a mutex here because the mutex_trylock() function must not be called from interrupt context, whereas the down_trylock() can. Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org> Cc: Leif Lindholm <leif.lindholm@linaro.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Sylvain Chouleur <sylvain.chouleur@gmail.com> Signed-off-by: Matt Fleming <matt@codeblueprint.co.uk>
-rw-r--r--drivers/firmware/efi/efi.c3
-rw-r--r--drivers/firmware/efi/runtime-wrappers.c81
-rw-r--r--include/linux/efi.h1
3 files changed, 53 insertions, 32 deletions
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index dfe07316cae5..97d98e82f0f4 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -810,6 +810,9 @@ int efi_status_to_err(efi_status_t status)
810 case EFI_NOT_FOUND: 810 case EFI_NOT_FOUND:
811 err = -ENOENT; 811 err = -ENOENT;
812 break; 812 break;
813 case EFI_ABORTED:
814 err = -EINTR;
815 break;
813 default: 816 default:
814 err = -EINVAL; 817 err = -EINVAL;
815 } 818 }
diff --git a/drivers/firmware/efi/runtime-wrappers.c b/drivers/firmware/efi/runtime-wrappers.c
index 41958774cde3..ae54870b2788 100644
--- a/drivers/firmware/efi/runtime-wrappers.c
+++ b/drivers/firmware/efi/runtime-wrappers.c
@@ -14,11 +14,13 @@
14 * This file is released under the GPLv2. 14 * This file is released under the GPLv2.
15 */ 15 */
16 16
17#define pr_fmt(fmt) "efi: " fmt
18
17#include <linux/bug.h> 19#include <linux/bug.h>
18#include <linux/efi.h> 20#include <linux/efi.h>
19#include <linux/irqflags.h> 21#include <linux/irqflags.h>
20#include <linux/mutex.h> 22#include <linux/mutex.h>
21#include <linux/spinlock.h> 23#include <linux/semaphore.h>
22#include <linux/stringify.h> 24#include <linux/stringify.h>
23#include <asm/efi.h> 25#include <asm/efi.h>
24 26
@@ -81,20 +83,21 @@ void efi_call_virt_check_flags(unsigned long flags, const char *call)
81 * +------------------------------------+-------------------------------+ 83 * +------------------------------------+-------------------------------+
82 * 84 *
83 * Due to the fact that the EFI pstore may write to the variable store in 85 * Due to the fact that the EFI pstore may write to the variable store in
84 * interrupt context, we need to use a spinlock for at least the groups that 86 * interrupt context, we need to use a lock for at least the groups that
85 * contain SetVariable() and QueryVariableInfo(). That leaves little else, as 87 * contain SetVariable() and QueryVariableInfo(). That leaves little else, as
86 * none of the remaining functions are actually ever called at runtime. 88 * none of the remaining functions are actually ever called at runtime.
87 * So let's just use a single spinlock to serialize all Runtime Services calls. 89 * So let's just use a single lock to serialize all Runtime Services calls.
88 */ 90 */
89static DEFINE_SPINLOCK(efi_runtime_lock); 91static DEFINE_SEMAPHORE(efi_runtime_lock);
90 92
91static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) 93static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
92{ 94{
93 efi_status_t status; 95 efi_status_t status;
94 96
95 spin_lock(&efi_runtime_lock); 97 if (down_interruptible(&efi_runtime_lock))
98 return EFI_ABORTED;
96 status = efi_call_virt(get_time, tm, tc); 99 status = efi_call_virt(get_time, tm, tc);
97 spin_unlock(&efi_runtime_lock); 100 up(&efi_runtime_lock);
98 return status; 101 return status;
99} 102}
100 103
@@ -102,9 +105,10 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm)
102{ 105{
103 efi_status_t status; 106 efi_status_t status;
104 107
105 spin_lock(&efi_runtime_lock); 108 if (down_interruptible(&efi_runtime_lock))
109 return EFI_ABORTED;
106 status = efi_call_virt(set_time, tm); 110 status = efi_call_virt(set_time, tm);
107 spin_unlock(&efi_runtime_lock); 111 up(&efi_runtime_lock);
108 return status; 112 return status;
109} 113}
110 114
@@ -114,9 +118,10 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
114{ 118{
115 efi_status_t status; 119 efi_status_t status;
116 120
117 spin_lock(&efi_runtime_lock); 121 if (down_interruptible(&efi_runtime_lock))
122 return EFI_ABORTED;
118 status = efi_call_virt(get_wakeup_time, enabled, pending, tm); 123 status = efi_call_virt(get_wakeup_time, enabled, pending, tm);
119 spin_unlock(&efi_runtime_lock); 124 up(&efi_runtime_lock);
120 return status; 125 return status;
121} 126}
122 127
@@ -124,9 +129,10 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
124{ 129{
125 efi_status_t status; 130 efi_status_t status;
126 131
127 spin_lock(&efi_runtime_lock); 132 if (down_interruptible(&efi_runtime_lock))
133 return EFI_ABORTED;
128 status = efi_call_virt(set_wakeup_time, enabled, tm); 134 status = efi_call_virt(set_wakeup_time, enabled, tm);
129 spin_unlock(&efi_runtime_lock); 135 up(&efi_runtime_lock);
130 return status; 136 return status;
131} 137}
132 138
@@ -138,10 +144,11 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name,
138{ 144{
139 efi_status_t status; 145 efi_status_t status;
140 146
141 spin_lock(&efi_runtime_lock); 147 if (down_interruptible(&efi_runtime_lock))
148 return EFI_ABORTED;
142 status = efi_call_virt(get_variable, name, vendor, attr, data_size, 149 status = efi_call_virt(get_variable, name, vendor, attr, data_size,
143 data); 150 data);
144 spin_unlock(&efi_runtime_lock); 151 up(&efi_runtime_lock);
145 return status; 152 return status;
146} 153}
147 154
@@ -151,9 +158,10 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
151{ 158{
152 efi_status_t status; 159 efi_status_t status;
153 160
154 spin_lock(&efi_runtime_lock); 161 if (down_interruptible(&efi_runtime_lock))
162 return EFI_ABORTED;
155 status = efi_call_virt(get_next_variable, name_size, name, vendor); 163 status = efi_call_virt(get_next_variable, name_size, name, vendor);
156 spin_unlock(&efi_runtime_lock); 164 up(&efi_runtime_lock);
157 return status; 165 return status;
158} 166}
159 167
@@ -165,10 +173,11 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
165{ 173{
166 efi_status_t status; 174 efi_status_t status;
167 175
168 spin_lock(&efi_runtime_lock); 176 if (down_interruptible(&efi_runtime_lock))
177 return EFI_ABORTED;
169 status = efi_call_virt(set_variable, name, vendor, attr, data_size, 178 status = efi_call_virt(set_variable, name, vendor, attr, data_size,
170 data); 179 data);
171 spin_unlock(&efi_runtime_lock); 180 up(&efi_runtime_lock);
172 return status; 181 return status;
173} 182}
174 183
@@ -179,12 +188,12 @@ virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
179{ 188{
180 efi_status_t status; 189 efi_status_t status;
181 190
182 if (!spin_trylock(&efi_runtime_lock)) 191 if (down_trylock(&efi_runtime_lock))
183 return EFI_NOT_READY; 192 return EFI_NOT_READY;
184 193
185 status = efi_call_virt(set_variable, name, vendor, attr, data_size, 194 status = efi_call_virt(set_variable, name, vendor, attr, data_size,
186 data); 195 data);
187 spin_unlock(&efi_runtime_lock); 196 up(&efi_runtime_lock);
188 return status; 197 return status;
189} 198}
190 199
@@ -199,10 +208,11 @@ static efi_status_t virt_efi_query_variable_info(u32 attr,
199 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 208 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
200 return EFI_UNSUPPORTED; 209 return EFI_UNSUPPORTED;
201 210
202 spin_lock(&efi_runtime_lock); 211 if (down_interruptible(&efi_runtime_lock))
212 return EFI_ABORTED;
203 status = efi_call_virt(query_variable_info, attr, storage_space, 213 status = efi_call_virt(query_variable_info, attr, storage_space,
204 remaining_space, max_variable_size); 214 remaining_space, max_variable_size);
205 spin_unlock(&efi_runtime_lock); 215 up(&efi_runtime_lock);
206 return status; 216 return status;
207} 217}
208 218
@@ -217,12 +227,12 @@ virt_efi_query_variable_info_nonblocking(u32 attr,
217 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 227 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
218 return EFI_UNSUPPORTED; 228 return EFI_UNSUPPORTED;
219 229
220 if (!spin_trylock(&efi_runtime_lock)) 230 if (down_trylock(&efi_runtime_lock))
221 return EFI_NOT_READY; 231 return EFI_NOT_READY;
222 232
223 status = efi_call_virt(query_variable_info, attr, storage_space, 233 status = efi_call_virt(query_variable_info, attr, storage_space,
224 remaining_space, max_variable_size); 234 remaining_space, max_variable_size);
225 spin_unlock(&efi_runtime_lock); 235 up(&efi_runtime_lock);
226 return status; 236 return status;
227} 237}
228 238
@@ -230,9 +240,10 @@ static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
230{ 240{
231 efi_status_t status; 241 efi_status_t status;
232 242
233 spin_lock(&efi_runtime_lock); 243 if (down_interruptible(&efi_runtime_lock))
244 return EFI_ABORTED;
234 status = efi_call_virt(get_next_high_mono_count, count); 245 status = efi_call_virt(get_next_high_mono_count, count);
235 spin_unlock(&efi_runtime_lock); 246 up(&efi_runtime_lock);
236 return status; 247 return status;
237} 248}
238 249
@@ -241,9 +252,13 @@ static void virt_efi_reset_system(int reset_type,
241 unsigned long data_size, 252 unsigned long data_size,
242 efi_char16_t *data) 253 efi_char16_t *data)
243{ 254{
244 spin_lock(&efi_runtime_lock); 255 if (down_interruptible(&efi_runtime_lock)) {
256 pr_warn("failed to invoke the reset_system() runtime service:\n"
257 "could not get exclusive access to the firmware\n");
258 return;
259 }
245 __efi_call_virt(reset_system, reset_type, status, data_size, data); 260 __efi_call_virt(reset_system, reset_type, status, data_size, data);
246 spin_unlock(&efi_runtime_lock); 261 up(&efi_runtime_lock);
247} 262}
248 263
249static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules, 264static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
@@ -255,9 +270,10 @@ static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
255 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 270 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
256 return EFI_UNSUPPORTED; 271 return EFI_UNSUPPORTED;
257 272
258 spin_lock(&efi_runtime_lock); 273 if (down_interruptible(&efi_runtime_lock))
274 return EFI_ABORTED;
259 status = efi_call_virt(update_capsule, capsules, count, sg_list); 275 status = efi_call_virt(update_capsule, capsules, count, sg_list);
260 spin_unlock(&efi_runtime_lock); 276 up(&efi_runtime_lock);
261 return status; 277 return status;
262} 278}
263 279
@@ -271,10 +287,11 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
271 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION) 287 if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
272 return EFI_UNSUPPORTED; 288 return EFI_UNSUPPORTED;
273 289
274 spin_lock(&efi_runtime_lock); 290 if (down_interruptible(&efi_runtime_lock))
291 return EFI_ABORTED;
275 status = efi_call_virt(query_capsule_caps, capsules, count, max_size, 292 status = efi_call_virt(query_capsule_caps, capsules, count, max_size,
276 reset_type); 293 reset_type);
277 spin_unlock(&efi_runtime_lock); 294 up(&efi_runtime_lock);
278 return status; 295 return status;
279} 296}
280 297
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 4d6da7b66c19..4c92c0630c45 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -38,6 +38,7 @@
38#define EFI_WRITE_PROTECTED ( 8 | (1UL << (BITS_PER_LONG-1))) 38#define EFI_WRITE_PROTECTED ( 8 | (1UL << (BITS_PER_LONG-1)))
39#define EFI_OUT_OF_RESOURCES ( 9 | (1UL << (BITS_PER_LONG-1))) 39#define EFI_OUT_OF_RESOURCES ( 9 | (1UL << (BITS_PER_LONG-1)))
40#define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1))) 40#define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1)))
41#define EFI_ABORTED (21 | (1UL << (BITS_PER_LONG-1)))
41#define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG-1))) 42#define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG-1)))
42 43
43typedef unsigned long efi_status_t; 44typedef unsigned long efi_status_t;