References: bnc#702407

# HG changeset patch
# User Jan Beulich <jbeulich@novell.com>
# Date 1311407355 -3600
# Node ID 537918f518eec3d8e2e2dad403fce40303321523
# Parent  42edf1481c5704c8ce1eb171a713b5411df0551a
add privileged (dom0) kernel feature indication

With our switching away from supporting 32-bit Dom0 operation, users
complained that attempts (perhaps due to lack of knowledge of that
change) to boot the no longer privileged kernel in Dom0 resulted in
apparently silent failure. To make the mismatch explicit and visible,
add dom0 feature flag that the kernel can set to indicate operation as
dom0 is supported.

Due to the way elf_xen_parse_features() worked up to now (getting
fixed here), adding features indications to the old, string based ELF
note would make the respective kernel unusable on older hypervisors.
For that reason, a new ELF Note is being introduced that allows
specifying supported features as a bit array instead (with features
unknown to the hypervisor simply ignored, as now also done by
elf_xen_parse_features(), whereas here unknown kernel-required
features still keep the kernel [and hence VM] from booting).

Introduce and use elf_note_numeric_array() to be forward
compatible (or else an old hypervisor wouldn't be able to parse kernel
specified features occupying more than 64 bits - thanks, Ian!).

Signed-off-by: Jan Beulich <jbeulich@novell.com>

# HG changeset patch
# User Jan Beulich <jbeulich@novell.com>
# Date 1311598088 -3600
# Node ID 50ddc200a60cad3929a79a992f09145fd39af49d
# Parent  d8725d9fb8657874011d2f2772f5e970b24dfe9b
fix regression from c/s 23735:537918f518ee

This was checking presence of the wrong (old) ELF note. I don't really
understand how this failed consistently only for one of the xen-boot
tests...

Signed-off-by: Jan Beulich <jbeulich@novell.com>

Index: xen-4.1.6-testing/tools/libxc/xc_dom_elfloader.c
===================================================================
--- xen-4.1.6-testing.orig/tools/libxc/xc_dom_elfloader.c
+++ xen-4.1.6-testing/tools/libxc/xc_dom_elfloader.c
@@ -357,6 +357,13 @@ static elf_errorstatus xc_dom_parse_elf_
         goto out;
     }
 
+    if ( elf_xen_feature_get(XENFEAT_dom0, dom->parms.f_required) )
+    {
+        xc_dom_panic(dom->xch, XC_INVALID_KERNEL, "%s: Kernel does not"
+                     " support unprivileged (DomU) operation", __FUNCTION__);
+        return -EINVAL;
+    }
+
     /* find kernel segment */
     dom->kernel_seg.vstart = dom->parms.virt_kstart;
     dom->kernel_seg.vend   = dom->parms.virt_kend;
Index: xen-4.1.6-testing/xen/arch/ia64/xen/domain.c
===================================================================
--- xen-4.1.6-testing.orig/xen/arch/ia64/xen/domain.c
+++ xen-4.1.6-testing/xen/arch/ia64/xen/domain.c
@@ -2165,6 +2165,13 @@ int __init construct_dom0(struct domain
 		return -1;
 	}
 
+	if (parms.elf_notes[XEN_ELFNOTE_SUPPORTED_FEATURES].type != XEN_ENT_NONE &&
+	    !test_bit(XENFEAT_dom0, parms.f_supported))
+	{
+		printk("Kernel does not support Dom0 operation\n");
+		return -1;
+	}
+
 	p_start = parms.virt_base;
 	pkern_start = parms.virt_kstart;
 	pkern_end = parms.virt_kend;
Index: xen-4.1.6-testing/xen/arch/x86/domain_build.c
===================================================================
--- xen-4.1.6-testing.orig/xen/arch/x86/domain_build.c
+++ xen-4.1.6-testing/xen/arch/x86/domain_build.c
@@ -418,6 +418,13 @@ int __init construct_dom0(
         goto out;
     }
 
+    if ( parms.elf_notes[XEN_ELFNOTE_SUPPORTED_FEATURES].type != XEN_ENT_NONE &&
+         !test_bit(XENFEAT_dom0, parms.f_supported) )
+    {
+        printk("Kernel does not support Dom0 operation\n");
+        return -EINVAL;
+    }
+
 #if defined(__x86_64__)
     if ( compat32 )
     {
Index: xen-4.1.6-testing/xen/common/kernel.c
===================================================================
--- xen-4.1.6-testing.orig/xen/common/kernel.c
+++ xen-4.1.6-testing/xen/common/kernel.c
@@ -289,6 +289,8 @@ DO(xen_version)(int cmd, XEN_GUEST_HANDL
                     (1U << XENFEAT_auto_translated_physmap);
             if ( supervisor_mode_kernel )
                 fi.submap |= 1U << XENFEAT_supervisor_mode_kernel;
+            if ( current->domain == dom0 )
+                fi.submap |= 1U << XENFEAT_dom0;
 #ifdef CONFIG_X86
             if ( !is_hvm_vcpu(current) )
                 fi.submap |= (1U << XENFEAT_mmu_pt_update_preserve_ad) |
Index: xen-4.1.6-testing/xen/common/libelf/libelf-dominfo.c
===================================================================
--- xen-4.1.6-testing.orig/xen/common/libelf/libelf-dominfo.c
+++ xen-4.1.6-testing/xen/common/libelf/libelf-dominfo.c
@@ -26,7 +26,8 @@ static const char *const elf_xen_feature
     [XENFEAT_writable_descriptor_tables] = "writable_descriptor_tables",
     [XENFEAT_auto_translated_physmap] = "auto_translated_physmap",
     [XENFEAT_supervisor_mode_kernel] = "supervisor_mode_kernel",
-    [XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb"
+    [XENFEAT_pae_pgdir_above_4gb] = "pae_pgdir_above_4gb",
+    [XENFEAT_dom0] = "dom0"
 };
 static const unsigned elf_xen_features =
 sizeof(elf_xen_feature_names) / sizeof(elf_xen_feature_names[0]);
@@ -82,7 +83,7 @@ elf_errorstatus elf_xen_parse_features(c
                 }
             }
         }
-        if ( i == elf_xen_features )
+        if ( i == elf_xen_features && required && feature[0] == '!' )
             return -1;
     }
 
@@ -113,6 +114,7 @@ elf_errorstatus elf_xen_parse_note(struc
         [XEN_ELFNOTE_LOADER] = { "LOADER", 1},
         [XEN_ELFNOTE_PAE_MODE] = { "PAE_MODE", 1},
         [XEN_ELFNOTE_FEATURES] = { "FEATURES", 1},
+        [XEN_ELFNOTE_SUPPORTED_FEATURES] = { "SUPPORTED_FEATURES", 0},
         [XEN_ELFNOTE_BSD_SYMTAB] = { "BSD_SYMTAB", 1},
         [XEN_ELFNOTE_SUSPEND_CANCEL] = { "SUSPEND_CANCEL", 0 },
         [XEN_ELFNOTE_MOD_START_PFN] = { "MOD_START_PFN", 0 },
@@ -121,7 +123,7 @@ elf_errorstatus elf_xen_parse_note(struc
 
     const char *str = NULL;
     uint64_t val = 0;
-    unsigned type = elf_uval(elf, note, type);
+    unsigned i, type = elf_uval(elf, note, type);
 
     if ( (type >= sizeof(note_desc) / sizeof(note_desc[0])) ||
          (note_desc[type].name == NULL) )
@@ -202,6 +204,12 @@ elf_errorstatus elf_xen_parse_note(struc
             return -1;
         break;
 
+    case XEN_ELFNOTE_SUPPORTED_FEATURES:
+        for ( i = 0; i < XENFEAT_NR_SUBMAPS; ++i )
+            parms->f_supported[i] |= elf_note_numeric_array(
+                elf, note, sizeof(*parms->f_supported), i);
+        break;
+
     }
     return 0;
 }
Index: xen-4.1.6-testing/xen/common/libelf/libelf-tools.c
===================================================================
--- xen-4.1.6-testing.orig/xen/common/libelf/libelf-tools.c
+++ xen-4.1.6-testing/xen/common/libelf/libelf-tools.c
@@ -319,6 +319,26 @@ uint64_t elf_note_numeric(struct elf_bin
     }
 }
 
+uint64_t elf_note_numeric_array(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note,
+                                unsigned int unitsz, unsigned int idx)
+{
+    elf_ptrval desc = elf_note_desc(elf, note);
+    unsigned int descsz = elf_uval(elf, note, descsz);
+
+    if ( descsz % unitsz || idx >= descsz / unitsz )
+        return 0;
+    switch (unitsz)
+    {
+    case 1:
+    case 2:
+    case 4:
+    case 8:
+        return elf_access_unsigned(elf, desc, idx * unitsz, unitsz);
+    default:
+        return 0;
+    }
+}
+
 ELF_HANDLE_DECL(elf_note) elf_note_next(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note)
 {
     unsigned namesz = (elf_uval(elf, note, namesz) + 3) & ~3;
Index: xen-4.1.6-testing/xen/include/public/elfnote.h
===================================================================
--- xen-4.1.6-testing.orig/xen/include/public/elfnote.h
+++ xen-4.1.6-testing/xen/include/public/elfnote.h
@@ -179,9 +179,22 @@
 #define XEN_ELFNOTE_MOD_START_PFN 16
 
 /*
+ * The features supported by this kernel (numeric).
+ *
+ * Other than XEN_ELFNOTE_FEATURES on pre-4.2 Xen, this note allows a
+ * kernel to specify support for features that older hypervisors don't
+ * know about. The set of features 4.2 and newer hypervisors will
+ * consider supported by the kernel is the combination of the sets
+ * specified through this and the string note.
+ *
+ * LEGACY: FEATURES
+ */
+#define XEN_ELFNOTE_SUPPORTED_FEATURES 17
+
+/*
  * The number of the highest elfnote defined.
  */
-#define XEN_ELFNOTE_MAX XEN_ELFNOTE_MOD_START_PFN
+#define XEN_ELFNOTE_MAX XEN_ELFNOTE_SUPPORTED_FEATURES
 
 /*
  * System information exported through crash notes.
Index: xen-4.1.6-testing/xen/include/public/features.h
===================================================================
--- xen-4.1.6-testing.orig/xen/include/public/features.h
+++ xen-4.1.6-testing/xen/include/public/features.h
@@ -75,7 +75,10 @@
 #define XENFEAT_hvm_safe_pvclock           9
 
 /* x86: pirq can be used by HVM guests */
-#define XENFEAT_hvm_pirqs           10
+#define XENFEAT_hvm_pirqs                 10
+
+/* operation as Dom0 is supported */
+#define XENFEAT_dom0                      11
 
 #define XENFEAT_NR_SUBMAPS 1
 
Index: xen-4.1.6-testing/xen/include/xen/libelf.h
===================================================================
--- xen-4.1.6-testing.orig/xen/include/xen/libelf.h
+++ xen-4.1.6-testing/xen/include/xen/libelf.h
@@ -332,6 +332,8 @@ ELF_HANDLE_DECL(elf_sym) elf_sym_by_inde
 const char *elf_note_name(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note); /* may return NULL */
 elf_ptrval elf_note_desc(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note);
 uint64_t elf_note_numeric(struct elf_binary *elf, ELF_HANDLE_DECL(elf_note) note);
+uint64_t elf_note_numeric_array(struct elf_binary *, ELF_HANDLE_DECL(elf_note) note,
+                                unsigned int unitsz, unsigned int idx);
 
 /*
  * If you use elf_note_next in a loop, you must put a nontrivial upper
