ed105f0f54
topology - fate#311376: EFI support in SP2 - fate#311529: Native UEFI booting under Xen (installation) 23074-pfn.h.patch 23571-vtd-fault-verbosity.patch 23574-x86-dom0-compressed-ELF.patch 23575-x86-DMI.patch 23610-x86-topology-info.patch 23611-amd-fam15-topology.patch 23613-EFI-headers.patch 23614-x86_64-EFI-boot.patch 23615-x86_64-EFI-runtime.patch 23616-x86_64-EFI-MPS.patch - Mark xen-scsi.ko supported (bnc#582265, fate#309459). - fate#310308: Hypervisor assisted watchdog driver ioemu-watchdog-support.patch ioemu-watchdog-linkage.patch ioemu-watchdog-ib700-timer.patch tools-watchdog-support.patch - bnc#702025 - VUL-0: xen: VT-d (PCI passthrough) MSI trap injection (CVE-2011-1898) Fixed in Xen version 4.1.1 - fate#310956: Support Direct Kernel Boot for FV guests kernel-boot-hvm.patch OBS-URL: https://build.opensuse.org/package/show/Virtualization/xen?expand=0&rev=130
788 lines
23 KiB
Diff
788 lines
23 KiB
Diff
References: fate#311376, fate#311529, bnc#578927, bnc#628554
|
|
|
|
# HG changeset patch
|
|
# User Jan Beulich <jbeulich@novell.com>
|
|
# Date 1309249249 -3600
|
|
# Node ID d19e778442673050bba8ea8cf61585902ff81162
|
|
# Parent 8b7d00f2abb21b504f6f8e1a6cc235cee8eb0858
|
|
x86-64: EFI runtime code
|
|
|
|
This allows Dom0 access to all suitable EFI runtime services. The
|
|
actual calls into EFI are done in "physical" mode, as entering virtual
|
|
mode has been determined to be incompatible with kexec (EFI's
|
|
SetVirtualAddressMap() can be called only once, and hence the
|
|
secondary kernel can't establish its mappings). ("Physical" mode here
|
|
being quoted because this is a mode with paging enabled [otherwise
|
|
64-bit mode wouldn't work] but all mappings being 1:1.)
|
|
|
|
Signed-off-by: Jan Beulich <jbeulich@novell.com>
|
|
|
|
--- a/xen/arch/x86/efi/boot.c
|
|
+++ b/xen/arch/x86/efi/boot.c
|
|
@@ -16,6 +16,7 @@
|
|
#include <xen/stringify.h>
|
|
#include <xen/vga.h>
|
|
#include <asm/e820.h>
|
|
+#include <asm/mm.h>
|
|
#include <asm/msr.h>
|
|
#include <asm/processor.h>
|
|
|
|
@@ -1149,6 +1150,53 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY
|
|
for( ; ; ); /* not reached */
|
|
}
|
|
|
|
+static __init void copy_mapping(unsigned long mfn, unsigned long end,
|
|
+ bool_t (*is_valid)(unsigned long smfn,
|
|
+ unsigned long emfn))
|
|
+{
|
|
+ unsigned long next;
|
|
+
|
|
+ for ( ; mfn < end; mfn = next )
|
|
+ {
|
|
+ l4_pgentry_t l4e = efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)];
|
|
+ l3_pgentry_t *l3src, *l3dst;
|
|
+ unsigned long va = (unsigned long)mfn_to_virt(mfn);
|
|
+
|
|
+ next = mfn + (1UL << (L3_PAGETABLE_SHIFT - PAGE_SHIFT));
|
|
+ if ( !is_valid(mfn, min(next, end)) )
|
|
+ continue;
|
|
+ if ( !(l4e_get_flags(l4e) & _PAGE_PRESENT) )
|
|
+ {
|
|
+ l3dst = alloc_xen_pagetable();
|
|
+ BUG_ON(!l3dst);
|
|
+ clear_page(l3dst);
|
|
+ efi_l4_pgtable[l4_table_offset(mfn << PAGE_SHIFT)] =
|
|
+ l4e_from_paddr(virt_to_maddr(l3dst), __PAGE_HYPERVISOR);
|
|
+ }
|
|
+ else
|
|
+ l3dst = l4e_to_l3e(l4e);
|
|
+ l3src = l4e_to_l3e(idle_pg_table[l4_table_offset(va)]);
|
|
+ l3dst[l3_table_offset(mfn << PAGE_SHIFT)] = l3src[l3_table_offset(va)];
|
|
+ }
|
|
+}
|
|
+
|
|
+static bool_t __init ram_range_valid(unsigned long smfn, unsigned long emfn)
|
|
+{
|
|
+ unsigned long sz = pfn_to_pdx(emfn - 1) / PDX_GROUP_COUNT + 1;
|
|
+
|
|
+ return !(smfn & pfn_hole_mask) &&
|
|
+ find_next_bit(pdx_group_valid, sz,
|
|
+ pfn_to_pdx(smfn) / PDX_GROUP_COUNT) < sz;
|
|
+}
|
|
+
|
|
+static bool_t __init rt_range_valid(unsigned long smfn, unsigned long emfn)
|
|
+{
|
|
+ return 1;
|
|
+}
|
|
+
|
|
+#define INVALID_VIRTUAL_ADDRESS (0xBAAADUL << \
|
|
+ (EFI_PAGE_SHIFT + BITS_PER_LONG - 32))
|
|
+
|
|
void __init efi_init_memory(void)
|
|
{
|
|
unsigned int i;
|
|
@@ -1169,11 +1217,11 @@ void __init efi_init_memory(void)
|
|
if ( !(desc->Attribute & EFI_MEMORY_RUNTIME) )
|
|
continue;
|
|
|
|
+ desc->VirtualStart = INVALID_VIRTUAL_ADDRESS;
|
|
+
|
|
smfn = PFN_DOWN(desc->PhysicalStart);
|
|
emfn = PFN_UP(desc->PhysicalStart + len);
|
|
|
|
- desc->VirtualStart = 0xBAAADUL << (EFI_PAGE_SHIFT + BITS_PER_LONG - 32);
|
|
-
|
|
if ( desc->Attribute & EFI_MEMORY_WB )
|
|
/* nothing */;
|
|
else if ( desc->Attribute & EFI_MEMORY_WT )
|
|
@@ -1217,5 +1265,34 @@ void __init efi_init_memory(void)
|
|
#if 0 /* Incompatible with kexec. */
|
|
efi_rs->SetVirtualAddressMap(efi_memmap_size, efi_mdesc_size,
|
|
mdesc_ver, efi_memmap);
|
|
+#else
|
|
+ /* Set up 1:1 page tables to do runtime calls in "physical" mode. */
|
|
+ efi_l4_pgtable = alloc_xen_pagetable();
|
|
+ BUG_ON(!efi_l4_pgtable);
|
|
+ clear_page(efi_l4_pgtable);
|
|
+
|
|
+ copy_mapping(0, max_page, ram_range_valid);
|
|
+
|
|
+ /* Insert non-RAM runtime mappings. */
|
|
+ for ( i = 0; i < efi_memmap_size; i += efi_mdesc_size )
|
|
+ {
|
|
+ const EFI_MEMORY_DESCRIPTOR *desc = efi_memmap + i;
|
|
+
|
|
+ if ( desc->Attribute & EFI_MEMORY_RUNTIME )
|
|
+ {
|
|
+ if ( desc->VirtualStart != INVALID_VIRTUAL_ADDRESS )
|
|
+ copy_mapping(PFN_DOWN(desc->PhysicalStart),
|
|
+ PFN_UP(desc->PhysicalStart +
|
|
+ (desc->NumberOfPages << EFI_PAGE_SHIFT)),
|
|
+ rt_range_valid);
|
|
+ else
|
|
+ /* XXX */;
|
|
+ }
|
|
+ }
|
|
+
|
|
+ /* Insert Xen mappings. */
|
|
+ for ( i = l4_table_offset(HYPERVISOR_VIRT_START);
|
|
+ i < l4_table_offset(HYPERVISOR_VIRT_END); ++i )
|
|
+ efi_l4_pgtable[i] = idle_pg_table[i];
|
|
#endif
|
|
}
|
|
--- a/xen/arch/x86/efi/compat.c
|
|
+++ b/xen/arch/x86/efi/compat.c
|
|
@@ -4,13 +4,27 @@
|
|
#define efi_get_info efi_compat_get_info
|
|
#define xenpf_efi_info compat_pf_efi_info
|
|
|
|
+#define efi_runtime_call efi_compat_runtime_call
|
|
+#define xenpf_efi_runtime_call compat_pf_efi_runtime_call
|
|
+
|
|
+#define xenpf_efi_guid compat_pf_efi_guid
|
|
+#define xenpf_efi_time compat_pf_efi_time
|
|
+
|
|
#define COMPAT
|
|
#undef DEFINE_XEN_GUEST_HANDLE
|
|
#define DEFINE_XEN_GUEST_HANDLE DEFINE_COMPAT_HANDLE
|
|
+#undef XEN_GUEST_HANDLE
|
|
+#define XEN_GUEST_HANDLE COMPAT_HANDLE
|
|
#undef guest_handle_okay
|
|
#define guest_handle_okay compat_handle_okay
|
|
#undef guest_handle_cast
|
|
#define guest_handle_cast compat_handle_cast
|
|
+#undef __copy_from_guest
|
|
+#define __copy_from_guest __copy_from_compat
|
|
+#undef copy_from_guest_offset
|
|
+#define copy_from_guest_offset copy_from_compat_offset
|
|
+#undef copy_to_guest
|
|
+#define copy_to_guest copy_to_compat
|
|
#undef __copy_to_guest_offset
|
|
#define __copy_to_guest_offset __copy_to_compat_offset
|
|
#include "runtime.c"
|
|
--- a/xen/arch/x86/efi/efi.h
|
|
+++ b/xen/arch/x86/efi/efi.h
|
|
@@ -5,6 +5,8 @@
|
|
#include <efi/efidevp.h>
|
|
#include <efi/efiapi.h>
|
|
#include <xen/efi.h>
|
|
+#include <xen/spinlock.h>
|
|
+#include <asm/page.h>
|
|
|
|
extern unsigned int efi_num_ct;
|
|
extern EFI_CONFIGURATION_TABLE *efi_ct;
|
|
@@ -16,3 +18,8 @@ extern EFI_RUNTIME_SERVICES *efi_rs;
|
|
|
|
extern UINTN efi_memmap_size, efi_mdesc_size;
|
|
extern void *efi_memmap;
|
|
+
|
|
+extern l4_pgentry_t *efi_l4_pgtable;
|
|
+
|
|
+unsigned long efi_rs_enter(void);
|
|
+void efi_rs_leave(unsigned long);
|
|
--- a/xen/arch/x86/efi/runtime.c
|
|
+++ b/xen/arch/x86/efi/runtime.c
|
|
@@ -2,6 +2,7 @@
|
|
#include <xen/cache.h>
|
|
#include <xen/errno.h>
|
|
#include <xen/guest_access.h>
|
|
+#include <xen/time.h>
|
|
|
|
DEFINE_XEN_GUEST_HANDLE(CHAR16);
|
|
|
|
@@ -19,6 +20,7 @@ unsigned int __read_mostly efi_fw_revisi
|
|
const CHAR16 *__read_mostly efi_fw_vendor;
|
|
|
|
EFI_RUNTIME_SERVICES *__read_mostly efi_rs;
|
|
+static DEFINE_SPINLOCK(efi_rs_lock);
|
|
|
|
UINTN __read_mostly efi_memmap_size;
|
|
UINTN __read_mostly efi_mdesc_size;
|
|
@@ -30,6 +32,68 @@ struct efi __read_mostly efi = {
|
|
.smbios = EFI_INVALID_TABLE_ADDR,
|
|
};
|
|
|
|
+l4_pgentry_t *__read_mostly efi_l4_pgtable;
|
|
+
|
|
+unsigned long efi_rs_enter(void)
|
|
+{
|
|
+ unsigned long cr3 = read_cr3();
|
|
+
|
|
+ spin_lock(&efi_rs_lock);
|
|
+
|
|
+ /* prevent fixup_page_fault() from doing anything */
|
|
+ irq_enter();
|
|
+
|
|
+ write_cr3(virt_to_maddr(efi_l4_pgtable));
|
|
+
|
|
+ return cr3;
|
|
+}
|
|
+
|
|
+void efi_rs_leave(unsigned long cr3)
|
|
+{
|
|
+ write_cr3(cr3);
|
|
+ irq_exit();
|
|
+ spin_unlock(&efi_rs_lock);
|
|
+}
|
|
+
|
|
+unsigned long efi_get_time(void)
|
|
+{
|
|
+ EFI_TIME time;
|
|
+ EFI_STATUS status;
|
|
+ unsigned long cr3 = efi_rs_enter();
|
|
+
|
|
+ status = efi_rs->GetTime(&time, NULL);
|
|
+ efi_rs_leave(cr3);
|
|
+
|
|
+ if ( EFI_ERROR(status) )
|
|
+ return 0;
|
|
+
|
|
+ return mktime(time.Year, time.Month, time.Day,
|
|
+ time.Hour, time.Minute, time.Second);
|
|
+}
|
|
+
|
|
+void efi_halt_system(void)
|
|
+{
|
|
+ EFI_STATUS status;
|
|
+ unsigned long cr3 = efi_rs_enter();
|
|
+
|
|
+ status = efi_rs->ResetSystem(EfiResetShutdown, EFI_SUCCESS, 0, NULL);
|
|
+ efi_rs_leave(cr3);
|
|
+
|
|
+ printk(XENLOG_WARNING "EFI: could not halt system (%#lx)\n", status);
|
|
+}
|
|
+
|
|
+void efi_reset_system(bool_t warm)
|
|
+{
|
|
+ EFI_STATUS status;
|
|
+ unsigned long cr3 = efi_rs_enter();
|
|
+
|
|
+ status = efi_rs->ResetSystem(warm ? EfiResetWarm : EfiResetCold,
|
|
+ EFI_SUCCESS, 0, NULL);
|
|
+ efi_rs_leave(cr3);
|
|
+
|
|
+ printk(XENLOG_WARNING "EFI: could not reset system (%#lx)\n", status);
|
|
+}
|
|
+
|
|
#endif
|
|
|
|
int efi_get_info(uint32_t idx, union xenpf_efi_info *info)
|
|
@@ -86,3 +150,267 @@ int efi_get_info(uint32_t idx, union xen
|
|
|
|
return 0;
|
|
}
|
|
+
|
|
+static long gwstrlen(XEN_GUEST_HANDLE(CHAR16) str)
|
|
+{
|
|
+ unsigned long len;
|
|
+
|
|
+ for ( len = 0; ; ++len )
|
|
+ {
|
|
+ CHAR16 c;
|
|
+
|
|
+ if ( copy_from_guest_offset(&c, str, len, 1) )
|
|
+ return -EFAULT;
|
|
+ if ( !c )
|
|
+ break;
|
|
+ }
|
|
+
|
|
+ return len;
|
|
+}
|
|
+
|
|
+static inline EFI_TIME *cast_time(struct xenpf_efi_time *time)
|
|
+{
|
|
+#define chk_fld(F, f) \
|
|
+ BUILD_BUG_ON(sizeof(cast_time(NULL)->F) != sizeof(time->f) || \
|
|
+ offsetof(EFI_TIME, F) != offsetof(struct xenpf_efi_time, f))
|
|
+ chk_fld(Year, year);
|
|
+ chk_fld(Month, month);
|
|
+ chk_fld(Day, day);
|
|
+ chk_fld(Hour, hour);
|
|
+ chk_fld(Minute, min);
|
|
+ chk_fld(Second, sec);
|
|
+ chk_fld(Nanosecond, ns);
|
|
+ chk_fld(TimeZone, tz);
|
|
+ chk_fld(Daylight, daylight);
|
|
+#undef chk_fld
|
|
+ return (void *)time;
|
|
+}
|
|
+
|
|
+static inline EFI_GUID *cast_guid(struct xenpf_efi_guid *guid)
|
|
+{
|
|
+#define chk_fld(n) \
|
|
+ BUILD_BUG_ON(sizeof(cast_guid(NULL)->Data##n) != sizeof(guid->data##n) || \
|
|
+ offsetof(EFI_GUID, Data##n) != \
|
|
+ offsetof(struct xenpf_efi_guid, data##n))
|
|
+ chk_fld(1);
|
|
+ chk_fld(2);
|
|
+ chk_fld(3);
|
|
+ chk_fld(4);
|
|
+#undef chk_fld
|
|
+ return (void *)guid;
|
|
+}
|
|
+
|
|
+int efi_runtime_call(struct xenpf_efi_runtime_call *op)
|
|
+{
|
|
+ unsigned long cr3;
|
|
+ EFI_STATUS status = EFI_NOT_STARTED;
|
|
+ int rc = 0;
|
|
+
|
|
+ switch ( op->function )
|
|
+ {
|
|
+ case XEN_EFI_get_time:
|
|
+ {
|
|
+ EFI_TIME_CAPABILITIES caps;
|
|
+
|
|
+ if ( op->misc )
|
|
+ return -EINVAL;
|
|
+
|
|
+ cr3 = efi_rs_enter();
|
|
+ status = efi_rs->GetTime(cast_time(&op->u.get_time.time), &caps);
|
|
+ efi_rs_leave(cr3);
|
|
+
|
|
+ if ( !EFI_ERROR(status) )
|
|
+ {
|
|
+ op->u.get_time.resolution = caps.Resolution;
|
|
+ op->u.get_time.accuracy = caps.Accuracy;
|
|
+ if ( caps.SetsToZero )
|
|
+ op->misc = XEN_EFI_GET_TIME_SET_CLEARS_NS;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case XEN_EFI_set_time:
|
|
+ if ( op->misc )
|
|
+ return -EINVAL;
|
|
+
|
|
+ cr3 = efi_rs_enter();
|
|
+ status = efi_rs->SetTime(cast_time(&op->u.set_time));
|
|
+ efi_rs_leave(cr3);
|
|
+ break;
|
|
+
|
|
+ case XEN_EFI_get_wakeup_time:
|
|
+ {
|
|
+ BOOLEAN enabled, pending;
|
|
+
|
|
+ if ( op->misc )
|
|
+ return -EINVAL;
|
|
+
|
|
+ cr3 = efi_rs_enter();
|
|
+ status = efi_rs->GetWakeupTime(&enabled, &pending,
|
|
+ cast_time(&op->u.get_wakeup_time));
|
|
+ efi_rs_leave(cr3);
|
|
+
|
|
+ if ( !EFI_ERROR(status) )
|
|
+ {
|
|
+ if ( enabled )
|
|
+ op->misc |= XEN_EFI_GET_WAKEUP_TIME_ENABLED;
|
|
+ if ( pending )
|
|
+ op->misc |= XEN_EFI_GET_WAKEUP_TIME_PENDING;
|
|
+ }
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case XEN_EFI_set_wakeup_time:
|
|
+ if ( op->misc & ~(XEN_EFI_SET_WAKEUP_TIME_ENABLE |
|
|
+ XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY) )
|
|
+ return -EINVAL;
|
|
+
|
|
+ cr3 = efi_rs_enter();
|
|
+ status = efi_rs->SetWakeupTime(!!(op->misc &
|
|
+ XEN_EFI_SET_WAKEUP_TIME_ENABLE),
|
|
+ (op->misc &
|
|
+ XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY) ?
|
|
+ NULL :
|
|
+ cast_time(&op->u.set_wakeup_time));
|
|
+ efi_rs_leave(cr3);
|
|
+
|
|
+ op->misc = 0;
|
|
+ break;
|
|
+
|
|
+ case XEN_EFI_get_next_high_monotonic_count:
|
|
+ if ( op->misc )
|
|
+ return -EINVAL;
|
|
+
|
|
+ cr3 = efi_rs_enter();
|
|
+ status = efi_rs->GetNextHighMonotonicCount(&op->misc);
|
|
+ efi_rs_leave(cr3);
|
|
+ break;
|
|
+
|
|
+ case XEN_EFI_get_variable:
|
|
+ {
|
|
+ CHAR16 *name;
|
|
+ long len;
|
|
+ unsigned char *data;
|
|
+ UINTN size;
|
|
+
|
|
+ if ( op->misc )
|
|
+ return -EINVAL;
|
|
+
|
|
+ len = gwstrlen(guest_handle_cast(op->u.get_variable.name, CHAR16));
|
|
+ if ( len < 0 )
|
|
+ return len;
|
|
+ name = xmalloc_array(CHAR16, ++len);
|
|
+ if ( !name )
|
|
+ return -ENOMEM;
|
|
+ __copy_from_guest(name, op->u.get_variable.name, len);
|
|
+
|
|
+ size = op->u.get_variable.size;
|
|
+ if ( size )
|
|
+ {
|
|
+ data = xmalloc_bytes(size);
|
|
+ if ( !data )
|
|
+ {
|
|
+ xfree(name);
|
|
+ return -ENOMEM;
|
|
+ }
|
|
+ }
|
|
+ else
|
|
+ data = NULL;
|
|
+
|
|
+ cr3 = efi_rs_enter();
|
|
+ status = efi_rs->GetVariable(
|
|
+ name, cast_guid(&op->u.get_variable.vendor_guid),
|
|
+ &op->misc, &size, data);
|
|
+ efi_rs_leave(cr3);
|
|
+
|
|
+ if ( !EFI_ERROR(status) &&
|
|
+ copy_to_guest(op->u.get_variable.data, data, size) )
|
|
+ rc = -EFAULT;
|
|
+ op->u.get_variable.size = size;
|
|
+
|
|
+ xfree(data);
|
|
+ xfree(name);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case XEN_EFI_set_variable:
|
|
+ {
|
|
+ CHAR16 *name;
|
|
+ long len;
|
|
+ unsigned char *data;
|
|
+
|
|
+ if ( op->misc )
|
|
+ return -EINVAL;
|
|
+
|
|
+ len = gwstrlen(guest_handle_cast(op->u.set_variable.name, CHAR16));
|
|
+ if ( len < 0 )
|
|
+ return len;
|
|
+ name = xmalloc_array(CHAR16, ++len);
|
|
+ if ( !name )
|
|
+ return -ENOMEM;
|
|
+ __copy_from_guest(name, op->u.set_variable.name, len);
|
|
+
|
|
+ data = xmalloc_bytes(op->u.set_variable.size);
|
|
+ if ( !data )
|
|
+ rc = -ENOMEM;
|
|
+ else if ( copy_from_guest(data, op->u.set_variable.data,
|
|
+ op->u.set_variable.size) )
|
|
+ rc = -EFAULT;
|
|
+ else
|
|
+ {
|
|
+ cr3 = efi_rs_enter();
|
|
+ status = efi_rs->SetVariable(
|
|
+ name, cast_guid(&op->u.set_variable.vendor_guid),
|
|
+ op->misc, op->u.set_variable.size, data);
|
|
+ efi_rs_leave(cr3);
|
|
+ }
|
|
+
|
|
+ xfree(data);
|
|
+ xfree(name);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ case XEN_EFI_get_next_variable_name:
|
|
+ {
|
|
+ union {
|
|
+ CHAR16 *str;
|
|
+ unsigned char *raw;
|
|
+ } name;
|
|
+ UINTN size;
|
|
+
|
|
+ if ( op->misc )
|
|
+ return -EINVAL;
|
|
+
|
|
+ size = op->u.get_next_variable_name.size;
|
|
+ name.raw = xmalloc_bytes(size);
|
|
+ if ( !name.raw )
|
|
+ return -ENOMEM;
|
|
+ copy_from_guest(name.raw, op->u.get_next_variable_name.name, size);
|
|
+
|
|
+ cr3 = efi_rs_enter();
|
|
+ status = efi_rs->GetNextVariableName(
|
|
+ &size, name.str,
|
|
+ cast_guid(&op->u.get_next_variable_name.vendor_guid));
|
|
+ efi_rs_leave(cr3);
|
|
+
|
|
+ if ( !EFI_ERROR(status) &&
|
|
+ copy_to_guest(op->u.get_next_variable_name.name, name.raw, size) )
|
|
+ rc = -EFAULT;
|
|
+ op->u.get_next_variable_name.size = size;
|
|
+
|
|
+ xfree(name.raw);
|
|
+ }
|
|
+ break;
|
|
+
|
|
+ default:
|
|
+ return -ENOSYS;
|
|
+ }
|
|
+
|
|
+#ifndef COMPAT
|
|
+ op->status = status;
|
|
+#else
|
|
+ op->status = (status & 0x3fffffff) | (status >> 62);
|
|
+#endif
|
|
+
|
|
+ return rc;
|
|
+}
|
|
--- a/xen/arch/x86/efi/stub.c
|
|
+++ b/xen/arch/x86/efi/stub.c
|
|
@@ -1,6 +1,7 @@
|
|
#include <xen/efi.h>
|
|
#include <xen/errno.h>
|
|
#include <xen/init.h>
|
|
+#include <asm/bug.h>
|
|
|
|
#ifndef efi_enabled
|
|
const bool_t efi_enabled = 0;
|
|
@@ -8,6 +9,15 @@ const bool_t efi_enabled = 0;
|
|
|
|
void __init efi_init_memory(void) { }
|
|
|
|
+unsigned long efi_get_time(void)
|
|
+{
|
|
+ BUG();
|
|
+ return 0;
|
|
+}
|
|
+
|
|
+void efi_halt_system(void) { }
|
|
+void efi_reset_system(bool_t warm) { }
|
|
+
|
|
int efi_get_info(uint32_t idx, union xenpf_efi_info *info)
|
|
{
|
|
return -ENOSYS;
|
|
@@ -15,3 +25,11 @@ int efi_get_info(uint32_t idx, union xen
|
|
|
|
int efi_compat_get_info(uint32_t idx, union compat_pf_efi_info *)
|
|
__attribute__((__alias__("efi_get_info")));
|
|
+
|
|
+int efi_runtime_call(struct xenpf_efi_runtime_call *op)
|
|
+{
|
|
+ return -ENOSYS;
|
|
+}
|
|
+
|
|
+int efi_compat_runtime_call(struct compat_pf_efi_runtime_call *)
|
|
+ __attribute__((__alias__("efi_runtime_call")));
|
|
--- a/xen/arch/x86/platform_hypercall.c
|
|
+++ b/xen/arch/x86/platform_hypercall.c
|
|
@@ -309,6 +309,17 @@ ret_t do_platform_op(XEN_GUEST_HANDLE(xe
|
|
}
|
|
break;
|
|
|
|
+ case XENPF_efi_runtime_call:
|
|
+ ret = xsm_efi_runtime_call();
|
|
+ if ( ret )
|
|
+ break;
|
|
+
|
|
+ ret = efi_runtime_call(&op->u.efi_runtime_call);
|
|
+ if ( ret == 0 &&
|
|
+ copy_field_to_guest(u_xenpf_op, op, u.efi_runtime_call) )
|
|
+ ret = -EFAULT;
|
|
+ break;
|
|
+
|
|
case XENPF_enter_acpi_sleep:
|
|
ret = xsm_acpi_sleep();
|
|
if ( ret )
|
|
--- a/xen/arch/x86/shutdown.c
|
|
+++ b/xen/arch/x86/shutdown.c
|
|
@@ -15,6 +15,7 @@
|
|
#include <xen/console.h>
|
|
#include <xen/shutdown.h>
|
|
#include <xen/acpi.h>
|
|
+#include <xen/efi.h>
|
|
#include <asm/msr.h>
|
|
#include <asm/regs.h>
|
|
#include <asm/mc146818rtc.h>
|
|
@@ -95,6 +96,7 @@ void machine_halt(void)
|
|
watchdog_disable();
|
|
console_start_sync();
|
|
local_irq_enable();
|
|
+ efi_halt_system();
|
|
smp_call_function(__machine_halt, NULL, 0);
|
|
__machine_halt(NULL);
|
|
}
|
|
@@ -337,6 +339,8 @@ void machine_restart(unsigned int delay_
|
|
if ( tboot_in_measured_env() )
|
|
tboot_shutdown(TB_SHUTDOWN_REBOOT);
|
|
|
|
+ efi_reset_system(reboot_mode != 0);
|
|
+
|
|
/* Rebooting needs to touch the page at absolute address 0. */
|
|
*((unsigned short *)__va(0x472)) = reboot_mode;
|
|
|
|
--- a/xen/arch/x86/time.c
|
|
+++ b/xen/arch/x86/time.c
|
|
@@ -21,6 +21,7 @@
|
|
#include <xen/smp.h>
|
|
#include <xen/irq.h>
|
|
#include <xen/softirq.h>
|
|
+#include <xen/efi.h>
|
|
#include <xen/cpuidle.h>
|
|
#include <xen/keyhandler.h>
|
|
#include <xen/guest_access.h>
|
|
@@ -756,6 +757,13 @@ static unsigned long get_cmos_time(void)
|
|
unsigned long res, flags;
|
|
int i;
|
|
|
|
+ if ( efi_enabled )
|
|
+ {
|
|
+ res = efi_get_time();
|
|
+ if ( res )
|
|
+ return res;
|
|
+ }
|
|
+
|
|
spin_lock_irqsave(&rtc_lock, flags);
|
|
|
|
/* read RTC exactly on falling edge of update flag */
|
|
--- a/xen/arch/x86/x86_64/platform_hypercall.c
|
|
+++ b/xen/arch/x86/x86_64/platform_hypercall.c
|
|
@@ -12,6 +12,7 @@ DEFINE_XEN_GUEST_HANDLE(compat_platform_
|
|
#define do_platform_op(x) compat_platform_op(_##x)
|
|
|
|
#define efi_get_info efi_compat_get_info
|
|
+#define efi_runtime_call(x) efi_compat_runtime_call(x)
|
|
|
|
#define xen_processor_px compat_processor_px
|
|
#define xen_processor_px_t compat_processor_px_t
|
|
--- a/xen/include/public/platform.h
|
|
+++ b/xen/include/public/platform.h
|
|
@@ -114,6 +114,77 @@ struct xenpf_platform_quirk {
|
|
typedef struct xenpf_platform_quirk xenpf_platform_quirk_t;
|
|
DEFINE_XEN_GUEST_HANDLE(xenpf_platform_quirk_t);
|
|
|
|
+#define XENPF_efi_runtime_call 49
|
|
+#define XEN_EFI_get_time 1
|
|
+#define XEN_EFI_set_time 2
|
|
+#define XEN_EFI_get_wakeup_time 3
|
|
+#define XEN_EFI_set_wakeup_time 4
|
|
+#define XEN_EFI_get_next_high_monotonic_count 5
|
|
+#define XEN_EFI_get_variable 6
|
|
+#define XEN_EFI_set_variable 7
|
|
+#define XEN_EFI_get_next_variable_name 8
|
|
+struct xenpf_efi_runtime_call {
|
|
+ uint32_t function;
|
|
+ /*
|
|
+ * This field is generally used for per sub-function flags (defined
|
|
+ * below), except for the XEN_EFI_get_next_high_monotonic_count case,
|
|
+ * where it holds the single returned value.
|
|
+ */
|
|
+ uint32_t misc;
|
|
+ unsigned long status;
|
|
+ union {
|
|
+#define XEN_EFI_GET_TIME_SET_CLEARS_NS 0x00000001
|
|
+ struct {
|
|
+ struct xenpf_efi_time {
|
|
+ uint16_t year;
|
|
+ uint8_t month;
|
|
+ uint8_t day;
|
|
+ uint8_t hour;
|
|
+ uint8_t min;
|
|
+ uint8_t sec;
|
|
+ uint32_t ns;
|
|
+ int16_t tz;
|
|
+ uint8_t daylight;
|
|
+ } time;
|
|
+ uint32_t resolution;
|
|
+ uint32_t accuracy;
|
|
+ } get_time;
|
|
+
|
|
+ struct xenpf_efi_time set_time;
|
|
+
|
|
+#define XEN_EFI_GET_WAKEUP_TIME_ENABLED 0x00000001
|
|
+#define XEN_EFI_GET_WAKEUP_TIME_PENDING 0x00000002
|
|
+ struct xenpf_efi_time get_wakeup_time;
|
|
+
|
|
+#define XEN_EFI_SET_WAKEUP_TIME_ENABLE 0x00000001
|
|
+#define XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY 0x00000002
|
|
+ struct xenpf_efi_time set_wakeup_time;
|
|
+
|
|
+#define XEN_EFI_VARIABLE_NON_VOLATILE 0x00000001
|
|
+#define XEN_EFI_VARIABLE_BOOTSERVICE_ACCESS 0x00000002
|
|
+#define XEN_EFI_VARIABLE_RUNTIME_ACCESS 0x00000004
|
|
+ struct {
|
|
+ XEN_GUEST_HANDLE(void) name; /* UCS-2/UTF-16 string */
|
|
+ unsigned long size;
|
|
+ XEN_GUEST_HANDLE(void) data;
|
|
+ struct xenpf_efi_guid {
|
|
+ uint32_t data1;
|
|
+ uint16_t data2;
|
|
+ uint16_t data3;
|
|
+ uint8_t data4[8];
|
|
+ } vendor_guid;
|
|
+ } get_variable, set_variable;
|
|
+
|
|
+ struct {
|
|
+ unsigned long size;
|
|
+ XEN_GUEST_HANDLE(void) name; /* UCS-2/UTF-16 string */
|
|
+ struct xenpf_efi_guid vendor_guid;
|
|
+ } get_next_variable_name;
|
|
+ } u;
|
|
+};
|
|
+typedef struct xenpf_efi_runtime_call xenpf_efi_runtime_call_t;
|
|
+DEFINE_XEN_GUEST_HANDLE(xenpf_efi_runtime_call_t);
|
|
+
|
|
#define XENPF_firmware_info 50
|
|
#define XEN_FW_DISK_INFO 1 /* from int 13 AH=08/41/48 */
|
|
#define XEN_FW_DISK_MBR_SIGNATURE 2 /* from MBR offset 0x1b8 */
|
|
@@ -388,6 +459,7 @@ struct xen_platform_op {
|
|
struct xenpf_read_memtype read_memtype;
|
|
struct xenpf_microcode_update microcode;
|
|
struct xenpf_platform_quirk platform_quirk;
|
|
+ struct xenpf_efi_runtime_call efi_runtime_call;
|
|
struct xenpf_firmware_info firmware_info;
|
|
struct xenpf_enter_acpi_sleep enter_acpi_sleep;
|
|
struct xenpf_change_freq change_freq;
|
|
--- a/xen/include/xen/efi.h
|
|
+++ b/xen/include/xen/efi.h
|
|
@@ -29,10 +29,18 @@ extern struct efi efi;
|
|
union xenpf_efi_info;
|
|
union compat_pf_efi_info;
|
|
|
|
+struct xenpf_efi_runtime_call;
|
|
+struct compat_pf_efi_runtime_call;
|
|
+
|
|
void efi_init_memory(void);
|
|
+unsigned long efi_get_time(void);
|
|
+void efi_halt_system(void);
|
|
+void efi_reset_system(bool_t warm);
|
|
#ifndef COMPAT
|
|
int efi_get_info(uint32_t idx, union xenpf_efi_info *);
|
|
+int efi_runtime_call(struct xenpf_efi_runtime_call *);
|
|
#endif
|
|
int efi_compat_get_info(uint32_t idx, union compat_pf_efi_info *);
|
|
+int efi_compat_runtime_call(struct compat_pf_efi_runtime_call *);
|
|
|
|
#endif /* __XEN_EFI_H__ */
|
|
--- a/xen/include/xsm/xsm.h
|
|
+++ b/xen/include/xsm/xsm.h
|
|
@@ -131,6 +131,7 @@ struct xsm_operations {
|
|
int (*physinfo) (void);
|
|
int (*platform_quirk) (uint32_t);
|
|
int (*firmware_info) (void);
|
|
+ int (*efi_runtime_call) (void);
|
|
int (*acpi_sleep) (void);
|
|
int (*change_freq) (void);
|
|
int (*getidletime) (void);
|
|
@@ -546,6 +547,11 @@ static inline int xsm_firmware_info (voi
|
|
return xsm_call(firmware_info());
|
|
}
|
|
|
|
+static inline int xsm_efi_runtime_call (void)
|
|
+{
|
|
+ return xsm_call(efi_runtime_call());
|
|
+}
|
|
+
|
|
static inline int xsm_acpi_sleep (void)
|
|
{
|
|
return xsm_call(acpi_sleep());
|