All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/4] x86-64: EFI runtime code
@ 2011-06-27 10:43 Jan Beulich
  2011-06-27 16:25 ` Konrad Rzeszutek Wilk
  0 siblings, 1 reply; 14+ messages in thread
From: Jan Beulich @ 2011-06-27 10:43 UTC (permalink / raw)
  To: xen-devel

[-- Attachment #1: Type: text/plain, Size: 24016 bytes --]

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.)

Open issue (not preventing this from being committed imo):

Page (and perhaps other) faults occuring while calling runtime
functions in the context of a hypercall don't get handled correctly
(they don't even seem to reach do_page_fault()). I'm intending to
ivestigate this further.

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
@@ -304,6 +304,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/symbols.h>
 #include <xen/keyhandler.h>
@@ -759,6 +760,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
@@ -132,6 +132,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);
@@ -553,6 +554,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());



[-- Attachment #2: x86-EFI-runtime.patch --]
[-- Type: text/plain, Size: 24012 bytes --]

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.)

Open issue (not preventing this from being committed imo):

Page (and perhaps other) faults occuring while calling runtime
functions in the context of a hypercall don't get handled correctly
(they don't even seem to reach do_page_fault()). I'm intending to
ivestigate this further.

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
@@ -304,6 +304,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/symbols.h>
 #include <xen/keyhandler.h>
@@ -759,6 +760,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
@@ -132,6 +132,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);
@@ -553,6 +554,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());

[-- Attachment #3: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] x86-64: EFI runtime code
  2011-06-27 10:43 [PATCH 3/4] x86-64: EFI runtime code Jan Beulich
@ 2011-06-27 16:25 ` Konrad Rzeszutek Wilk
  2011-06-27 17:36   ` Keir Fraser
  2011-06-28  7:11   ` Jan Beulich
  0 siblings, 2 replies; 14+ messages in thread
From: Konrad Rzeszutek Wilk @ 2011-06-27 16:25 UTC (permalink / raw)
  To: Jan Beulich; +Cc: xen-devel

On Mon, Jun 27, 2011 at 11:43:02AM +0100, Jan Beulich wrote:
> This allows Dom0 access to all suitable EFI runtime services. The

What type of patches for the upstream 3.0 kernel are needed to take
advantage of these new hypercalls?

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] x86-64: EFI runtime code
  2011-06-27 16:25 ` Konrad Rzeszutek Wilk
@ 2011-06-27 17:36   ` Keir Fraser
  2011-06-28  7:11   ` Jan Beulich
  1 sibling, 0 replies; 14+ messages in thread
From: Keir Fraser @ 2011-06-27 17:36 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk, Jan Beulich; +Cc: xen-devel

On 27/06/2011 17:25, "Konrad Rzeszutek Wilk" <konrad.wilk@oracle.com> wrote:

> On Mon, Jun 27, 2011 at 11:43:02AM +0100, Jan Beulich wrote:
>> This allows Dom0 access to all suitable EFI runtime services. The
> 
> What type of patches for the upstream 3.0 kernel are needed to take
> advantage of these new hypercalls?

This is probably the biggest thing to get right, as details below the public
interface alterations can all be subject to change. I belive patches 2/4 and
3/4 are the only two with public header changes. Do you want to reserve an
Ack/Nack on those? You might need to get 2/4 direct from Jan as it seems to
have stalled at the list server.

 -- Keir

> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xensource.com
> http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] x86-64: EFI runtime code
  2011-06-27 16:25 ` Konrad Rzeszutek Wilk
  2011-06-27 17:36   ` Keir Fraser
@ 2011-06-28  7:11   ` Jan Beulich
  2011-06-28  7:39     ` Keir Fraser
  1 sibling, 1 reply; 14+ messages in thread
From: Jan Beulich @ 2011-06-28  7:11 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk; +Cc: xen-devel

>>> On 27.06.11 at 18:25, Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> wrote:
> On Mon, Jun 27, 2011 at 11:43:02AM +0100, Jan Beulich wrote:
>> This allows Dom0 access to all suitable EFI runtime services. The
> 
> What type of patches for the upstream 3.0 kernel are needed to take
> advantage of these new hypercalls?

I did not put any consideration in how to integrate this with the
upstream kernel. For our kernel, I used the *-xen.? mechanism
to have a parallel source file to arch/x86/platform/efi/efi.c, and
excluded building of arch/x86/platform/efi/efi_stub_*.S and
arch/x86/platform/efi/efi_*.c.

Patch below for reference.

Jan

--- head-2011-05-23.orig/arch/x86/Kconfig	2011-04-14 11:32:40.000000000 +0200
+++ head-2011-05-23/arch/x86/Kconfig	2011-06-09 17:04:17.000000000 +0200
@@ -1511,7 +1511,7 @@ config ARCH_USES_PG_UNCACHED
 
 config EFI
 	bool "EFI runtime service support"
-	depends on ACPI && !XEN
+	depends on ACPI && !XEN_UNPRIVILEGED_GUEST
 	---help---
 	  This enables the kernel to use EFI runtime services that are
 	  available (such as the EFI variable services).
--- head-2011-05-23.orig/arch/x86/include/mach-xen/asm/setup.h	2011-06-21 15:35:45.000000000 +0200
+++ head-2011-05-23/arch/x86/include/mach-xen/asm/setup.h	2011-06-15 15:26:22.000000000 +0200
@@ -10,6 +10,12 @@ void reserve_pgtable_low(void);
 
 extern unsigned long xen_initrd_start;
 
+#ifdef CONFIG_EFI
+void efi_probe(void);
+#else
+#define efi_probe() ((void)0)
+#endif
+
 #endif
 
 #include_next <asm/setup.h>
--- head-2011-05-23.orig/arch/x86/kernel/setup-xen.c	2011-06-10 12:12:00.000000000 +0200
+++ head-2011-05-23/arch/x86/kernel/setup-xen.c	2011-06-10 12:42:34.000000000 +0200
@@ -870,6 +870,8 @@ void __init setup_arch(char **cmdline_p)
 		                      xen_start_info->console.dom0.info_size);
 		xen_start_info->console.domU.mfn = 0;
 		xen_start_info->console.domU.evtchn = 0;
+
+		efi_probe();
 	} else
 		screen_info.orig_video_isVGA = 0;
 	copy_edid();
--- head-2011-05-23.orig/arch/x86/platform/efi/Makefile	2011-06-21 15:35:45.000000000 +0200
+++ head-2011-05-23/arch/x86/platform/efi/Makefile	2011-06-09 17:06:13.000000000 +0200
@@ -1 +1,2 @@
 obj-$(CONFIG_EFI) 		+= efi.o efi_$(BITS).o efi_stub_$(BITS).o
+disabled-obj-$(CONFIG_XEN)	:= efi_%$(BITS).o
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ head-2011-05-23/arch/x86/platform/efi/efi-xen.c	2011-06-21 15:24:29.000000000 +0200
@@ -0,0 +1,430 @@
+/*
+ * Common EFI (Extensible Firmware Interface) support functions
+ * Based on Extensible Firmware Interface Specification version 1.0
+ *
+ * Copyright (C) 1999 VA Linux Systems
+ * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
+ * Copyright (C) 1999-2002 Hewlett-Packard Co.
+ *	David Mosberger-Tang <davidm@hpl.hp.com>
+ *	Stephane Eranian <eranian@hpl.hp.com>
+ * Copyright (C) 2005-2008 Intel Co.
+ *	Fenghua Yu <fenghua.yu@intel.com>
+ *	Bibo Mao <bibo.mao@intel.com>
+ *	Chandramouli Narayanan <mouli@linux.intel.com>
+ *	Huang Ying <ying.huang@intel.com>
+ *
+ * Copied from efi_32.c to eliminate the duplicated code between EFI
+ * 32/64 support code. --ying 2007-10-26
+ *
+ * All EFI Runtime Services are not implemented yet as EFI only
+ * supports physical mode addressing on SoftSDV. This is to be fixed
+ * in a future version.  --drummond 1999-07-20
+ *
+ * Implemented EFI runtime services and virtual mode calls.  --davidm
+ *
+ * Goutham Rao: <goutham.rao@intel.com>
+ *	Skip non-WB memory and ignore empty memory ranges.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/efi.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+#include <linux/time.h>
+
+#include <asm/setup.h>
+#include <asm/efi.h>
+#include <asm/time.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+#include <asm/x86_init.h>
+
+#include <xen/interface/platform.h>
+
+#define EFI_DEBUG	1
+#define PFX 		"EFI: "
+
+int __read_mostly efi_enabled;
+EXPORT_SYMBOL(efi_enabled);
+
+#define call op.u.efi_runtime_call
+#define DECLARE_CALL(what) \
+	struct xen_platform_op op; \
+	op.cmd = XENPF_efi_runtime_call; \
+	call.function = XEN_EFI_##what; \
+	call.misc = 0
+
+static efi_status_t xen_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
+{
+	int err;
+	DECLARE_CALL(get_time);
+
+	err = HYPERVISOR_platform_op(&op);
+	if (err)
+		return EFI_UNSUPPORTED;
+
+	if (tm) {
+		BUILD_BUG_ON(sizeof(*tm) != sizeof(call.u.get_time.time));
+		memcpy(tm, &call.u.get_time.time, sizeof(*tm));
+	}
+
+	if (tc) {
+		tc->resolution = call.u.get_time.resolution;
+		tc->accuracy = call.u.get_time.accuracy;
+		tc->sets_to_zero = !!(call.misc &
+				      XEN_EFI_GET_TIME_SET_CLEARS_NS);
+	}
+
+	return call.status;
+}
+
+static efi_status_t xen_efi_set_time(efi_time_t *tm)
+{
+	DECLARE_CALL(set_time);
+
+	BUILD_BUG_ON(sizeof(*tm) != sizeof(call.u.set_time));
+	memcpy(&call.u.set_time, tm, sizeof(*tm));
+
+	return HYPERVISOR_platform_op(&op) ? EFI_UNSUPPORTED : call.status;
+}
+
+static efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled,
+					    efi_bool_t *pending,
+					    efi_time_t *tm)
+{
+	int err;
+	DECLARE_CALL(get_wakeup_time);
+
+	err = HYPERVISOR_platform_op(&op);
+	if (err)
+		return EFI_UNSUPPORTED;
+
+	if (tm) {
+		BUILD_BUG_ON(sizeof(*tm) != sizeof(call.u.get_wakeup_time));
+		memcpy(tm, &call.u.get_wakeup_time, sizeof(*tm));
+	}
+
+	if (enabled)
+		*enabled = !!(call.misc & XEN_EFI_GET_WAKEUP_TIME_ENABLED);
+
+	if (pending)
+		*pending = !!(call.misc & XEN_EFI_GET_WAKEUP_TIME_PENDING);
+
+	return call.status;
+}
+
+static efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
+{
+	DECLARE_CALL(set_wakeup_time);
+
+	BUILD_BUG_ON(sizeof(*tm) != sizeof(call.u.set_wakeup_time));
+	if (enabled)
+		call.misc = XEN_EFI_SET_WAKEUP_TIME_ENABLE;
+	if (tm)
+		memcpy(&call.u.set_wakeup_time, tm, sizeof(*tm));
+	else
+		call.misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY;
+
+	return HYPERVISOR_platform_op(&op) ? EFI_UNSUPPORTED : call.status;
+}
+
+static efi_status_t xen_efi_get_variable(efi_char16_t *name,
+					 efi_guid_t *vendor,
+					 u32 *attr,
+					 unsigned long *data_size,
+					 void *data)
+{
+	int err;
+	DECLARE_CALL(get_variable);
+
+	set_xen_guest_handle(call.u.get_variable.name, name);
+	BUILD_BUG_ON(sizeof(*vendor) !=
+		     sizeof(call.u.get_variable.vendor_guid));
+	memcpy(&call.u.get_variable.vendor_guid, vendor, sizeof(*vendor));
+	call.u.get_variable.size = *data_size;
+	set_xen_guest_handle(call.u.get_variable.data, data);
+	err = HYPERVISOR_platform_op(&op);
+	if (err)
+		return EFI_UNSUPPORTED;
+
+	*data_size = call.u.get_variable.size;
+	*attr = call.misc;
+
+	return call.status;
+}
+
+static efi_status_t xen_efi_get_next_variable(unsigned long *name_size,
+					      efi_char16_t *name,
+					      efi_guid_t *vendor)
+{
+	int err;
+	DECLARE_CALL(get_next_variable_name);
+
+	call.u.get_next_variable_name.size = *name_size;
+	set_xen_guest_handle(call.u.get_next_variable_name.name, name);
+	BUILD_BUG_ON(sizeof(*vendor) !=
+		     sizeof(call.u.get_next_variable_name.vendor_guid));
+	memcpy(&call.u.get_next_variable_name.vendor_guid, vendor,
+	       sizeof(*vendor));
+	err = HYPERVISOR_platform_op(&op);
+	if (err)
+		return EFI_UNSUPPORTED;
+
+	*name_size = call.u.get_next_variable_name.size;
+	memcpy(vendor, &call.u.get_next_variable_name.vendor_guid,
+	       sizeof(*vendor));
+
+	return call.status;
+}
+
+static efi_status_t xen_efi_set_variable(efi_char16_t *name,
+					 efi_guid_t *vendor,
+					 unsigned long attr,
+					 unsigned long data_size,
+					 void *data)
+{
+	DECLARE_CALL(set_variable);
+
+	set_xen_guest_handle(call.u.set_variable.name, name);
+	call.misc = attr;
+	BUILD_BUG_ON(sizeof(*vendor) !=
+		     sizeof(call.u.set_variable.vendor_guid));
+	memcpy(&call.u.set_variable.vendor_guid, vendor, sizeof(*vendor));
+	call.u.set_variable.size = data_size;
+	set_xen_guest_handle(call.u.set_variable.data, data);
+
+	return HYPERVISOR_platform_op(&op) ? EFI_UNSUPPORTED : call.status;
+}
+
+static efi_status_t xen_efi_get_next_high_mono_count(u32 *count)
+{
+	int err;
+	DECLARE_CALL(get_next_high_monotonic_count);
+
+	err = HYPERVISOR_platform_op(&op);
+	if (err)
+		return EFI_UNSUPPORTED;
+
+	*count = call.misc;
+
+	return call.status;
+}
+
+#undef DECLARE_CALL
+#undef call
+
+struct efi __read_mostly efi = {
+	.mps                      = EFI_INVALID_TABLE_ADDR,
+	.acpi                     = EFI_INVALID_TABLE_ADDR,
+	.acpi20                   = EFI_INVALID_TABLE_ADDR,
+	.smbios                   = EFI_INVALID_TABLE_ADDR,
+	.sal_systab               = EFI_INVALID_TABLE_ADDR,
+	.boot_info                = EFI_INVALID_TABLE_ADDR,
+	.hcdp                     = EFI_INVALID_TABLE_ADDR,
+	.uga                      = EFI_INVALID_TABLE_ADDR,
+	.uv_systab                = EFI_INVALID_TABLE_ADDR,
+	.get_time                 = xen_efi_get_time,
+	.set_time                 = xen_efi_set_time,
+	.get_wakeup_time          = xen_efi_get_wakeup_time,
+	.set_wakeup_time          = xen_efi_set_wakeup_time,
+	.get_variable             = xen_efi_get_variable,
+	.get_next_variable        = xen_efi_get_next_variable,
+	.set_variable             = xen_efi_set_variable,
+	.get_next_high_mono_count = xen_efi_get_next_high_mono_count,
+};
+EXPORT_SYMBOL(efi);
+
+static int __init setup_noefi(char *arg)
+{
+	efi_enabled = 0;
+	return 0;
+}
+early_param("noefi", setup_noefi);
+
+
+int efi_set_rtc_mmss(unsigned long nowtime)
+{
+	int real_seconds, real_minutes;
+	efi_status_t 	status;
+	efi_time_t 	eft;
+	efi_time_cap_t 	cap;
+
+	status = efi.get_time(&eft, &cap);
+	if (status != EFI_SUCCESS) {
+		printk(KERN_ERR "Oops: efitime: can't read time!\n");
+		return -1;
+	}
+
+	real_seconds = nowtime % 60;
+	real_minutes = nowtime / 60;
+	if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
+		real_minutes += 30;
+	real_minutes %= 60;
+	eft.minute = real_minutes;
+	eft.second = real_seconds;
+
+	status = efi.set_time(&eft);
+	if (status != EFI_SUCCESS) {
+		printk(KERN_ERR "Oops: efitime: can't write time!\n");
+		return -1;
+	}
+	return 0;
+}
+
+unsigned long efi_get_time(void)
+{
+	efi_status_t status;
+	efi_time_t eft;
+	efi_time_cap_t cap;
+
+	status = efi.get_time(&eft, &cap);
+	if (status != EFI_SUCCESS) {
+		printk(KERN_ERR "Oops: efitime: can't read time!\n");
+		return mach_get_cmos_time();
+	}
+
+	return mktime(eft.year, eft.month, eft.day, eft.hour,
+		      eft.minute, eft.second);
+}
+
+void __init efi_probe(void)
+{
+	static struct xen_platform_op __initdata op = {
+		.cmd = XENPF_firmware_info,
+		.u.firmware_info = {
+			.type = XEN_FW_EFI_INFO,
+			.index = XEN_FW_EFI_CONFIG_TABLE
+		}
+	};
+
+	if (HYPERVISOR_platform_op(&op) == 0)
+		efi_enabled = 1;
+}
+
+void __init efi_init(void)
+{
+	efi_config_table_t *config_tables;
+	efi_char16_t c16[100];
+	char vendor[ARRAY_SIZE(c16)] = "unknown";
+	int ret, i;
+	struct xen_platform_op op;
+	union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
+
+	op.cmd = XENPF_firmware_info;
+	op.u.firmware_info.type = XEN_FW_EFI_INFO;
+
+	/*
+	 * Show what we know for posterity
+	 */
+	op.u.firmware_info.index = XEN_FW_EFI_VENDOR;
+	info->vendor.bufsz = sizeof(c16);
+	set_xen_guest_handle(info->vendor.name, c16);
+	ret = HYPERVISOR_platform_op(&op);
+	if (!ret) {
+		for (i = 0; i < sizeof(vendor) - 1 && c16[i]; ++i)
+			vendor[i] = c16[i];
+		vendor[i] = '\0';
+	} else
+		printk(KERN_ERR PFX "Could not get the firmware vendor!\n");
+
+	op.u.firmware_info.index = XEN_FW_EFI_VERSION;
+	ret = HYPERVISOR_platform_op(&op);
+	if (!ret)
+		printk(KERN_INFO "EFI v%u.%.02u by %s\n",
+		       info->version >> 16,
+		       info->version & 0xffff, vendor);
+	else
+		printk(KERN_ERR PFX "Could not get EFI revision!\n");
+
+	/*
+	 * Let's see what config tables the firmware passed to us.
+	 */
+	op.u.firmware_info.index = XEN_FW_EFI_CONFIG_TABLE;
+	if (HYPERVISOR_platform_op(&op))
+		BUG();
+	config_tables = early_ioremap(
+		info->cfg.addr,
+		info->cfg.nent * sizeof(efi_config_table_t));
+	if (config_tables == NULL)
+		panic("Could not map EFI Configuration Table!\n");
+
+	printk(KERN_INFO);
+	for (i = 0; i < info->cfg.nent; i++) {
+		if (!efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID)) {
+			efi.mps = config_tables[i].table;
+			printk(" MPS=0x%lx ", config_tables[i].table);
+		} else if (!efi_guidcmp(config_tables[i].guid,
+					ACPI_20_TABLE_GUID)) {
+			efi.acpi20 = config_tables[i].table;
+			printk(" ACPI 2.0=0x%lx ", config_tables[i].table);
+		} else if (!efi_guidcmp(config_tables[i].guid,
+					ACPI_TABLE_GUID)) {
+			efi.acpi = config_tables[i].table;
+			printk(" ACPI=0x%lx ", config_tables[i].table);
+		} else if (!efi_guidcmp(config_tables[i].guid,
+					SMBIOS_TABLE_GUID)) {
+			efi.smbios = config_tables[i].table;
+			printk(" SMBIOS=0x%lx ", config_tables[i].table);
+		} else if (!efi_guidcmp(config_tables[i].guid,
+					HCDP_TABLE_GUID)) {
+			efi.hcdp = config_tables[i].table;
+			printk(" HCDP=0x%lx ", config_tables[i].table);
+		} else if (!efi_guidcmp(config_tables[i].guid,
+					UGA_IO_PROTOCOL_GUID)) {
+			efi.uga = config_tables[i].table;
+			printk(" UGA=0x%lx ", config_tables[i].table);
+		}
+	}
+	printk("\n");
+	early_iounmap(config_tables, info->cfg.nent * sizeof(efi_config_table_t));
+
+	x86_platform.get_wallclock = efi_get_time;
+	x86_platform.set_wallclock = efi_set_rtc_mmss;
+}
+
+void __init efi_enter_virtual_mode(void) { }
+
+static struct platform_device rtc_efi_dev = {
+	.name = "rtc-efi",
+	.id = -1,
+};
+
+static int __init rtc_init(void)
+{
+	if (efi_enabled && platform_device_register(&rtc_efi_dev) < 0)
+		printk(KERN_ERR "unable to register rtc device...\n");
+
+	/* not necessarily an error */
+	return 0;
+}
+arch_initcall(rtc_init);
+
+/*
+ * Convenience functions to obtain memory types and attributes
+ */
+u32 efi_mem_type(unsigned long phys_addr)
+{
+	struct xen_platform_op op;
+	union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
+
+	op.cmd = XENPF_firmware_info;
+	op.u.firmware_info.type = XEN_FW_EFI_INFO;
+	op.u.firmware_info.index = XEN_FW_EFI_MEM_INFO;
+	info->mem.addr = phys_addr;
+	info->mem.size = 0;
+	return HYPERVISOR_platform_op(&op) ? 0 : info->mem.type;
+}
+
+u64 efi_mem_attributes(unsigned long phys_addr)
+{
+	struct xen_platform_op op;
+	union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
+
+	op.cmd = XENPF_firmware_info;
+	op.u.firmware_info.type = XEN_FW_EFI_INFO;
+	op.u.firmware_info.index = XEN_FW_EFI_MEM_INFO;
+	info->mem.addr = phys_addr;
+	info->mem.size = 0;
+	return HYPERVISOR_platform_op(&op) ? 0 : info->mem.attr;
+}
--- head-2011-05-23.orig/drivers/rtc/Kconfig	2011-06-21 15:35:45.000000000 +0200
+++ head-2011-05-23/drivers/rtc/Kconfig	2011-06-21 15:06:11.000000000 +0200
@@ -522,7 +522,7 @@ config RTC_DRV_DS1742
 
 config RTC_DRV_EFI
 	tristate "EFI RTC"
-	depends on IA64
+	depends on IA64 || (XEN && EFI)
 	help
 	  If you say yes here you will get support for the EFI
 	  Real Time Clock.
--- head-2011-05-23.orig/drivers/xen/console/console.c	2011-06-21 15:35:45.000000000 +0200
+++ head-2011-05-23/drivers/xen/console/console.c	2011-06-15 15:41:36.000000000 +0200
@@ -315,6 +315,7 @@ void __init dom0_init_screen_info(const 
 		break;
 
 	case XEN_VGATYPE_VESA_LFB:
+	case XEN_VGATYPE_EFI_LFB:
 		if (size < offsetof(struct dom0_vga_console_info,
 		                    u.vesa_lfb.gbl_caps))
 			break;
@@ -333,6 +334,10 @@ void __init dom0_init_screen_info(const 
 		screen_info.blue_pos = info->u.vesa_lfb.blue_pos;
 		screen_info.rsvd_size = info->u.vesa_lfb.rsvd_size;
 		screen_info.rsvd_pos = info->u.vesa_lfb.rsvd_pos;
+		if (info->video_type == XEN_VGATYPE_EFI_LFB) {
+			screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
+			break;
+		}
 		if (size >= offsetof(struct dom0_vga_console_info,
 		                     u.vesa_lfb.gbl_caps)
 		            + sizeof(info->u.vesa_lfb.gbl_caps))
--- head-2011-05-23.orig/include/linux/efi.h	2011-06-21 15:35:45.000000000 +0200
+++ head-2011-05-23/include/linux/efi.h	2011-06-10 11:12:39.000000000 +0200
@@ -249,7 +249,9 @@ struct efi_memory_map {
  * All runtime access to EFI goes through this structure:
  */
 extern struct efi {
+#ifndef CONFIG_XEN
 	efi_system_table_t *systab;	/* EFI system table */
+#endif
 	unsigned long mps;		/* MPS table */
 	unsigned long acpi;		/* ACPI table  (IA64 ext 0.71) */
 	unsigned long acpi20;		/* ACPI table  (ACPI 2.0) */
@@ -267,8 +269,10 @@ extern struct efi {
 	efi_get_next_variable_t *get_next_variable;
 	efi_set_variable_t *set_variable;
 	efi_get_next_high_mono_count_t *get_next_high_mono_count;
+#ifndef CONFIG_XEN
 	efi_reset_system_t *reset_system;
 	efi_set_virtual_address_map_t *set_virtual_address_map;
+#endif
 } efi;
 
 static inline int
--- head-2011-05-23.orig/include/xen/interface/platform.h	2011-06-21 15:35:45.000000000 +0200
+++ head-2011-05-23/include/xen/interface/platform.h	2011-06-17 16:07:28.000000000 +0200
@@ -114,10 +114,86 @@ 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 */
 #define XEN_FW_VBEDDC_INFO        3 /* from int 10 AX=4f15 */
+#define XEN_FW_EFI_INFO           4 /* from EFI */
+#define  XEN_FW_EFI_VERSION        0
+#define  XEN_FW_EFI_CONFIG_TABLE   1
+#define  XEN_FW_EFI_VENDOR         2
+#define  XEN_FW_EFI_MEM_INFO       3
 struct xenpf_firmware_info {
     /* IN variables. */
     uint32_t type;
@@ -148,6 +224,24 @@ struct xenpf_firmware_info {
             /* must refer to 128-byte buffer */
             XEN_GUEST_HANDLE(uint8) edid;
         } vbeddc_info; /* XEN_FW_VBEDDC_INFO */
+        union xenpf_efi_info {
+            uint32_t version;
+            struct {
+                uint64_t addr;                /* EFI_CONFIGURATION_TABLE */
+                uint32_t nent;
+            } cfg;
+            struct {
+                uint32_t revision;
+                uint32_t bufsz;               /* input, in bytes */
+                XEN_GUEST_HANDLE(void) name;  /* UCS-2/UTF-16 string */
+            } vendor;
+            struct {
+                uint64_t addr;
+                uint64_t size;
+                uint64_t attr;
+                uint32_t type;
+            } mem;
+        } efi_info; /* XEN_FW_EFI_INFO */
     } u;
 };
 typedef struct xenpf_firmware_info xenpf_firmware_info_t;
@@ -373,6 +467,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;
--- head-2011-05-23.orig/include/xen/interface/xen.h	2011-06-21 15:35:45.000000000 +0200
+++ head-2011-05-23/include/xen/interface/xen.h	2011-06-07 13:55:11.000000000 +0200
@@ -660,6 +660,7 @@ typedef struct dom0_vga_console_info {
     uint8_t video_type; /* DOM0_VGA_CONSOLE_??? */
 #define XEN_VGATYPE_TEXT_MODE_3 0x03
 #define XEN_VGATYPE_VESA_LFB    0x23
+#define XEN_VGATYPE_EFI_LFB     0x70
 
     union {
         struct {

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] x86-64: EFI runtime code
  2011-06-28  7:11   ` Jan Beulich
@ 2011-06-28  7:39     ` Keir Fraser
  2011-06-28  7:56       ` Jan Beulich
  0 siblings, 1 reply; 14+ messages in thread
From: Keir Fraser @ 2011-06-28  7:39 UTC (permalink / raw)
  To: Jan Beulich, Konrad Rzeszutek Wilk; +Cc: xen-devel

On 28/06/2011 08:11, "Jan Beulich" <JBeulich@novell.com> wrote:

>>>> On 27.06.11 at 18:25, Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> wrote:
>> On Mon, Jun 27, 2011 at 11:43:02AM +0100, Jan Beulich wrote:
>>> This allows Dom0 access to all suitable EFI runtime services. The
>> 
>> What type of patches for the upstream 3.0 kernel are needed to take
>> advantage of these new hypercalls?
> 
> I did not put any consideration in how to integrate this with the
> upstream kernel. For our kernel, I used the *-xen.? mechanism
> to have a parallel source file to arch/x86/platform/efi/efi.c, and
> excluded building of arch/x86/platform/efi/efi_stub_*.S and
> arch/x86/platform/efi/efi_*.c.
> 
> Patch below for reference.

Since the new hypercalls are 1:1 replacements for the EFI run-time calls (I
think?) we could perhaps keep most of Linux's EFI subsystem intact and spoof
it with a fake operations table containing hypercall stubs.

 -- Keir

> Jan
> 
> --- head-2011-05-23.orig/arch/x86/Kconfig 2011-04-14 11:32:40.000000000 +0200
> +++ head-2011-05-23/arch/x86/Kconfig 2011-06-09 17:04:17.000000000 +0200
> @@ -1511,7 +1511,7 @@ config ARCH_USES_PG_UNCACHED
>  
>  config EFI
> bool "EFI runtime service support"
> - depends on ACPI && !XEN
> + depends on ACPI && !XEN_UNPRIVILEGED_GUEST
> ---help---
>  This enables the kernel to use EFI runtime services that are
>  available (such as the EFI variable services).
> --- head-2011-05-23.orig/arch/x86/include/mach-xen/asm/setup.h 2011-06-21
> 15:35:45.000000000 +0200
> +++ head-2011-05-23/arch/x86/include/mach-xen/asm/setup.h 2011-06-15
> 15:26:22.000000000 +0200
> @@ -10,6 +10,12 @@ void reserve_pgtable_low(void);
>  
>  extern unsigned long xen_initrd_start;
>  
> +#ifdef CONFIG_EFI
> +void efi_probe(void);
> +#else
> +#define efi_probe() ((void)0)
> +#endif
> +
>  #endif
>  
>  #include_next <asm/setup.h>
> --- head-2011-05-23.orig/arch/x86/kernel/setup-xen.c 2011-06-10
> 12:12:00.000000000 +0200
> +++ head-2011-05-23/arch/x86/kernel/setup-xen.c 2011-06-10 12:42:34.000000000
> +0200
> @@ -870,6 +870,8 @@ void __init setup_arch(char **cmdline_p)
>                      xen_start_info->console.dom0.info_size);
> xen_start_info->console.domU.mfn = 0;
> xen_start_info->console.domU.evtchn = 0;
> +
> +  efi_probe();
> } else
> screen_info.orig_video_isVGA = 0;
> copy_edid();
> --- head-2011-05-23.orig/arch/x86/platform/efi/Makefile 2011-06-21
> 15:35:45.000000000 +0200
> +++ head-2011-05-23/arch/x86/platform/efi/Makefile 2011-06-09
> 17:06:13.000000000 +0200
> @@ -1 +1,2 @@
>  obj-$(CONFIG_EFI)   += efi.o efi_$(BITS).o efi_stub_$(BITS).o
> +disabled-obj-$(CONFIG_XEN) := efi_%$(BITS).o
> --- /dev/null 1970-01-01 00:00:00.000000000 +0000
> +++ head-2011-05-23/arch/x86/platform/efi/efi-xen.c 2011-06-21
> 15:24:29.000000000 +0200
> @@ -0,0 +1,430 @@
> +/*
> + * Common EFI (Extensible Firmware Interface) support functions
> + * Based on Extensible Firmware Interface Specification version 1.0
> + *
> + * Copyright (C) 1999 VA Linux Systems
> + * Copyright (C) 1999 Walt Drummond <drummond@valinux.com>
> + * Copyright (C) 1999-2002 Hewlett-Packard Co.
> + * David Mosberger-Tang <davidm@hpl.hp.com>
> + * Stephane Eranian <eranian@hpl.hp.com>
> + * Copyright (C) 2005-2008 Intel Co.
> + * Fenghua Yu <fenghua.yu@intel.com>
> + * Bibo Mao <bibo.mao@intel.com>
> + * Chandramouli Narayanan <mouli@linux.intel.com>
> + * Huang Ying <ying.huang@intel.com>
> + *
> + * Copied from efi_32.c to eliminate the duplicated code between EFI
> + * 32/64 support code. --ying 2007-10-26
> + *
> + * All EFI Runtime Services are not implemented yet as EFI only
> + * supports physical mode addressing on SoftSDV. This is to be fixed
> + * in a future version.  --drummond 1999-07-20
> + *
> + * Implemented EFI runtime services and virtual mode calls.  --davidm
> + *
> + * Goutham Rao: <goutham.rao@intel.com>
> + * Skip non-WB memory and ignore empty memory ranges.
> + */
> +
> +#include <linux/kernel.h>
> +#include <linux/init.h>
> +#include <linux/efi.h>
> +#include <linux/platform_device.h>
> +#include <linux/spinlock.h>
> +#include <linux/time.h>
> +
> +#include <asm/setup.h>
> +#include <asm/efi.h>
> +#include <asm/time.h>
> +#include <asm/cacheflush.h>
> +#include <asm/tlbflush.h>
> +#include <asm/x86_init.h>
> +
> +#include <xen/interface/platform.h>
> +
> +#define EFI_DEBUG 1
> +#define PFX   "EFI: "
> +
> +int __read_mostly efi_enabled;
> +EXPORT_SYMBOL(efi_enabled);
> +
> +#define call op.u.efi_runtime_call
> +#define DECLARE_CALL(what) \
> + struct xen_platform_op op; \
> + op.cmd = XENPF_efi_runtime_call; \
> + call.function = XEN_EFI_##what; \
> + call.misc = 0
> +
> +static efi_status_t xen_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
> +{
> + int err;
> + DECLARE_CALL(get_time);
> +
> + err = HYPERVISOR_platform_op(&op);
> + if (err)
> +  return EFI_UNSUPPORTED;
> +
> + if (tm) {
> +  BUILD_BUG_ON(sizeof(*tm) != sizeof(call.u.get_time.time));
> +  memcpy(tm, &call.u.get_time.time, sizeof(*tm));
> + }
> +
> + if (tc) {
> +  tc->resolution = call.u.get_time.resolution;
> +  tc->accuracy = call.u.get_time.accuracy;
> +  tc->sets_to_zero = !!(call.misc &
> +          XEN_EFI_GET_TIME_SET_CLEARS_NS);
> + }
> +
> + return call.status;
> +}
> +
> +static efi_status_t xen_efi_set_time(efi_time_t *tm)
> +{
> + DECLARE_CALL(set_time);
> +
> + BUILD_BUG_ON(sizeof(*tm) != sizeof(call.u.set_time));
> + memcpy(&call.u.set_time, tm, sizeof(*tm));
> +
> + return HYPERVISOR_platform_op(&op) ? EFI_UNSUPPORTED : call.status;
> +}
> +
> +static efi_status_t xen_efi_get_wakeup_time(efi_bool_t *enabled,
> +         efi_bool_t *pending,
> +         efi_time_t *tm)
> +{
> + int err;
> + DECLARE_CALL(get_wakeup_time);
> +
> + err = HYPERVISOR_platform_op(&op);
> + if (err)
> +  return EFI_UNSUPPORTED;
> +
> + if (tm) {
> +  BUILD_BUG_ON(sizeof(*tm) != sizeof(call.u.get_wakeup_time));
> +  memcpy(tm, &call.u.get_wakeup_time, sizeof(*tm));
> + }
> +
> + if (enabled)
> +  *enabled = !!(call.misc & XEN_EFI_GET_WAKEUP_TIME_ENABLED);
> +
> + if (pending)
> +  *pending = !!(call.misc & XEN_EFI_GET_WAKEUP_TIME_PENDING);
> +
> + return call.status;
> +}
> +
> +static efi_status_t xen_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t
> *tm)
> +{
> + DECLARE_CALL(set_wakeup_time);
> +
> + BUILD_BUG_ON(sizeof(*tm) != sizeof(call.u.set_wakeup_time));
> + if (enabled)
> +  call.misc = XEN_EFI_SET_WAKEUP_TIME_ENABLE;
> + if (tm)
> +  memcpy(&call.u.set_wakeup_time, tm, sizeof(*tm));
> + else
> +  call.misc |= XEN_EFI_SET_WAKEUP_TIME_ENABLE_ONLY;
> +
> + return HYPERVISOR_platform_op(&op) ? EFI_UNSUPPORTED : call.status;
> +}
> +
> +static efi_status_t xen_efi_get_variable(efi_char16_t *name,
> +      efi_guid_t *vendor,
> +      u32 *attr,
> +      unsigned long *data_size,
> +      void *data)
> +{
> + int err;
> + DECLARE_CALL(get_variable);
> +
> + set_xen_guest_handle(call.u.get_variable.name, name);
> + BUILD_BUG_ON(sizeof(*vendor) !=
> +       sizeof(call.u.get_variable.vendor_guid));
> + memcpy(&call.u.get_variable.vendor_guid, vendor, sizeof(*vendor));
> + call.u.get_variable.size = *data_size;
> + set_xen_guest_handle(call.u.get_variable.data, data);
> + err = HYPERVISOR_platform_op(&op);
> + if (err)
> +  return EFI_UNSUPPORTED;
> +
> + *data_size = call.u.get_variable.size;
> + *attr = call.misc;
> +
> + return call.status;
> +}
> +
> +static efi_status_t xen_efi_get_next_variable(unsigned long *name_size,
> +           efi_char16_t *name,
> +           efi_guid_t *vendor)
> +{
> + int err;
> + DECLARE_CALL(get_next_variable_name);
> +
> + call.u.get_next_variable_name.size = *name_size;
> + set_xen_guest_handle(call.u.get_next_variable_name.name, name);
> + BUILD_BUG_ON(sizeof(*vendor) !=
> +       sizeof(call.u.get_next_variable_name.vendor_guid));
> + memcpy(&call.u.get_next_variable_name.vendor_guid, vendor,
> +        sizeof(*vendor));
> + err = HYPERVISOR_platform_op(&op);
> + if (err)
> +  return EFI_UNSUPPORTED;
> +
> + *name_size = call.u.get_next_variable_name.size;
> + memcpy(vendor, &call.u.get_next_variable_name.vendor_guid,
> +        sizeof(*vendor));
> +
> + return call.status;
> +}
> +
> +static efi_status_t xen_efi_set_variable(efi_char16_t *name,
> +      efi_guid_t *vendor,
> +      unsigned long attr,
> +      unsigned long data_size,
> +      void *data)
> +{
> + DECLARE_CALL(set_variable);
> +
> + set_xen_guest_handle(call.u.set_variable.name, name);
> + call.misc = attr;
> + BUILD_BUG_ON(sizeof(*vendor) !=
> +       sizeof(call.u.set_variable.vendor_guid));
> + memcpy(&call.u.set_variable.vendor_guid, vendor, sizeof(*vendor));
> + call.u.set_variable.size = data_size;
> + set_xen_guest_handle(call.u.set_variable.data, data);
> +
> + return HYPERVISOR_platform_op(&op) ? EFI_UNSUPPORTED : call.status;
> +}
> +
> +static efi_status_t xen_efi_get_next_high_mono_count(u32 *count)
> +{
> + int err;
> + DECLARE_CALL(get_next_high_monotonic_count);
> +
> + err = HYPERVISOR_platform_op(&op);
> + if (err)
> +  return EFI_UNSUPPORTED;
> +
> + *count = call.misc;
> +
> + return call.status;
> +}
> +
> +#undef DECLARE_CALL
> +#undef call
> +
> +struct efi __read_mostly efi = {
> + .mps                      = EFI_INVALID_TABLE_ADDR,
> + .acpi                     = EFI_INVALID_TABLE_ADDR,
> + .acpi20                   = EFI_INVALID_TABLE_ADDR,
> + .smbios                   = EFI_INVALID_TABLE_ADDR,
> + .sal_systab               = EFI_INVALID_TABLE_ADDR,
> + .boot_info                = EFI_INVALID_TABLE_ADDR,
> + .hcdp                     = EFI_INVALID_TABLE_ADDR,
> + .uga                      = EFI_INVALID_TABLE_ADDR,
> + .uv_systab                = EFI_INVALID_TABLE_ADDR,
> + .get_time                 = xen_efi_get_time,
> + .set_time                 = xen_efi_set_time,
> + .get_wakeup_time          = xen_efi_get_wakeup_time,
> + .set_wakeup_time          = xen_efi_set_wakeup_time,
> + .get_variable             = xen_efi_get_variable,
> + .get_next_variable        = xen_efi_get_next_variable,
> + .set_variable             = xen_efi_set_variable,
> + .get_next_high_mono_count = xen_efi_get_next_high_mono_count,
> +};
> +EXPORT_SYMBOL(efi);
> +
> +static int __init setup_noefi(char *arg)
> +{
> + efi_enabled = 0;
> + return 0;
> +}
> +early_param("noefi", setup_noefi);
> +
> +
> +int efi_set_rtc_mmss(unsigned long nowtime)
> +{
> + int real_seconds, real_minutes;
> + efi_status_t  status;
> + efi_time_t  eft;
> + efi_time_cap_t  cap;
> +
> + status = efi.get_time(&eft, &cap);
> + if (status != EFI_SUCCESS) {
> +  printk(KERN_ERR "Oops: efitime: can't read time!\n");
> +  return -1;
> + }
> +
> + real_seconds = nowtime % 60;
> + real_minutes = nowtime / 60;
> + if (((abs(real_minutes - eft.minute) + 15)/30) & 1)
> +  real_minutes += 30;
> + real_minutes %= 60;
> + eft.minute = real_minutes;
> + eft.second = real_seconds;
> +
> + status = efi.set_time(&eft);
> + if (status != EFI_SUCCESS) {
> +  printk(KERN_ERR "Oops: efitime: can't write time!\n");
> +  return -1;
> + }
> + return 0;
> +}
> +
> +unsigned long efi_get_time(void)
> +{
> + efi_status_t status;
> + efi_time_t eft;
> + efi_time_cap_t cap;
> +
> + status = efi.get_time(&eft, &cap);
> + if (status != EFI_SUCCESS) {
> +  printk(KERN_ERR "Oops: efitime: can't read time!\n");
> +  return mach_get_cmos_time();
> + }
> +
> + return mktime(eft.year, eft.month, eft.day, eft.hour,
> +        eft.minute, eft.second);
> +}
> +
> +void __init efi_probe(void)
> +{
> + static struct xen_platform_op __initdata op = {
> +  .cmd = XENPF_firmware_info,
> +  .u.firmware_info = {
> +   .type = XEN_FW_EFI_INFO,
> +   .index = XEN_FW_EFI_CONFIG_TABLE
> +  }
> + };
> +
> + if (HYPERVISOR_platform_op(&op) == 0)
> +  efi_enabled = 1;
> +}
> +
> +void __init efi_init(void)
> +{
> + efi_config_table_t *config_tables;
> + efi_char16_t c16[100];
> + char vendor[ARRAY_SIZE(c16)] = "unknown";
> + int ret, i;
> + struct xen_platform_op op;
> + union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
> +
> + op.cmd = XENPF_firmware_info;
> + op.u.firmware_info.type = XEN_FW_EFI_INFO;
> +
> + /*
> +  * Show what we know for posterity
> +  */
> + op.u.firmware_info.index = XEN_FW_EFI_VENDOR;
> + info->vendor.bufsz = sizeof(c16);
> + set_xen_guest_handle(info->vendor.name, c16);
> + ret = HYPERVISOR_platform_op(&op);
> + if (!ret) {
> +  for (i = 0; i < sizeof(vendor) - 1 && c16[i]; ++i)
> +   vendor[i] = c16[i];
> +  vendor[i] = '\0';
> + } else
> +  printk(KERN_ERR PFX "Could not get the firmware vendor!\n");
> +
> + op.u.firmware_info.index = XEN_FW_EFI_VERSION;
> + ret = HYPERVISOR_platform_op(&op);
> + if (!ret)
> +  printk(KERN_INFO "EFI v%u.%.02u by %s\n",
> +         info->version >> 16,
> +         info->version & 0xffff, vendor);
> + else
> +  printk(KERN_ERR PFX "Could not get EFI revision!\n");
> +
> + /*
> +  * Let's see what config tables the firmware passed to us.
> +  */
> + op.u.firmware_info.index = XEN_FW_EFI_CONFIG_TABLE;
> + if (HYPERVISOR_platform_op(&op))
> +  BUG();
> + config_tables = early_ioremap(
> +  info->cfg.addr,
> +  info->cfg.nent * sizeof(efi_config_table_t));
> + if (config_tables == NULL)
> +  panic("Could not map EFI Configuration Table!\n");
> +
> + printk(KERN_INFO);
> + for (i = 0; i < info->cfg.nent; i++) {
> +  if (!efi_guidcmp(config_tables[i].guid, MPS_TABLE_GUID)) {
> +   efi.mps = config_tables[i].table;
> +   printk(" MPS=0x%lx ", config_tables[i].table);
> +  } else if (!efi_guidcmp(config_tables[i].guid,
> +     ACPI_20_TABLE_GUID)) {
> +   efi.acpi20 = config_tables[i].table;
> +   printk(" ACPI 2.0=0x%lx ", config_tables[i].table);
> +  } else if (!efi_guidcmp(config_tables[i].guid,
> +     ACPI_TABLE_GUID)) {
> +   efi.acpi = config_tables[i].table;
> +   printk(" ACPI=0x%lx ", config_tables[i].table);
> +  } else if (!efi_guidcmp(config_tables[i].guid,
> +     SMBIOS_TABLE_GUID)) {
> +   efi.smbios = config_tables[i].table;
> +   printk(" SMBIOS=0x%lx ", config_tables[i].table);
> +  } else if (!efi_guidcmp(config_tables[i].guid,
> +     HCDP_TABLE_GUID)) {
> +   efi.hcdp = config_tables[i].table;
> +   printk(" HCDP=0x%lx ", config_tables[i].table);
> +  } else if (!efi_guidcmp(config_tables[i].guid,
> +     UGA_IO_PROTOCOL_GUID)) {
> +   efi.uga = config_tables[i].table;
> +   printk(" UGA=0x%lx ", config_tables[i].table);
> +  }
> + }
> + printk("\n");
> + early_iounmap(config_tables, info->cfg.nent * sizeof(efi_config_table_t));
> +
> + x86_platform.get_wallclock = efi_get_time;
> + x86_platform.set_wallclock = efi_set_rtc_mmss;
> +}
> +
> +void __init efi_enter_virtual_mode(void) { }
> +
> +static struct platform_device rtc_efi_dev = {
> + .name = "rtc-efi",
> + .id = -1,
> +};
> +
> +static int __init rtc_init(void)
> +{
> + if (efi_enabled && platform_device_register(&rtc_efi_dev) < 0)
> +  printk(KERN_ERR "unable to register rtc device...\n");
> +
> + /* not necessarily an error */
> + return 0;
> +}
> +arch_initcall(rtc_init);
> +
> +/*
> + * Convenience functions to obtain memory types and attributes
> + */
> +u32 efi_mem_type(unsigned long phys_addr)
> +{
> + struct xen_platform_op op;
> + union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
> +
> + op.cmd = XENPF_firmware_info;
> + op.u.firmware_info.type = XEN_FW_EFI_INFO;
> + op.u.firmware_info.index = XEN_FW_EFI_MEM_INFO;
> + info->mem.addr = phys_addr;
> + info->mem.size = 0;
> + return HYPERVISOR_platform_op(&op) ? 0 : info->mem.type;
> +}
> +
> +u64 efi_mem_attributes(unsigned long phys_addr)
> +{
> + struct xen_platform_op op;
> + union xenpf_efi_info *info = &op.u.firmware_info.u.efi_info;
> +
> + op.cmd = XENPF_firmware_info;
> + op.u.firmware_info.type = XEN_FW_EFI_INFO;
> + op.u.firmware_info.index = XEN_FW_EFI_MEM_INFO;
> + info->mem.addr = phys_addr;
> + info->mem.size = 0;
> + return HYPERVISOR_platform_op(&op) ? 0 : info->mem.attr;
> +}
> --- head-2011-05-23.orig/drivers/rtc/Kconfig 2011-06-21 15:35:45.000000000
> +0200
> +++ head-2011-05-23/drivers/rtc/Kconfig 2011-06-21 15:06:11.000000000 +0200
> @@ -522,7 +522,7 @@ config RTC_DRV_DS1742
>  
>  config RTC_DRV_EFI
> tristate "EFI RTC"
> - depends on IA64
> + depends on IA64 || (XEN && EFI)
> help
>  If you say yes here you will get support for the EFI
>  Real Time Clock.
> --- head-2011-05-23.orig/drivers/xen/console/console.c 2011-06-21
> 15:35:45.000000000 +0200
> +++ head-2011-05-23/drivers/xen/console/console.c 2011-06-15
> 15:41:36.000000000 +0200
> @@ -315,6 +315,7 @@ void __init dom0_init_screen_info(const
> break;
>  
> case XEN_VGATYPE_VESA_LFB:
> + case XEN_VGATYPE_EFI_LFB:
> if (size < offsetof(struct dom0_vga_console_info,
>                    u.vesa_lfb.gbl_caps))
> break;
> @@ -333,6 +334,10 @@ void __init dom0_init_screen_info(const
> screen_info.blue_pos = info->u.vesa_lfb.blue_pos;
> screen_info.rsvd_size = info->u.vesa_lfb.rsvd_size;
> screen_info.rsvd_pos = info->u.vesa_lfb.rsvd_pos;
> +  if (info->video_type == XEN_VGATYPE_EFI_LFB) {
> +   screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
> +   break;
> +  }
> if (size >= offsetof(struct dom0_vga_console_info,
>                     u.vesa_lfb.gbl_caps)
>            + sizeof(info->u.vesa_lfb.gbl_caps))
> --- head-2011-05-23.orig/include/linux/efi.h 2011-06-21 15:35:45.000000000
> +0200
> +++ head-2011-05-23/include/linux/efi.h 2011-06-10 11:12:39.000000000 +0200
> @@ -249,7 +249,9 @@ struct efi_memory_map {
>   * All runtime access to EFI goes through this structure:
>   */
>  extern struct efi {
> +#ifndef CONFIG_XEN
> efi_system_table_t *systab; /* EFI system table */
> +#endif
> unsigned long mps;  /* MPS table */
> unsigned long acpi;  /* ACPI table  (IA64 ext 0.71) */
> unsigned long acpi20;  /* ACPI table  (ACPI 2.0) */
> @@ -267,8 +269,10 @@ extern struct efi {
> efi_get_next_variable_t *get_next_variable;
> efi_set_variable_t *set_variable;
> efi_get_next_high_mono_count_t *get_next_high_mono_count;
> +#ifndef CONFIG_XEN
> efi_reset_system_t *reset_system;
> efi_set_virtual_address_map_t *set_virtual_address_map;
> +#endif
>  } efi;
>  
>  static inline int
> --- head-2011-05-23.orig/include/xen/interface/platform.h 2011-06-21
> 15:35:45.000000000 +0200
> +++ head-2011-05-23/include/xen/interface/platform.h 2011-06-17
> 16:07:28.000000000 +0200
> @@ -114,10 +114,86 @@ 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 */
>  #define XEN_FW_VBEDDC_INFO        3 /* from int 10 AX=4f15 */
> +#define XEN_FW_EFI_INFO           4 /* from EFI */
> +#define  XEN_FW_EFI_VERSION        0
> +#define  XEN_FW_EFI_CONFIG_TABLE   1
> +#define  XEN_FW_EFI_VENDOR         2
> +#define  XEN_FW_EFI_MEM_INFO       3
>  struct xenpf_firmware_info {
>      /* IN variables. */
>      uint32_t type;
> @@ -148,6 +224,24 @@ struct xenpf_firmware_info {
>              /* must refer to 128-byte buffer */
>              XEN_GUEST_HANDLE(uint8) edid;
>          } vbeddc_info; /* XEN_FW_VBEDDC_INFO */
> +        union xenpf_efi_info {
> +            uint32_t version;
> +            struct {
> +                uint64_t addr;                /* EFI_CONFIGURATION_TABLE */
> +                uint32_t nent;
> +            } cfg;
> +            struct {
> +                uint32_t revision;
> +                uint32_t bufsz;               /* input, in bytes */
> +                XEN_GUEST_HANDLE(void) name;  /* UCS-2/UTF-16 string */
> +            } vendor;
> +            struct {
> +                uint64_t addr;
> +                uint64_t size;
> +                uint64_t attr;
> +                uint32_t type;
> +            } mem;
> +        } efi_info; /* XEN_FW_EFI_INFO */
>      } u;
>  };
>  typedef struct xenpf_firmware_info xenpf_firmware_info_t;
> @@ -373,6 +467,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;
> --- head-2011-05-23.orig/include/xen/interface/xen.h 2011-06-21
> 15:35:45.000000000 +0200
> +++ head-2011-05-23/include/xen/interface/xen.h 2011-06-07 13:55:11.000000000
> +0200
> @@ -660,6 +660,7 @@ typedef struct dom0_vga_console_info {
>      uint8_t video_type; /* DOM0_VGA_CONSOLE_??? */
>  #define XEN_VGATYPE_TEXT_MODE_3 0x03
>  #define XEN_VGATYPE_VESA_LFB    0x23
> +#define XEN_VGATYPE_EFI_LFB     0x70
>  
>      union {
>          struct {
> 
> 
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xensource.com
> http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] x86-64: EFI runtime code
  2011-06-28  7:39     ` Keir Fraser
@ 2011-06-28  7:56       ` Jan Beulich
  2011-06-28 15:36         ` Konrad Rzeszutek Wilk
  2011-06-28 16:05         ` Konrad Rzeszutek Wilk
  0 siblings, 2 replies; 14+ messages in thread
From: Jan Beulich @ 2011-06-28  7:56 UTC (permalink / raw)
  To: Keir Fraser, Konrad Rzeszutek Wilk; +Cc: xen-devel

>>> On 28.06.11 at 09:39, Keir Fraser <keir.xen@gmail.com> wrote:
> On 28/06/2011 08:11, "Jan Beulich" <JBeulich@novell.com> wrote:
> 
>>>>> On 27.06.11 at 18:25, Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> wrote:
>>> On Mon, Jun 27, 2011 at 11:43:02AM +0100, Jan Beulich wrote:
>>>> This allows Dom0 access to all suitable EFI runtime services. The
>>> 
>>> What type of patches for the upstream 3.0 kernel are needed to take
>>> advantage of these new hypercalls?
>> 
>> I did not put any consideration in how to integrate this with the
>> upstream kernel. For our kernel, I used the *-xen.? mechanism
>> to have a parallel source file to arch/x86/platform/efi/efi.c, and
>> excluded building of arch/x86/platform/efi/efi_stub_*.S and
>> arch/x86/platform/efi/efi_*.c.
>> 
>> Patch below for reference.
> 
> Since the new hypercalls are 1:1 replacements for the EFI run-time calls (I
> think?)

Yes, with a few exceptions of things that must not be done from
Dom0 (i.e. the ResetSystem() and SetVirtualAddressMap() ones).

> we could perhaps keep most of Linux's EFI subsystem intact and spoof
> it with a fake operations table containing hypercall stubs.

Indeed, that part ought to be simple. The question is which of the
(luckily few) other code paths need adjustment.

Jan

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] x86-64: EFI runtime code
  2011-06-28  7:56       ` Jan Beulich
@ 2011-06-28 15:36         ` Konrad Rzeszutek Wilk
  2011-06-28 16:38           ` Jan Beulich
  2011-06-28 16:05         ` Konrad Rzeszutek Wilk
  1 sibling, 1 reply; 14+ messages in thread
From: Konrad Rzeszutek Wilk @ 2011-06-28 15:36 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Keir Fraser, xen-devel

On Tue, Jun 28, 2011 at 08:56:03AM +0100, Jan Beulich wrote:
> >>> On 28.06.11 at 09:39, Keir Fraser <keir.xen@gmail.com> wrote:
> > On 28/06/2011 08:11, "Jan Beulich" <JBeulich@novell.com> wrote:
> > 
> >>>>> On 27.06.11 at 18:25, Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> wrote:
> >>> On Mon, Jun 27, 2011 at 11:43:02AM +0100, Jan Beulich wrote:
> >>>> This allows Dom0 access to all suitable EFI runtime services. The
> >>> 
> >>> What type of patches for the upstream 3.0 kernel are needed to take
> >>> advantage of these new hypercalls?
> >> 
> >> I did not put any consideration in how to integrate this with the
> >> upstream kernel. For our kernel, I used the *-xen.? mechanism
> >> to have a parallel source file to arch/x86/platform/efi/efi.c, and
> >> excluded building of arch/x86/platform/efi/efi_stub_*.S and
> >> arch/x86/platform/efi/efi_*.c.
> >> 
> >> Patch below for reference.
> > 
> > Since the new hypercalls are 1:1 replacements for the EFI run-time calls (I
> > think?)
> 
> Yes, with a few exceptions of things that must not be done from
> Dom0 (i.e. the ResetSystem() and SetVirtualAddressMap() ones).
> 
> > we could perhaps keep most of Linux's EFI subsystem intact and spoof
> > it with a fake operations table containing hypercall stubs.
> 
> Indeed, that part ought to be simple. The question is which of the
> (luckily few) other code paths need adjustment.

And to actually test it to make sure it boots.

How does one go about this? I do have an Intel box that has EFI shell - what
would I need to do?

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] x86-64: EFI runtime code
  2011-06-28  7:56       ` Jan Beulich
  2011-06-28 15:36         ` Konrad Rzeszutek Wilk
@ 2011-06-28 16:05         ` Konrad Rzeszutek Wilk
  2011-06-28 16:36           ` Jan Beulich
  1 sibling, 1 reply; 14+ messages in thread
From: Konrad Rzeszutek Wilk @ 2011-06-28 16:05 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Keir Fraser, xen-devel

On Tue, Jun 28, 2011 at 08:56:03AM +0100, Jan Beulich wrote:
> >>> On 28.06.11 at 09:39, Keir Fraser <keir.xen@gmail.com> wrote:
> > On 28/06/2011 08:11, "Jan Beulich" <JBeulich@novell.com> wrote:
> > 
> >>>>> On 27.06.11 at 18:25, Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> wrote:
> >>> On Mon, Jun 27, 2011 at 11:43:02AM +0100, Jan Beulich wrote:
> >>>> This allows Dom0 access to all suitable EFI runtime services. The
> >>> 
> >>> What type of patches for the upstream 3.0 kernel are needed to take
> >>> advantage of these new hypercalls?
> >> 
> >> I did not put any consideration in how to integrate this with the
> >> upstream kernel. For our kernel, I used the *-xen.? mechanism
> >> to have a parallel source file to arch/x86/platform/efi/efi.c, and
> >> excluded building of arch/x86/platform/efi/efi_stub_*.S and
> >> arch/x86/platform/efi/efi_*.c.
> >> 
> >> Patch below for reference.
> > 
> > Since the new hypercalls are 1:1 replacements for the EFI run-time calls (I
> > think?)
> 
> Yes, with a few exceptions of things that must not be done from
> Dom0 (i.e. the ResetSystem() and SetVirtualAddressMap() ones).
> 
> > we could perhaps keep most of Linux's EFI subsystem intact and spoof
> > it with a fake operations table containing hypercall stubs.
> 
> Indeed, that part ought to be simple. The question is which of the
> (luckily few) other code paths need adjustment.

What kind of minimal "stuff" is required from EFI for Dom0 consumption?

I see the need for the VGA console, and that looks easy enough.
The E820 is parsed by the Xen hypervisor, so XENMEM_machine_memory_map from Dom0
will take care of that.

The other information Dom0 needs is the ACPI DSDT to figure out the polarity
and trigger for the interrupts. Is the ACPI DSDT "lost" when it is running from EFI?

In the future we will need the _CST, _PSS (and its friends) to shuffle
the contents of that up to the hypervisor for CPU Cx/Px states. Does the ACPI
runtime code need to be aware of EFI?

What about ACPI S3? The contents of ACPI FADT table is required for that. Will
EFI make that obsolete?

I am just wondering whether Dom0 actually needs to know that EFI exists.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] x86-64: EFI runtime code
  2011-06-28 16:05         ` Konrad Rzeszutek Wilk
@ 2011-06-28 16:36           ` Jan Beulich
  2011-06-28 17:03             ` Konrad Rzeszutek Wilk
  0 siblings, 1 reply; 14+ messages in thread
From: Jan Beulich @ 2011-06-28 16:36 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk; +Cc: Keir Fraser, xen-devel

>>> On 28.06.11 at 18:05, Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> wrote:
> What kind of minimal "stuff" is required from EFI for Dom0 consumption?

The minimal set of things is obtaining the various pointers to
configuration tables (ACPI, MPS, SMBIOS).

> I see the need for the VGA console, and that looks easy enough.

There's no VGA console in modern UEFI, you only get a graphical
one (with no guarantee that it's VGA).

> The E820 is parsed by the Xen hypervisor, so XENMEM_machine_memory_map from 
> Dom0
> will take care of that.
> 
> The other information Dom0 needs is the ACPI DSDT to figure out the polarity
> and trigger for the interrupts. Is the ACPI DSDT "lost" when it is running 
> from EFI?

No, but it can't be retrieved the "traditional" way.

> In the future we will need the _CST, _PSS (and its friends) to shuffle
> the contents of that up to the hypervisor for CPU Cx/Px states. Does the 
> ACPI
> runtime code need to be aware of EFI?

No - ACPI is all the same except for the mechanism to retrieve the
root pointer.

> What about ACPI S3? The contents of ACPI FADT table is required for that. 
> Will
> EFI make that obsolete?

Same again.

> I am just wondering whether Dom0 actually needs to know that EFI exists.

Yes, it needs to, due to the table pointer retrieval differences. And
then there's the runtime services (RTC access, EFI variables) that
the OS ought to use. On the RTC side of things, a legacy free system
might not have a CMOS clock, and hence even native Linux is currently
broken in that respect (because the driver can be built only for IA64).
Access to the variables is necessary so you can control the EFI
environment (most importantly configure the boot loader) from within
the OS.

Jan

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] x86-64: EFI runtime code
  2011-06-28 15:36         ` Konrad Rzeszutek Wilk
@ 2011-06-28 16:38           ` Jan Beulich
  0 siblings, 0 replies; 14+ messages in thread
From: Jan Beulich @ 2011-06-28 16:38 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk; +Cc: Keir Fraser, xen-devel

>>> On 28.06.11 at 17:36, Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> wrote:
> How does one go about this? I do have an Intel box that has EFI shell - what
> would I need to do?

Build xen.efi, write up a config file for it to read (most importantly so
it knows what Dom0 kernel and initrd to use), and you should be
good to go (provided the EFI implementation isn't too flawed). This
being an EFI application you can simply run it from the shell prompt.

Jan

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] x86-64: EFI runtime code
  2011-06-28 16:36           ` Jan Beulich
@ 2011-06-28 17:03             ` Konrad Rzeszutek Wilk
  2011-06-29  6:50               ` Jan Beulich
  0 siblings, 1 reply; 14+ messages in thread
From: Konrad Rzeszutek Wilk @ 2011-06-28 17:03 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Keir Fraser, xen-devel

> > I see the need for the VGA console, and that looks easy enough.
> 
> There's no VGA console in modern UEFI, you only get a graphical
> one (with no guarantee that it's VGA).

I meant that the "struct screen_info *screen_info" needs to be populated
properly in the Linux side. And for that we just need to take care of the
extra new XEN_VGATYPE..EFI type.

> > The other information Dom0 needs is the ACPI DSDT to figure out the polarity
> > and trigger for the interrupts. Is the ACPI DSDT "lost" when it is running 
> > from EFI?
> 
> No, but it can't be retrieved the "traditional" way.
.. snip..
> No - ACPI is all the same except for the mechanism to retrieve the
> root pointer.

Ah, here it is: "acpi_os_get_root_pointer" uses the efi.acpi20 or
efi.acpi and the DMI scan uses efi.smbios.

And those physical addresses reside within a reserved E820 region or
a gap I hope.

> > I am just wondering whether Dom0 actually needs to know that EFI exists.
> 
> Yes, it needs to, due to the table pointer retrieval differences. And
> then there's the runtime services (RTC access, EFI variables) that
> the OS ought to use. On the RTC side of things, a legacy free system

I am just looking at the minimal to understand it.
> might not have a CMOS clock, and hence even native Linux is currently
> broken in that respect (because the driver can be built only for IA64).

We do switch to the Xen clock (which is to say that the hypervisor is
responsible for it) ... so I think we could skip the RTC in the Linux kernel.

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] x86-64: EFI runtime code
  2011-06-28 17:03             ` Konrad Rzeszutek Wilk
@ 2011-06-29  6:50               ` Jan Beulich
  2011-07-13 13:42                 ` Konrad Rzeszutek Wilk
  0 siblings, 1 reply; 14+ messages in thread
From: Jan Beulich @ 2011-06-29  6:50 UTC (permalink / raw)
  To: Konrad Rzeszutek Wilk; +Cc: Keir Fraser, xen-devel

>>> On 28.06.11 at 19:03, Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> wrote:
> Ah, here it is: "acpi_os_get_root_pointer" uses the efi.acpi20 or
> efi.acpi and the DMI scan uses efi.smbios.
> 
> And those physical addresses reside within a reserved E820 region or
> a gap I hope.

That's how it's supposed to be. If we find systems where it lives
elsewhere, we'll have to add workarounds (in Xen).

>> Yes, it needs to, due to the table pointer retrieval differences. And
>> then there's the runtime services (RTC access, EFI variables) that
>> the OS ought to use. On the RTC side of things, a legacy free system
> 
> I am just looking at the minimal to understand it.
>> might not have a CMOS clock, and hence even native Linux is currently
>> broken in that respect (because the driver can be built only for IA64).
> 
> We do switch to the Xen clock (which is to say that the hypervisor is
> responsible for it) ... so I think we could skip the RTC in the Linux 
> kernel.

No, Dom0 has to manage the RTC (and so it does today, at least
in all non-pvops kernels I know of).

Jan

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] x86-64: EFI runtime code
  2011-06-29  6:50               ` Jan Beulich
@ 2011-07-13 13:42                 ` Konrad Rzeszutek Wilk
  0 siblings, 0 replies; 14+ messages in thread
From: Konrad Rzeszutek Wilk @ 2011-07-13 13:42 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Keir Fraser, xen-devel

On Wed, Jun 29, 2011 at 07:50:38AM +0100, Jan Beulich wrote:
> >>> On 28.06.11 at 19:03, Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> wrote:
> > Ah, here it is: "acpi_os_get_root_pointer" uses the efi.acpi20 or
> > efi.acpi and the DMI scan uses efi.smbios.
> > 
> > And those physical addresses reside within a reserved E820 region or
> > a gap I hope.
> 
> That's how it's supposed to be. If we find systems where it lives
> elsewhere, we'll have to add workarounds (in Xen).
> 
> >> Yes, it needs to, due to the table pointer retrieval differences. And
> >> then there's the runtime services (RTC access, EFI variables) that
> >> the OS ought to use. On the RTC side of things, a legacy free system
> > 
> > I am just looking at the minimal to understand it.
> >> might not have a CMOS clock, and hence even native Linux is currently
> >> broken in that respect (because the driver can be built only for IA64).
> > 
> > We do switch to the Xen clock (which is to say that the hypervisor is
> > responsible for it) ... so I think we could skip the RTC in the Linux 
> > kernel.
> 
> No, Dom0 has to manage the RTC (and so it does today, at least
> in all non-pvops kernels I know of).

And it looks that the efi set/get vars are important for the efibootmgr, so
that, RTC, and ACPI RSDT pointer must be implemented somehow. The ACPI RSDT
can be potentially piggybacked http://marc.info/?i=E8CC3FDD41FF9Findou.takao@jp.fujitsu.com
by making that variable global. But for the RTC and set/get vars I am not
sure.

The good thing is that I finally got an EFI box so let me play with this.

On another topic - I saw you posted some patches upstream for EFI cleanup -
were you by any chance looking at implementing this in paravirt?

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 3/4] x86-64: EFI runtime code
@ 2011-07-13 14:32 Jan Beulich
  0 siblings, 0 replies; 14+ messages in thread
From: Jan Beulich @ 2011-07-13 14:32 UTC (permalink / raw)
  To: konrad.wilk; +Cc: keir.xen, xen-devel


[-- Attachment #1.1: Type: text/plain, Size: 308 bytes --]

>>> Konrad Rzeszutek Wilk  07/13/11 3:43 PM >>>
>On another topic - I saw you posted some patches upstream for EFI cleanup -
>were you by any chance looking at implementing this in paravirt?

No, not really - I was just noticing some issues that weren't correct
even for native's EFI support.

Jan


[-- Attachment #1.2: HTML --]
[-- Type: text/html, Size: 604 bytes --]

[-- Attachment #2: Type: text/plain, Size: 138 bytes --]

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xensource.com
http://lists.xensource.com/xen-devel

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2011-07-13 14:32 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-06-27 10:43 [PATCH 3/4] x86-64: EFI runtime code Jan Beulich
2011-06-27 16:25 ` Konrad Rzeszutek Wilk
2011-06-27 17:36   ` Keir Fraser
2011-06-28  7:11   ` Jan Beulich
2011-06-28  7:39     ` Keir Fraser
2011-06-28  7:56       ` Jan Beulich
2011-06-28 15:36         ` Konrad Rzeszutek Wilk
2011-06-28 16:38           ` Jan Beulich
2011-06-28 16:05         ` Konrad Rzeszutek Wilk
2011-06-28 16:36           ` Jan Beulich
2011-06-28 17:03             ` Konrad Rzeszutek Wilk
2011-06-29  6:50               ` Jan Beulich
2011-07-13 13:42                 ` Konrad Rzeszutek Wilk
2011-07-13 14:32 Jan Beulich

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.