1
1
/*
2
2
* runtime-wrappers.c - Runtime Services function call wrappers
3
3
*
4
+ * Implementation summary:
5
+ * -----------------------
6
+ * 1. When user/kernel thread requests to execute efi_runtime_service(),
7
+ * enqueue work to efi_rts_wq.
8
+ * 2. Caller thread waits for completion until the work is finished
9
+ * because it's dependent on the return status and execution of
10
+ * efi_runtime_service().
11
+ * For instance, get_variable() and get_next_variable().
12
+ *
4
13
* Copyright (C) 2014 Linaro Ltd. <ard.biesheuvel@linaro.org>
5
14
*
6
15
* Split off from arch/x86/platform/efi/efi.c
22
31
#include <linux/mutex.h>
23
32
#include <linux/semaphore.h>
24
33
#include <linux/stringify.h>
34
+ #include <linux/workqueue.h>
35
+ #include <linux/completion.h>
36
+
25
37
#include <asm/efi.h>
26
38
27
39
/*
33
45
#define __efi_call_virt (f , args ...) \
34
46
__efi_call_virt_pointer(efi.systab->runtime, f, args)
35
47
48
+ /* efi_runtime_service() function identifiers */
49
+ enum efi_rts_ids {
50
+ GET_TIME ,
51
+ SET_TIME ,
52
+ GET_WAKEUP_TIME ,
53
+ SET_WAKEUP_TIME ,
54
+ GET_VARIABLE ,
55
+ GET_NEXT_VARIABLE ,
56
+ SET_VARIABLE ,
57
+ QUERY_VARIABLE_INFO ,
58
+ GET_NEXT_HIGH_MONO_COUNT ,
59
+ UPDATE_CAPSULE ,
60
+ QUERY_CAPSULE_CAPS ,
61
+ };
62
+
63
+ /*
64
+ * efi_runtime_work: Details of EFI Runtime Service work
65
+ * @arg<1-5>: EFI Runtime Service function arguments
66
+ * @status: Status of executing EFI Runtime Service
67
+ * @efi_rts_id: EFI Runtime Service function identifier
68
+ * @efi_rts_comp: Struct used for handling completions
69
+ */
70
+ struct efi_runtime_work {
71
+ void * arg1 ;
72
+ void * arg2 ;
73
+ void * arg3 ;
74
+ void * arg4 ;
75
+ void * arg5 ;
76
+ efi_status_t status ;
77
+ struct work_struct work ;
78
+ enum efi_rts_ids efi_rts_id ;
79
+ struct completion efi_rts_comp ;
80
+ };
81
+
82
+ /*
83
+ * efi_queue_work: Queue efi_runtime_service() and wait until it's done
84
+ * @rts: efi_runtime_service() function identifier
85
+ * @rts_arg<1-5>: efi_runtime_service() function arguments
86
+ *
87
+ * Accesses to efi_runtime_services() are serialized by a binary
88
+ * semaphore (efi_runtime_lock) and caller waits until the work is
89
+ * finished, hence _only_ one work is queued at a time and the caller
90
+ * thread waits for completion.
91
+ */
92
+ #define efi_queue_work (_rts , _arg1 , _arg2 , _arg3 , _arg4 , _arg5 ) \
93
+ ({ \
94
+ struct efi_runtime_work efi_rts_work; \
95
+ efi_rts_work.status = EFI_ABORTED; \
96
+ \
97
+ init_completion(&efi_rts_work.efi_rts_comp); \
98
+ INIT_WORK_ONSTACK(&efi_rts_work.work, efi_call_rts); \
99
+ efi_rts_work.arg1 = _arg1; \
100
+ efi_rts_work.arg2 = _arg2; \
101
+ efi_rts_work.arg3 = _arg3; \
102
+ efi_rts_work.arg4 = _arg4; \
103
+ efi_rts_work.arg5 = _arg5; \
104
+ efi_rts_work.efi_rts_id = _rts; \
105
+ \
106
+ /* \
107
+ * queue_work() returns 0 if work was already on queue, \
108
+ * _ideally_ this should never happen. \
109
+ */ \
110
+ if (queue_work (efi_rts_wq , & efi_rts_work .work )) \
111
+ wait_for_completion (& efi_rts_work .efi_rts_comp ); \
112
+ else \
113
+ pr_err ("Failed to queue work to efi_rts_wq.\n" ); \
114
+ \
115
+ efi_rts_work .status ; \
116
+ })
117
+
36
118
void efi_call_virt_check_flags (unsigned long flags , const char * call )
37
119
{
38
120
unsigned long cur_flags , mismatch ;
@@ -90,13 +172,98 @@ void efi_call_virt_check_flags(unsigned long flags, const char *call)
90
172
*/
91
173
static DEFINE_SEMAPHORE (efi_runtime_lock );
92
174
175
+ /*
176
+ * Calls the appropriate efi_runtime_service() with the appropriate
177
+ * arguments.
178
+ *
179
+ * Semantics followed by efi_call_rts() to understand efi_runtime_work:
180
+ * 1. If argument was a pointer, recast it from void pointer to original
181
+ * pointer type.
182
+ * 2. If argument was a value, recast it from void pointer to original
183
+ * pointer type and dereference it.
184
+ */
185
+ static void efi_call_rts (struct work_struct * work )
186
+ {
187
+ struct efi_runtime_work * efi_rts_work ;
188
+ void * arg1 , * arg2 , * arg3 , * arg4 , * arg5 ;
189
+ efi_status_t status = EFI_NOT_FOUND ;
190
+
191
+ efi_rts_work = container_of (work , struct efi_runtime_work , work );
192
+ arg1 = efi_rts_work -> arg1 ;
193
+ arg2 = efi_rts_work -> arg2 ;
194
+ arg3 = efi_rts_work -> arg3 ;
195
+ arg4 = efi_rts_work -> arg4 ;
196
+ arg5 = efi_rts_work -> arg5 ;
197
+
198
+ switch (efi_rts_work -> efi_rts_id ) {
199
+ case GET_TIME :
200
+ status = efi_call_virt (get_time , (efi_time_t * )arg1 ,
201
+ (efi_time_cap_t * )arg2 );
202
+ break ;
203
+ case SET_TIME :
204
+ status = efi_call_virt (set_time , (efi_time_t * )arg1 );
205
+ break ;
206
+ case GET_WAKEUP_TIME :
207
+ status = efi_call_virt (get_wakeup_time , (efi_bool_t * )arg1 ,
208
+ (efi_bool_t * )arg2 , (efi_time_t * )arg3 );
209
+ break ;
210
+ case SET_WAKEUP_TIME :
211
+ status = efi_call_virt (set_wakeup_time , * (efi_bool_t * )arg1 ,
212
+ (efi_time_t * )arg2 );
213
+ break ;
214
+ case GET_VARIABLE :
215
+ status = efi_call_virt (get_variable , (efi_char16_t * )arg1 ,
216
+ (efi_guid_t * )arg2 , (u32 * )arg3 ,
217
+ (unsigned long * )arg4 , (void * )arg5 );
218
+ break ;
219
+ case GET_NEXT_VARIABLE :
220
+ status = efi_call_virt (get_next_variable , (unsigned long * )arg1 ,
221
+ (efi_char16_t * )arg2 ,
222
+ (efi_guid_t * )arg3 );
223
+ break ;
224
+ case SET_VARIABLE :
225
+ status = efi_call_virt (set_variable , (efi_char16_t * )arg1 ,
226
+ (efi_guid_t * )arg2 , * (u32 * )arg3 ,
227
+ * (unsigned long * )arg4 , (void * )arg5 );
228
+ break ;
229
+ case QUERY_VARIABLE_INFO :
230
+ status = efi_call_virt (query_variable_info , * (u32 * )arg1 ,
231
+ (u64 * )arg2 , (u64 * )arg3 , (u64 * )arg4 );
232
+ break ;
233
+ case GET_NEXT_HIGH_MONO_COUNT :
234
+ status = efi_call_virt (get_next_high_mono_count , (u32 * )arg1 );
235
+ break ;
236
+ case UPDATE_CAPSULE :
237
+ status = efi_call_virt (update_capsule ,
238
+ (efi_capsule_header_t * * )arg1 ,
239
+ * (unsigned long * )arg2 ,
240
+ * (unsigned long * )arg3 );
241
+ break ;
242
+ case QUERY_CAPSULE_CAPS :
243
+ status = efi_call_virt (query_capsule_caps ,
244
+ (efi_capsule_header_t * * )arg1 ,
245
+ * (unsigned long * )arg2 , (u64 * )arg3 ,
246
+ (int * )arg4 );
247
+ break ;
248
+ default :
249
+ /*
250
+ * Ideally, we should never reach here because a caller of this
251
+ * function should have put the right efi_runtime_service()
252
+ * function identifier into efi_rts_work->efi_rts_id
253
+ */
254
+ pr_err ("Requested executing invalid EFI Runtime Service.\n" );
255
+ }
256
+ efi_rts_work -> status = status ;
257
+ complete (& efi_rts_work -> efi_rts_comp );
258
+ }
259
+
93
260
static efi_status_t virt_efi_get_time (efi_time_t * tm , efi_time_cap_t * tc )
94
261
{
95
262
efi_status_t status ;
96
263
97
264
if (down_interruptible (& efi_runtime_lock ))
98
265
return EFI_ABORTED ;
99
- status = efi_call_virt ( get_time , tm , tc );
266
+ status = efi_queue_work ( GET_TIME , tm , tc , NULL , NULL , NULL );
100
267
up (& efi_runtime_lock );
101
268
return status ;
102
269
}
@@ -107,7 +274,7 @@ static efi_status_t virt_efi_set_time(efi_time_t *tm)
107
274
108
275
if (down_interruptible (& efi_runtime_lock ))
109
276
return EFI_ABORTED ;
110
- status = efi_call_virt ( set_time , tm );
277
+ status = efi_queue_work ( SET_TIME , tm , NULL , NULL , NULL , NULL );
111
278
up (& efi_runtime_lock );
112
279
return status ;
113
280
}
@@ -120,7 +287,8 @@ static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
120
287
121
288
if (down_interruptible (& efi_runtime_lock ))
122
289
return EFI_ABORTED ;
123
- status = efi_call_virt (get_wakeup_time , enabled , pending , tm );
290
+ status = efi_queue_work (GET_WAKEUP_TIME , enabled , pending , tm , NULL ,
291
+ NULL );
124
292
up (& efi_runtime_lock );
125
293
return status ;
126
294
}
@@ -131,7 +299,8 @@ static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
131
299
132
300
if (down_interruptible (& efi_runtime_lock ))
133
301
return EFI_ABORTED ;
134
- status = efi_call_virt (set_wakeup_time , enabled , tm );
302
+ status = efi_queue_work (SET_WAKEUP_TIME , & enabled , tm , NULL , NULL ,
303
+ NULL );
135
304
up (& efi_runtime_lock );
136
305
return status ;
137
306
}
@@ -146,8 +315,8 @@ static efi_status_t virt_efi_get_variable(efi_char16_t *name,
146
315
147
316
if (down_interruptible (& efi_runtime_lock ))
148
317
return EFI_ABORTED ;
149
- status = efi_call_virt ( get_variable , name , vendor , attr , data_size ,
150
- data );
318
+ status = efi_queue_work ( GET_VARIABLE , name , vendor , attr , data_size ,
319
+ data );
151
320
up (& efi_runtime_lock );
152
321
return status ;
153
322
}
@@ -160,7 +329,8 @@ static efi_status_t virt_efi_get_next_variable(unsigned long *name_size,
160
329
161
330
if (down_interruptible (& efi_runtime_lock ))
162
331
return EFI_ABORTED ;
163
- status = efi_call_virt (get_next_variable , name_size , name , vendor );
332
+ status = efi_queue_work (GET_NEXT_VARIABLE , name_size , name , vendor ,
333
+ NULL , NULL );
164
334
up (& efi_runtime_lock );
165
335
return status ;
166
336
}
@@ -175,8 +345,8 @@ static efi_status_t virt_efi_set_variable(efi_char16_t *name,
175
345
176
346
if (down_interruptible (& efi_runtime_lock ))
177
347
return EFI_ABORTED ;
178
- status = efi_call_virt ( set_variable , name , vendor , attr , data_size ,
179
- data );
348
+ status = efi_queue_work ( SET_VARIABLE , name , vendor , & attr , & data_size ,
349
+ data );
180
350
up (& efi_runtime_lock );
181
351
return status ;
182
352
}
@@ -210,8 +380,8 @@ static efi_status_t virt_efi_query_variable_info(u32 attr,
210
380
211
381
if (down_interruptible (& efi_runtime_lock ))
212
382
return EFI_ABORTED ;
213
- status = efi_call_virt ( query_variable_info , attr , storage_space ,
214
- remaining_space , max_variable_size );
383
+ status = efi_queue_work ( QUERY_VARIABLE_INFO , & attr , storage_space ,
384
+ remaining_space , max_variable_size , NULL );
215
385
up (& efi_runtime_lock );
216
386
return status ;
217
387
}
@@ -242,7 +412,8 @@ static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
242
412
243
413
if (down_interruptible (& efi_runtime_lock ))
244
414
return EFI_ABORTED ;
245
- status = efi_call_virt (get_next_high_mono_count , count );
415
+ status = efi_queue_work (GET_NEXT_HIGH_MONO_COUNT , count , NULL , NULL ,
416
+ NULL , NULL );
246
417
up (& efi_runtime_lock );
247
418
return status ;
248
419
}
@@ -272,7 +443,8 @@ static efi_status_t virt_efi_update_capsule(efi_capsule_header_t **capsules,
272
443
273
444
if (down_interruptible (& efi_runtime_lock ))
274
445
return EFI_ABORTED ;
275
- status = efi_call_virt (update_capsule , capsules , count , sg_list );
446
+ status = efi_queue_work (UPDATE_CAPSULE , capsules , & count , & sg_list ,
447
+ NULL , NULL );
276
448
up (& efi_runtime_lock );
277
449
return status ;
278
450
}
@@ -289,8 +461,8 @@ static efi_status_t virt_efi_query_capsule_caps(efi_capsule_header_t **capsules,
289
461
290
462
if (down_interruptible (& efi_runtime_lock ))
291
463
return EFI_ABORTED ;
292
- status = efi_call_virt ( query_capsule_caps , capsules , count , max_size ,
293
- reset_type );
464
+ status = efi_queue_work ( QUERY_CAPSULE_CAPS , capsules , & count ,
465
+ max_size , reset_type , NULL );
294
466
up (& efi_runtime_lock );
295
467
return status ;
296
468
}
0 commit comments