diff --git a/xen/common/efi/efi.h b/xen/common/efi/efi.h index c557104abc..9fe6ff16b0 100644 --- a/xen/common/efi/efi.h +++ b/xen/common/efi/efi.h @@ -36,6 +36,3 @@ extern const struct efi_pci_rom *efi_pci_roms; extern UINT64 efi_boot_max_var_store_size, efi_boot_remain_var_store_size, efi_boot_max_var_size; - -unsigned long efi_rs_enter(void); -void efi_rs_leave(unsigned long); diff --git a/xen/common/efi/runtime.c b/xen/common/efi/runtime.c index ae875570fb..b10b15e523 100644 --- a/xen/common/efi/runtime.c +++ b/xen/common/efi/runtime.c @@ -8,6 +8,25 @@ DEFINE_XEN_GUEST_HANDLE(CHAR16); +struct efi_rs_state { +#ifdef CONFIG_X86 + /* + * The way stacks get set up leads to them always being on an 8-byte + * boundary not evenly divisible by 16 (see asm-x86/current.h). The EFI ABI, + * just like the CPU one, however requires stacks to be 16-byte aligned + * before every function call. Since the compiler assumes this (unless + * passing it -mpreferred-stack-boundary=3), it wouldn't generate code to + * align the stack to 16 bytes even if putting a 16-byte aligned object + * there. Hence we need to force larger than 16-byte alignment, even if we + * don't strictly need that. + */ + unsigned long __aligned(32) cr3; +#endif +}; + +struct efi_rs_state efi_rs_enter(void); +void efi_rs_leave(struct efi_rs_state *); + #ifndef COMPAT #ifdef CONFIG_ARM /* Disabled until runtime services implemented */ @@ -52,17 +71,19 @@ struct efi __read_mostly efi = { const struct efi_pci_rom *__read_mostly efi_pci_roms; #ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */ -unsigned long efi_rs_enter(void) + +struct efi_rs_state efi_rs_enter(void) { static const u16 fcw = FCW_DEFAULT; static const u32 mxcsr = MXCSR_DEFAULT; - unsigned long cr3 = read_cr3(); + struct efi_rs_state state = { .cr3 = 0 }; if ( !efi_l4_pgtable ) - return 0; + return state; + state.cr3 = read_cr3(); save_fpu_enable(); - asm volatile ( "fldcw %0" :: "m" (fcw) ); + asm volatile ( "fnclex; fldcw %0" :: "m" (fcw) ); asm volatile ( "ldmxcsr %0" :: "m" (mxcsr) ); spin_lock(&efi_rs_lock); @@ -85,14 +106,14 @@ unsigned long efi_rs_enter(void) write_cr3(virt_to_maddr(efi_l4_pgtable)); - return cr3; + return state; } -void efi_rs_leave(unsigned long cr3) +void efi_rs_leave(struct efi_rs_state *state) { - if ( !cr3 ) + if ( !state->cr3 ) return; - write_cr3(cr3); + write_cr3(state->cr3); if ( is_pv_vcpu(current) && !is_idle_vcpu(current) ) { struct desc_ptr gdt_desc = { @@ -119,14 +140,15 @@ unsigned long efi_get_time(void) { EFI_TIME time; EFI_STATUS status; - unsigned long cr3 = efi_rs_enter(), flags; + struct efi_rs_state state = efi_rs_enter(); + unsigned long flags; - if ( !cr3 ) + if ( !state.cr3 ) return 0; spin_lock_irqsave(&rtc_lock, flags); status = efi_rs->GetTime(&time, NULL); spin_unlock_irqrestore(&rtc_lock, flags); - efi_rs_leave(cr3); + efi_rs_leave(&state); if ( EFI_ERROR(status) ) return 0; @@ -138,12 +160,12 @@ unsigned long efi_get_time(void) void efi_halt_system(void) { EFI_STATUS status; - unsigned long cr3 = efi_rs_enter(); + struct efi_rs_state state = efi_rs_enter(); - if ( !cr3 ) + if ( !state.cr3 ) return; status = efi_rs->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL); - efi_rs_leave(cr3); + efi_rs_leave(&state); printk(XENLOG_WARNING "EFI: could not halt system (%#lx)\n", status); } @@ -151,13 +173,13 @@ void efi_halt_system(void) void efi_reset_system(bool_t warm) { EFI_STATUS status; - unsigned long cr3 = efi_rs_enter(); + struct efi_rs_state state = efi_rs_enter(); - if ( !cr3 ) + if ( !state.cr3 ) return; status = efi_rs->ResetSystem(warm ? EfiResetWarm : EfiResetCold, EFI_SUCCESS, 0, NULL); - efi_rs_leave(cr3); + efi_rs_leave(&state); printk(XENLOG_WARNING "EFI: could not reset system (%#lx)\n", status); } @@ -177,12 +199,12 @@ int efi_get_info(uint32_t idx, union xenpf_efi_info *info) break; case XEN_FW_EFI_RT_VERSION: { - unsigned long cr3 = efi_rs_enter(); + struct efi_rs_state state = efi_rs_enter(); - if ( !cr3 ) + if ( !state.cr3 ) return -EOPNOTSUPP; info->version = efi_rs->Hdr.Revision; - efi_rs_leave(cr3); + efi_rs_leave(&state); break; } case XEN_FW_EFI_CONFIG_TABLE: @@ -300,7 +322,8 @@ static inline EFI_GUID *cast_guid(struct xenpf_efi_guid *guid) int efi_runtime_call(struct xenpf_efi_runtime_call *op) { - unsigned long cr3, flags; + struct efi_rs_state state; + unsigned long flags; EFI_STATUS status = EFI_NOT_STARTED; int rc = 0; @@ -313,13 +336,13 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *op) if ( op->misc ) return -EINVAL; - cr3 = efi_rs_enter(); - if ( !cr3 ) + state = efi_rs_enter(); + if ( !state.cr3 ) return -EOPNOTSUPP; spin_lock_irqsave(&rtc_lock, flags); status = efi_rs->GetTime(cast_time(&op->u.get_time.time), &caps); spin_unlock_irqrestore(&rtc_lock, flags); - efi_rs_leave(cr3); + efi_rs_leave(&state); if ( !EFI_ERROR(status) ) { @@ -335,13 +358,13 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *op) if ( op->misc ) return -EINVAL; - cr3 = efi_rs_enter(); - if ( !cr3 ) + state = efi_rs_enter(); + if ( !state.cr3 ) return -EOPNOTSUPP; spin_lock_irqsave(&rtc_lock, flags); status = efi_rs->SetTime(cast_time(&op->u.set_time)); spin_unlock_irqrestore(&rtc_lock, flags); - efi_rs_leave(cr3); + efi_rs_leave(&state); break; case XEN_EFI_get_wakeup_time: @@ -351,14 +374,14 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *op) if ( op->misc ) return -EINVAL; - cr3 = efi_rs_enter(); - if ( !cr3 ) + state = efi_rs_enter(); + if ( !state.cr3 ) return -EOPNOTSUPP; spin_lock_irqsave(&rtc_lock, flags); status = efi_rs->GetWakeupTime(&enabled, &pending, cast_time(&op->u.get_wakeup_time)); spin_unlock_irqrestore(&rtc_lock, flags); - efi_rs_leave(cr3); + efi_rs_leave(&state); if ( !EFI_ERROR(status) ) { @@ -375,8 +398,8 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *op) XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY) ) return -EINVAL; - cr3 = efi_rs_enter(); - if ( !cr3 ) + state = efi_rs_enter(); + if ( !state.cr3 ) return -EOPNOTSUPP; spin_lock_irqsave(&rtc_lock, flags); status = efi_rs->SetWakeupTime(!!(op->misc & @@ -386,7 +409,7 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *op) NULL : cast_time(&op->u.set_wakeup_time)); spin_unlock_irqrestore(&rtc_lock, flags); - efi_rs_leave(cr3); + efi_rs_leave(&state); op->misc = 0; break; @@ -395,12 +418,12 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *op) if ( op->misc ) return -EINVAL; - cr3 = efi_rs_enter(); - if ( cr3 ) + state = efi_rs_enter(); + if ( state.cr3 ) status = efi_rs->GetNextHighMonotonicCount(&op->misc); else rc = -EOPNOTSUPP; - efi_rs_leave(cr3); + efi_rs_leave(&state); break; case XEN_EFI_get_variable: @@ -434,13 +457,13 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *op) else data = NULL; - cr3 = efi_rs_enter(); - if ( cr3 ) + state = efi_rs_enter(); + if ( state.cr3 ) { status = efi_rs->GetVariable( name, cast_guid(&op->u.get_variable.vendor_guid), &op->misc, &size, data); - efi_rs_leave(cr3); + efi_rs_leave(&state); if ( !EFI_ERROR(status) && copy_to_guest(op->u.get_variable.data, data, size) ) @@ -477,14 +500,14 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *op) rc = -EFAULT; else { - cr3 = efi_rs_enter(); - if ( cr3 ) + state = efi_rs_enter(); + if ( state.cr3 ) status = efi_rs->SetVariable( name, cast_guid(&op->u.set_variable.vendor_guid), op->misc, op->u.set_variable.size, data); else rc = -EOPNOTSUPP; - efi_rs_leave(cr3); + efi_rs_leave(&state); } xfree(data); @@ -514,13 +537,13 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *op) return -EFAULT; } - cr3 = efi_rs_enter(); - if ( cr3 ) + state = efi_rs_enter(); + if ( state.cr3 ) { status = efi_rs->GetNextVariableName( &size, name.str, cast_guid(&op->u.get_next_variable_name.vendor_guid)); - efi_rs_leave(cr3); + efi_rs_leave(&state); /* * Copy the variable name if necessary. The caller provided size @@ -569,10 +592,10 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *op) break; } - cr3 = efi_rs_enter(); - if ( !cr3 || (efi_rs->Hdr.Revision >> 16) < 2 ) + state = efi_rs_enter(); + if ( !state.cr3 || (efi_rs->Hdr.Revision >> 16) < 2 ) { - efi_rs_leave(cr3); + efi_rs_leave(&state); return -EOPNOTSUPP; } status = efi_rs->QueryVariableInfo( @@ -580,7 +603,7 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *op) &op->u.query_variable_info.max_store_size, &op->u.query_variable_info.remain_store_size, &op->u.query_variable_info.max_size); - efi_rs_leave(cr3); + efi_rs_leave(&state); break; case XEN_EFI_query_capsule_capabilities: @@ -588,13 +611,13 @@ int efi_runtime_call(struct xenpf_efi_runtime_call *op) if ( op->misc ) return -EINVAL; - cr3 = efi_rs_enter(); - if ( !cr3 || (efi_rs->Hdr.Revision >> 16) < 2 ) + state = efi_rs_enter(); + if ( !state.cr3 || (efi_rs->Hdr.Revision >> 16) < 2 ) { - efi_rs_leave(cr3); + efi_rs_leave(&state); return -EOPNOTSUPP; } - efi_rs_leave(cr3); + efi_rs_leave(&state); /* XXX fall through for now */ default: return -ENOSYS; diff --git a/xen/include/xen/compiler.h b/xen/include/xen/compiler.h index 4b3472daee..e6a32cef90 100644 --- a/xen/include/xen/compiler.h +++ b/xen/include/xen/compiler.h @@ -34,6 +34,8 @@ #define __used_section(s) __used __attribute__((__section__(s))) #define __text_section(s) __attribute__((__section__(s))) +#define __aligned(a) __attribute__((__aligned__(a))) + #ifdef INIT_SECTIONS_ONLY /* * For sources indicated to have only init code, make sure even