1 #include "efi.h"
2 #include "runtime.h"
3 #include <xen/cache.h>
4 #include <xen/errno.h>
5 #include <xen/guest_access.h>
6 #include <xen/irq.h>
7 #include <xen/time.h>
8
9 DEFINE_XEN_GUEST_HANDLE(CHAR16);
10
11 struct efi_rs_state {
12 #ifdef CONFIG_X86
13 /*
14 * The way stacks get set up leads to them always being on an 8-byte
15 * boundary not evenly divisible by 16 (see asm-x86/current.h). The EFI ABI,
16 * just like the CPU one, however requires stacks to be 16-byte aligned
17 * before every function call. Since the compiler assumes this (unless
18 * passing it -mpreferred-stack-boundary=3), it wouldn't generate code to
19 * align the stack to 16 bytes even if putting a 16-byte aligned object
20 * there. Hence we need to force larger than 16-byte alignment, even if we
21 * don't strictly need that.
22 */
23 unsigned long __aligned(32) cr3;
24 #endif
25 };
26
27 struct efi_rs_state efi_rs_enter(void);
28 void efi_rs_leave(struct efi_rs_state *);
29
30 #ifndef COMPAT
31
32 #ifndef CONFIG_ARM
33 # include <asm/i387.h>
34 # include <asm/xstate.h>
35 # include <public/platform.h>
36 #endif
37
38 unsigned int __read_mostly efi_num_ct;
39 const EFI_CONFIGURATION_TABLE *__read_mostly efi_ct;
40
41 unsigned int __read_mostly efi_version;
42 unsigned int __read_mostly efi_fw_revision;
43 const CHAR16 *__read_mostly efi_fw_vendor;
44
45 const EFI_RUNTIME_SERVICES *__read_mostly efi_rs;
46 #ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */
47 static DEFINE_SPINLOCK(efi_rs_lock);
48 static unsigned int efi_rs_on_cpu = NR_CPUS;
49 #endif
50
51 UINTN __read_mostly efi_memmap_size;
52 UINTN __read_mostly efi_mdesc_size;
53 void *__read_mostly efi_memmap;
54
55 UINT64 __read_mostly efi_boot_max_var_store_size;
56 UINT64 __read_mostly efi_boot_remain_var_store_size;
57 UINT64 __read_mostly efi_boot_max_var_size;
58
59 UINT64 __read_mostly efi_apple_properties_addr;
60 UINTN __read_mostly efi_apple_properties_len;
61
62 /* Bit field representing available EFI features/properties. */
63 unsigned int efi_flags;
64
65 struct efi __read_mostly efi = {
66 .acpi = EFI_INVALID_TABLE_ADDR,
67 .acpi20 = EFI_INVALID_TABLE_ADDR,
68 .mps = EFI_INVALID_TABLE_ADDR,
69 .smbios = EFI_INVALID_TABLE_ADDR,
70 .smbios3 = EFI_INVALID_TABLE_ADDR,
71 };
72
73 const struct efi_pci_rom *__read_mostly efi_pci_roms;
74
efi_enabled(unsigned int feature)75 bool efi_enabled(unsigned int feature)
76 {
77 return test_bit(feature, &efi_flags);
78 }
79
80 #ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */
81
efi_rs_enter(void)82 struct efi_rs_state efi_rs_enter(void)
83 {
84 static const u16 fcw = FCW_DEFAULT;
85 static const u32 mxcsr = MXCSR_DEFAULT;
86 struct efi_rs_state state = { .cr3 = 0 };
87
88 if ( !efi_l4_pgtable )
89 return state;
90
91 state.cr3 = read_cr3();
92 save_fpu_enable();
93 asm volatile ( "fnclex; fldcw %0" :: "m" (fcw) );
94 asm volatile ( "ldmxcsr %0" :: "m" (mxcsr) );
95
96 spin_lock(&efi_rs_lock);
97
98 efi_rs_on_cpu = smp_processor_id();
99
100 /* prevent fixup_page_fault() from doing anything */
101 irq_enter();
102
103 if ( is_pv_vcpu(current) && !is_idle_vcpu(current) )
104 {
105 struct desc_ptr gdt_desc = {
106 .limit = LAST_RESERVED_GDT_BYTE,
107 .base = (unsigned long)(per_cpu(gdt, smp_processor_id()) -
108 FIRST_RESERVED_GDT_ENTRY)
109 };
110
111 lgdt(&gdt_desc);
112 }
113
114 switch_cr3_cr4(virt_to_maddr(efi_l4_pgtable), read_cr4());
115
116 return state;
117 }
118
efi_rs_leave(struct efi_rs_state * state)119 void efi_rs_leave(struct efi_rs_state *state)
120 {
121 struct vcpu *curr = current;
122
123 if ( !state->cr3 )
124 return;
125 switch_cr3_cr4(state->cr3, read_cr4());
126 if ( is_pv_vcpu(curr) && !is_idle_vcpu(curr) )
127 {
128 struct desc_ptr gdt_desc = {
129 .limit = LAST_RESERVED_GDT_BYTE,
130 .base = GDT_VIRT_START(curr)
131 };
132
133 lgdt(&gdt_desc);
134 }
135 irq_exit();
136 efi_rs_on_cpu = NR_CPUS;
137 spin_unlock(&efi_rs_lock);
138 vcpu_restore_fpu_nonlazy(curr, true);
139 }
140
efi_rs_using_pgtables(void)141 bool efi_rs_using_pgtables(void)
142 {
143 return efi_l4_pgtable &&
144 (smp_processor_id() == efi_rs_on_cpu) &&
145 (read_cr3() == virt_to_maddr(efi_l4_pgtable));
146 }
147
efi_get_time(void)148 unsigned long efi_get_time(void)
149 {
150 EFI_TIME time;
151 EFI_STATUS status;
152 struct efi_rs_state state = efi_rs_enter();
153 unsigned long flags;
154
155 if ( !state.cr3 )
156 return 0;
157 spin_lock_irqsave(&rtc_lock, flags);
158 status = efi_rs->GetTime(&time, NULL);
159 spin_unlock_irqrestore(&rtc_lock, flags);
160 efi_rs_leave(&state);
161
162 if ( EFI_ERROR(status) )
163 return 0;
164
165 return mktime(time.Year, time.Month, time.Day,
166 time.Hour, time.Minute, time.Second);
167 }
168
efi_halt_system(void)169 void efi_halt_system(void)
170 {
171 EFI_STATUS status;
172 struct efi_rs_state state = efi_rs_enter();
173
174 if ( !state.cr3 )
175 return;
176 status = efi_rs->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
177 efi_rs_leave(&state);
178
179 printk(XENLOG_WARNING "EFI: could not halt system (%#lx)\n", status);
180 }
181
efi_reset_system(bool warm)182 void efi_reset_system(bool warm)
183 {
184 EFI_STATUS status;
185 struct efi_rs_state state = efi_rs_enter();
186
187 if ( !state.cr3 )
188 return;
189 status = efi_rs->ResetSystem(warm ? EfiResetWarm : EfiResetCold,
190 EFI_SUCCESS, 0, NULL);
191 efi_rs_leave(&state);
192
193 printk(XENLOG_WARNING "EFI: could not reset system (%#lx)\n", status);
194 }
195
196 #endif /* CONFIG_ARM */
197
wmemchr(const CHAR16 * s,CHAR16 c,UINTN n)198 const CHAR16 *wmemchr(const CHAR16 *s, CHAR16 c, UINTN n)
199 {
200 while ( n && *s != c )
201 {
202 --n;
203 ++s;
204 }
205 return n ? s : NULL;
206 }
207
208 #endif /* COMPAT */
209
210 #ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */
efi_get_info(uint32_t idx,union xenpf_efi_info * info)211 int efi_get_info(uint32_t idx, union xenpf_efi_info *info)
212 {
213 unsigned int i, n;
214
215 if ( !efi_enabled(EFI_BOOT) )
216 return -ENOSYS;
217
218 switch ( idx )
219 {
220 case XEN_FW_EFI_VERSION:
221 info->version = efi_version;
222 break;
223 case XEN_FW_EFI_RT_VERSION:
224 {
225 if ( !efi_enabled(EFI_RS) )
226 return -EOPNOTSUPP;
227 info->version = efi_rs->Hdr.Revision;
228 break;
229 }
230 case XEN_FW_EFI_CONFIG_TABLE:
231 info->cfg.addr = __pa(efi_ct);
232 info->cfg.nent = efi_num_ct;
233 break;
234 case XEN_FW_EFI_VENDOR:
235 if ( !efi_fw_vendor )
236 return -EOPNOTSUPP;
237 info->vendor.revision = efi_fw_revision;
238 n = info->vendor.bufsz / sizeof(*efi_fw_vendor);
239 if ( !guest_handle_okay(guest_handle_cast(info->vendor.name,
240 CHAR16), n) )
241 return -EFAULT;
242 for ( i = 0; i < n; ++i )
243 {
244 if ( __copy_to_guest_offset(info->vendor.name, i,
245 efi_fw_vendor + i, 1) )
246 return -EFAULT;
247 if ( !efi_fw_vendor[i] )
248 break;
249 }
250 break;
251 case XEN_FW_EFI_MEM_INFO:
252 for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size )
253 {
254 EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
255 u64 len = desc->NumberOfPages << EFI_PAGE_SHIFT;
256
257 if ( info->mem.addr >= desc->PhysicalStart &&
258 info->mem.addr < desc->PhysicalStart + len )
259 {
260 info->mem.type = desc->Type;
261 info->mem.attr = desc->Attribute;
262 if ( info->mem.addr + info->mem.size < info->mem.addr ||
263 info->mem.addr + info->mem.size >
264 desc->PhysicalStart + len )
265 info->mem.size = desc->PhysicalStart + len -
266 info->mem.addr;
267 return 0;
268 }
269 }
270 return -ESRCH;
271 case XEN_FW_EFI_PCI_ROM: {
272 const struct efi_pci_rom *ent;
273
274 for ( ent = efi_pci_roms; ent; ent = ent->next )
275 if ( info->pci_rom.segment == ent->segment &&
276 info->pci_rom.bus == ent->bus &&
277 info->pci_rom.devfn == ent->devfn &&
278 info->pci_rom.vendor == ent->vendor &&
279 info->pci_rom.devid == ent->devid )
280 {
281 info->pci_rom.address = __pa(ent->data);
282 info->pci_rom.size = ent->size;
283 return 0;
284 }
285 return -ESRCH;
286 }
287
288 case XEN_FW_EFI_APPLE_PROPERTIES:
289 if ( !efi_apple_properties_len )
290 return -ENODATA;
291 info->apple_properties.address = efi_apple_properties_addr;
292 info->apple_properties.size = efi_apple_properties_len;
293 break;
294
295 default:
296 return -EINVAL;
297 }
298
299 return 0;
300 }
301
gwstrlen(XEN_GUEST_HANDLE_PARAM (CHAR16)str)302 static long gwstrlen(XEN_GUEST_HANDLE_PARAM(CHAR16) str)
303 {
304 unsigned long len;
305
306 for ( len = 0; ; ++len )
307 {
308 CHAR16 c;
309
310 if ( copy_from_guest_offset(&c, str, len, 1) )
311 return -EFAULT;
312 if ( !c )
313 break;
314 }
315
316 return len;
317 }
318
cast_time(struct xenpf_efi_time * time)319 static inline EFI_TIME *cast_time(struct xenpf_efi_time *time)
320 {
321 #define chk_fld(F, f) \
322 BUILD_BUG_ON(sizeof(cast_time(NULL)->F) != sizeof(time->f) || \
323 offsetof(EFI_TIME, F) != offsetof(struct xenpf_efi_time, f))
324 chk_fld(Year, year);
325 chk_fld(Month, month);
326 chk_fld(Day, day);
327 chk_fld(Hour, hour);
328 chk_fld(Minute, min);
329 chk_fld(Second, sec);
330 chk_fld(Nanosecond, ns);
331 chk_fld(TimeZone, tz);
332 chk_fld(Daylight, daylight);
333 #undef chk_fld
334 return (void *)time;
335 }
336
cast_guid(struct xenpf_efi_guid * guid)337 static inline EFI_GUID *cast_guid(struct xenpf_efi_guid *guid)
338 {
339 #define chk_fld(n) \
340 BUILD_BUG_ON(sizeof(cast_guid(NULL)->Data##n) != sizeof(guid->data##n) || \
341 offsetof(EFI_GUID, Data##n) != \
342 offsetof(struct xenpf_efi_guid, data##n))
343 chk_fld(1);
344 chk_fld(2);
345 chk_fld(3);
346 chk_fld(4);
347 #undef chk_fld
348 return (void *)guid;
349 }
350
efi_runtime_call(struct xenpf_efi_runtime_call * op)351 int efi_runtime_call(struct xenpf_efi_runtime_call *op)
352 {
353 struct efi_rs_state state;
354 unsigned long flags;
355 EFI_STATUS status = EFI_NOT_STARTED;
356 int rc = 0;
357
358 if ( !efi_enabled(EFI_BOOT) )
359 return -ENOSYS;
360
361 if ( !efi_enabled(EFI_RS) )
362 return -EOPNOTSUPP;
363
364 switch ( op->function )
365 {
366 case XEN_EFI_get_time:
367 {
368 EFI_TIME_CAPABILITIES caps;
369
370 if ( op->misc )
371 return -EINVAL;
372
373 state = efi_rs_enter();
374 if ( !state.cr3 )
375 return -EOPNOTSUPP;
376 spin_lock_irqsave(&rtc_lock, flags);
377 status = efi_rs->GetTime(cast_time(&op->u.get_time.time), &caps);
378 spin_unlock_irqrestore(&rtc_lock, flags);
379 efi_rs_leave(&state);
380
381 if ( !EFI_ERROR(status) )
382 {
383 op->u.get_time.resolution = caps.Resolution;
384 op->u.get_time.accuracy = caps.Accuracy;
385 if ( caps.SetsToZero )
386 op->misc = XEN_EFI_GET_TIME_SET_CLEARS_NS;
387 }
388 }
389 break;
390
391 case XEN_EFI_set_time:
392 if ( op->misc )
393 return -EINVAL;
394
395 state = efi_rs_enter();
396 if ( !state.cr3 )
397 return -EOPNOTSUPP;
398 spin_lock_irqsave(&rtc_lock, flags);
399 status = efi_rs->SetTime(cast_time(&op->u.set_time));
400 spin_unlock_irqrestore(&rtc_lock, flags);
401 efi_rs_leave(&state);
402 break;
403
404 case XEN_EFI_get_wakeup_time:
405 {
406 BOOLEAN enabled, pending;
407
408 if ( op->misc )
409 return -EINVAL;
410
411 state = efi_rs_enter();
412 if ( !state.cr3 )
413 return -EOPNOTSUPP;
414 spin_lock_irqsave(&rtc_lock, flags);
415 status = efi_rs->GetWakeupTime(&enabled, &pending,
416 cast_time(&op->u.get_wakeup_time));
417 spin_unlock_irqrestore(&rtc_lock, flags);
418 efi_rs_leave(&state);
419
420 if ( !EFI_ERROR(status) )
421 {
422 if ( enabled )
423 op->misc |= XEN_EFI_GET_WAKEUP_TIME_ENABLED;
424 if ( pending )
425 op->misc |= XEN_EFI_GET_WAKEUP_TIME_PENDING;
426 }
427 }
428 break;
429
430 case XEN_EFI_set_wakeup_time:
431 if ( op->misc & ~(XEN_EFI_SET_WAKEUP_TIME_ENABLE |
432 XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY) )
433 return -EINVAL;
434
435 state = efi_rs_enter();
436 if ( !state.cr3 )
437 return -EOPNOTSUPP;
438 spin_lock_irqsave(&rtc_lock, flags);
439 status = efi_rs->SetWakeupTime(!!(op->misc &
440 XEN_EFI_SET_WAKEUP_TIME_ENABLE),
441 (op->misc &
442 XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY) ?
443 NULL :
444 cast_time(&op->u.set_wakeup_time));
445 spin_unlock_irqrestore(&rtc_lock, flags);
446 efi_rs_leave(&state);
447
448 op->misc = 0;
449 break;
450
451 case XEN_EFI_get_next_high_monotonic_count:
452 if ( op->misc )
453 return -EINVAL;
454
455 state = efi_rs_enter();
456 if ( state.cr3 )
457 status = efi_rs->GetNextHighMonotonicCount(&op->misc);
458 else
459 rc = -EOPNOTSUPP;
460 efi_rs_leave(&state);
461 break;
462
463 case XEN_EFI_get_variable:
464 {
465 CHAR16 *name;
466 long len;
467 unsigned char *data;
468 UINTN size;
469
470 if ( op->misc )
471 return -EINVAL;
472
473 len = gwstrlen(guest_handle_cast(op->u.get_variable.name, CHAR16));
474 if ( len < 0 )
475 return len;
476 name = xmalloc_array(CHAR16, ++len);
477 if ( !name )
478 return -ENOMEM;
479 if ( __copy_from_guest(name, op->u.get_variable.name, len) ||
480 wmemchr(name, 0, len) != name + len - 1 )
481 {
482 xfree(name);
483 return -EIO;
484 }
485
486 size = op->u.get_variable.size;
487 if ( size )
488 {
489 data = xmalloc_bytes(size);
490 if ( !data )
491 {
492 xfree(name);
493 return -ENOMEM;
494 }
495 }
496 else
497 data = NULL;
498
499 state = efi_rs_enter();
500 if ( state.cr3 )
501 {
502 status = efi_rs->GetVariable(
503 name, cast_guid(&op->u.get_variable.vendor_guid),
504 &op->misc, &size, data);
505 efi_rs_leave(&state);
506
507 if ( !EFI_ERROR(status) &&
508 copy_to_guest(op->u.get_variable.data, data, size) )
509 rc = -EFAULT;
510 op->u.get_variable.size = size;
511 }
512 else
513 rc = -EOPNOTSUPP;
514
515 xfree(data);
516 xfree(name);
517 }
518 break;
519
520 case XEN_EFI_set_variable:
521 {
522 CHAR16 *name;
523 long len;
524 unsigned char *data;
525
526 len = gwstrlen(guest_handle_cast(op->u.set_variable.name, CHAR16));
527 if ( len < 0 )
528 return len;
529 name = xmalloc_array(CHAR16, ++len);
530 if ( !name )
531 return -ENOMEM;
532 if ( __copy_from_guest(name, op->u.set_variable.name, len) ||
533 wmemchr(name, 0, len) != name + len - 1 )
534 {
535 xfree(name);
536 return -EIO;
537 }
538
539 data = xmalloc_bytes(op->u.set_variable.size);
540 if ( !data )
541 rc = -ENOMEM;
542 else if ( copy_from_guest(data, op->u.set_variable.data,
543 op->u.set_variable.size) )
544 rc = -EFAULT;
545 else
546 {
547 state = efi_rs_enter();
548 if ( state.cr3 )
549 status = efi_rs->SetVariable(
550 name, cast_guid(&op->u.set_variable.vendor_guid),
551 op->misc, op->u.set_variable.size, data);
552 else
553 rc = -EOPNOTSUPP;
554 efi_rs_leave(&state);
555 }
556
557 xfree(data);
558 xfree(name);
559 }
560 break;
561
562 case XEN_EFI_get_next_variable_name:
563 {
564 union {
565 CHAR16 *str;
566 unsigned char *raw;
567 } name;
568 UINTN size;
569
570 if ( op->misc )
571 return -EINVAL;
572
573 size = op->u.get_next_variable_name.size;
574 name.raw = xzalloc_bytes(size);
575 if ( !name.raw )
576 return -ENOMEM;
577 if ( copy_from_guest(name.raw, op->u.get_next_variable_name.name,
578 size) )
579 {
580 xfree(name.raw);
581 return -EFAULT;
582 }
583
584 state = efi_rs_enter();
585 if ( state.cr3 )
586 {
587 status = efi_rs->GetNextVariableName(
588 &size, name.str,
589 cast_guid(&op->u.get_next_variable_name.vendor_guid));
590 efi_rs_leave(&state);
591
592 /*
593 * Copy the variable name if necessary. The caller provided size
594 * is used because some firmwares update size when they shouldn't.
595 * */
596 if ( !EFI_ERROR(status) &&
597 __copy_to_guest(op->u.get_next_variable_name.name,
598 name.raw, op->u.get_next_variable_name.size) )
599 rc = -EFAULT;
600 op->u.get_next_variable_name.size = size;
601 }
602 else
603 rc = -EOPNOTSUPP;
604
605 xfree(name.raw);
606 }
607 break;
608
609 case XEN_EFI_query_variable_info:
610 if ( op->misc & ~XEN_EFI_VARINFO_BOOT_SNAPSHOT )
611 return -EINVAL;
612
613 if ( op->misc & XEN_EFI_VARINFO_BOOT_SNAPSHOT )
614 {
615 if ( (op->u.query_variable_info.attr
616 & ~EFI_VARIABLE_APPEND_WRITE) !=
617 (EFI_VARIABLE_NON_VOLATILE |
618 EFI_VARIABLE_BOOTSERVICE_ACCESS |
619 EFI_VARIABLE_RUNTIME_ACCESS) )
620 return -EINVAL;
621
622 op->u.query_variable_info.max_store_size =
623 efi_boot_max_var_store_size;
624 op->u.query_variable_info.remain_store_size =
625 efi_boot_remain_var_store_size;
626 if ( efi_boot_max_var_store_size )
627 {
628 op->u.query_variable_info.max_size = efi_boot_max_var_size;
629 status = EFI_SUCCESS;
630 }
631 else
632 {
633 op->u.query_variable_info.max_size = 0;
634 status = efi_boot_max_var_size;
635 }
636 break;
637 }
638
639 if ( !efi_enabled(EFI_RS) || (efi_rs->Hdr.Revision >> 16) < 2 )
640 return -EOPNOTSUPP;
641 state = efi_rs_enter();
642 if ( !state.cr3 )
643 return -EOPNOTSUPP;
644 status = efi_rs->QueryVariableInfo(
645 op->u.query_variable_info.attr,
646 &op->u.query_variable_info.max_store_size,
647 &op->u.query_variable_info.remain_store_size,
648 &op->u.query_variable_info.max_size);
649 efi_rs_leave(&state);
650 break;
651
652 case XEN_EFI_query_capsule_capabilities:
653 case XEN_EFI_update_capsule:
654 if ( op->misc )
655 return -EINVAL;
656
657 if ( !efi_enabled(EFI_RS) || (efi_rs->Hdr.Revision >> 16) < 2 )
658 return -EOPNOTSUPP;
659 /* XXX fall through for now */
660 default:
661 return -ENOSYS;
662 }
663
664 #ifndef COMPAT
665 op->status = status;
666 #else
667 op->status = (status & 0x3fffffff) | ((status >> 32) & 0xc0000000);
668 #endif
669
670 return rc;
671 }
672 #endif
673