Skip to content

Commit dce48e3

Browse files
Ard Biesheuvelmfleming
authored andcommitted
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>
1 parent 21b3ddd commit dce48e3

File tree

3 files changed

+53
-32
lines changed

3 files changed

+53
-32
lines changed

drivers/firmware/efi/efi.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -810,6 +810,9 @@ int efi_status_to_err(efi_status_t status)
810810
case EFI_NOT_FOUND:
811811
err = -ENOENT;
812812
break;
813+
case EFI_ABORTED:
814+
err = -EINTR;
815+
break;
813816
default:
814817
err = -EINVAL;
815818
}

drivers/firmware/efi/runtime-wrappers.c

Lines changed: 49 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@
1414
* This file is released under the GPLv2.
1515
*/
1616

17+
#define pr_fmt(fmt) "efi: " fmt
18+
1719
#include <linux/bug.h>
1820
#include <linux/efi.h>
1921
#include <linux/irqflags.h>
2022
#include <linux/mutex.h>
21-
#include <linux/spinlock.h>
23+
#include <linux/semaphore.h>
2224
#include <linux/stringify.h>
2325
#include <asm/efi.h>
2426

@@ -81,30 +83,32 @@ void efi_call_virt_check_flags(unsigned long flags, const char *call)
8183
* +------------------------------------+-------------------------------+
8284
*
8385
* 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
8587
* contain SetVariable() and QueryVariableInfo(). That leaves little else, as
8688
* 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.
8890
*/
89-
static DEFINE_SPINLOCK(efi_runtime_lock);
91+
static DEFINE_SEMAPHORE(efi_runtime_lock);
9092

9193
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
9294
{
9395
efi_status_t status;
9496

95-
spin_lock(&efi_runtime_lock);
97+
if (down_interruptible(&efi_runtime_lock))
98+
return EFI_ABORTED;
9699
status = efi_call_virt(get_time, tm, tc);
97-
spin_unlock(&efi_runtime_lock);
100+
up(&efi_runtime_lock);
98101
return status;
99102
}
100103

101104
static efi_status_t virt_efi_set_time(efi_time_t *tm)
102105
{
103106
efi_status_t status;
104107

105-
spin_lock(&efi_runtime_lock);
108+
if (down_interruptible(&efi_runtime_lock))
109+
return EFI_ABORTED;
106110
status = efi_call_virt(set_time, tm);
107-
spin_unlock(&efi_runtime_lock);
111+
up(&efi_runtime_lock);
108112
return status;
109113
}
110114

@@ -114,19 +118,21 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
114118
{
115119
efi_status_t status;
116120

117-
spin_lock(&efi_runtime_lock);
121+
if (down_interruptible(&efi_runtime_lock))
122+
return EFI_ABORTED;
118123
status = efi_call_virt(get_wakeup_time, enabled, pending, tm);
119-
spin_unlock(&efi_runtime_lock);
124+
up(&efi_runtime_lock);
120125
return status;
121126
}
122127

123128
static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
124129
{
125130
efi_status_t status;
126131

127-
spin_lock(&efi_runtime_lock);
132+
if (down_interruptible(&efi_runtime_lock))
133+
return EFI_ABORTED;
128134
status = efi_call_virt(set_wakeup_time, enabled, tm);
129-
spin_unlock(&efi_runtime_lock);
135+
up(&efi_runtime_lock);
130136
return status;
131137
}
132138

@@ -138,10 +144,11 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name,
138144
{
139145
efi_status_t status;
140146

141-
spin_lock(&efi_runtime_lock);
147+
if (down_interruptible(&efi_runtime_lock))
148+
return EFI_ABORTED;
142149
status = efi_call_virt(get_variable, name, vendor, attr, data_size,
143150
data);
144-
spin_unlock(&efi_runtime_lock);
151+
up(&efi_runtime_lock);
145152
return status;
146153
}
147154

@@ -151,9 +158,10 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
151158
{
152159
efi_status_t status;
153160

154-
spin_lock(&efi_runtime_lock);
161+
if (down_interruptible(&efi_runtime_lock))
162+
return EFI_ABORTED;
155163
status = efi_call_virt(get_next_variable, name_size, name, vendor);
156-
spin_unlock(&efi_runtime_lock);
164+
up(&efi_runtime_lock);
157165
return status;
158166
}
159167

@@ -165,10 +173,11 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
165173
{
166174
efi_status_t status;
167175

168-
spin_lock(&efi_runtime_lock);
176+
if (down_interruptible(&efi_runtime_lock))
177+
return EFI_ABORTED;
169178
status = efi_call_virt(set_variable, name, vendor, attr, data_size,
170179
data);
171-
spin_unlock(&efi_runtime_lock);
180+
up(&efi_runtime_lock);
172181
return status;
173182
}
174183

@@ -179,12 +188,12 @@ virt_efi_set_variable_nonblocking(efi_char16_t *name, efi_guid_t *vendor,
179188
{
180189
efi_status_t status;
181190

182-
if (!spin_trylock(&efi_runtime_lock))
191+
if (down_trylock(&efi_runtime_lock))
183192
return EFI_NOT_READY;
184193

185194
status = efi_call_virt(set_variable, name, vendor, attr, data_size,
186195
data);
187-
spin_unlock(&efi_runtime_lock);
196+
up(&efi_runtime_lock);
188197
return status;
189198
}
190199

@@ -199,10 +208,11 @@ static efi_status_t virt_efi_query_variable_info(u32 attr,
199208
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
200209
return EFI_UNSUPPORTED;
201210

202-
spin_lock(&efi_runtime_lock);
211+
if (down_interruptible(&efi_runtime_lock))
212+
return EFI_ABORTED;
203213
status = efi_call_virt(query_variable_info, attr, storage_space,
204214
remaining_space, max_variable_size);
205-
spin_unlock(&efi_runtime_lock);
215+
up(&efi_runtime_lock);
206216
return status;
207217
}
208218

@@ -217,22 +227,23 @@ virt_efi_query_variable_info_nonblocking(u32 attr,
217227
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
218228
return EFI_UNSUPPORTED;
219229

220-
if (!spin_trylock(&efi_runtime_lock))
230+
if (down_trylock(&efi_runtime_lock))
221231
return EFI_NOT_READY;
222232

223233
status = efi_call_virt(query_variable_info, attr, storage_space,
224234
remaining_space, max_variable_size);
225-
spin_unlock(&efi_runtime_lock);
235+
up(&efi_runtime_lock);
226236
return status;
227237
}
228238

229239
static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
230240
{
231241
efi_status_t status;
232242

233-
spin_lock(&efi_runtime_lock);
243+
if (down_interruptible(&efi_runtime_lock))
244+
return EFI_ABORTED;
234245
status = efi_call_virt(get_next_high_mono_count, count);
235-
spin_unlock(&efi_runtime_lock);
246+
up(&efi_runtime_lock);
236247
return status;
237248
}
238249

@@ -241,9 +252,13 @@ static void virt_efi_reset_system(int reset_type,
241252
unsigned long data_size,
242253
efi_char16_t *data)
243254
{
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+
}
245260
__efi_call_virt(reset_system, reset_type, status, data_size, data);
246-
spin_unlock(&efi_runtime_lock);
261+
up(&efi_runtime_lock);
247262
}
248263

249264
static 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,
255270
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
256271
return EFI_UNSUPPORTED;
257272

258-
spin_lock(&efi_runtime_lock);
273+
if (down_interruptible(&efi_runtime_lock))
274+
return EFI_ABORTED;
259275
status = efi_call_virt(update_capsule, capsules, count, sg_list);
260-
spin_unlock(&efi_runtime_lock);
276+
up(&efi_runtime_lock);
261277
return status;
262278
}
263279

@@ -271,10 +287,11 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
271287
if (efi.runtime_version < EFI_2_00_SYSTEM_TABLE_REVISION)
272288
return EFI_UNSUPPORTED;
273289

274-
spin_lock(&efi_runtime_lock);
290+
if (down_interruptible(&efi_runtime_lock))
291+
return EFI_ABORTED;
275292
status = efi_call_virt(query_capsule_caps, capsules, count, max_size,
276293
reset_type);
277-
spin_unlock(&efi_runtime_lock);
294+
up(&efi_runtime_lock);
278295
return status;
279296
}
280297

include/linux/efi.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#define EFI_WRITE_PROTECTED ( 8 | (1UL << (BITS_PER_LONG-1)))
3939
#define EFI_OUT_OF_RESOURCES ( 9 | (1UL << (BITS_PER_LONG-1)))
4040
#define EFI_NOT_FOUND (14 | (1UL << (BITS_PER_LONG-1)))
41+
#define EFI_ABORTED (21 | (1UL << (BITS_PER_LONG-1)))
4142
#define EFI_SECURITY_VIOLATION (26 | (1UL << (BITS_PER_LONG-1)))
4243

4344
typedef unsigned long efi_status_t;

0 commit comments

Comments
 (0)