xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
* [v5][PATCH 00/16] Fix RMRR
@ 2015-07-07  6:17 Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map Tiejun Chen
                   ` (15 more replies)
  0 siblings, 16 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel

v5:

* Fold our original patch #2 and #3 as this new, and here
  introduce a new, clear_identity_p2m_entry, which can wrapper
  guest_physmap_remove_page(). And we use this to clean our
  identity mapping. 

* Just leave one bit XEN_DOMCTL_DEV_RDM_RELAXED as our policy flag, so
  now "0" means "strict" and "1" means "relaxed", and also make DT device
  ignore the flag field simply. And then correct all associated code
  comments.

* Just make sure the per-device plicy always override the global policy,
  and so cleanup some associated comments and the patch head description.

* Improve some descriptions in doc.

* Make all rdm variables specific to .hvm

* Inside patch #6, we're trying to rename that field, is_64bar, inside struct
  bars with flag, and then extend to also indicate if this bar is already
  allocated.

* Inside patch 11, Rename xc_device_get_rdm() with libxl__xc_device_get_rdm(),
  and then replace malloc() with libxl__malloc(), and finally cleanup this fallout.
  libxl__xc_device_get_rdm() should return proper libxl error code, ERROR_FAIL.
  Then instead, the allocated RDM entries would be returned with an out parameter.

* The original patch #13 is sent out separately since actually this is not related
  to RMRR.

v4:

* Change one condition inside patch #2, "xen/x86/p2m: introduce
  set_identity_p2m_entry",

  if ( p2mt == p2m_invalid || p2mt == p2m_mmio_dm )

 to make sure we just catch our requirement.

* Inside patch #3, "xen/vtd: create RMRR mapping",
  Instead of intel_iommu_unmap_page(), we should use
  guest_physmap_remove_page() to unmap rmrr mapping correctly. And drop
  iommu_map_page() since actually ept_set_entry() can do this
  internally.

* Inside patch #4, "xen/passthrough: extend hypercall to support rdm
  reservation policy", add code comments to describer why we fix to set a
  policy flag in some cases like adding a device to hwdomain, and removing
  a device from user domain. And fix one judging condition

  domctl->u.assign_device.flag == XEN_DOMCTL_DEV_NO_RDM
  -> domctl->u.assign_device.flag != XEN_DOMCTL_DEV_NO_RDM

  Additionally, also add to range check the flag passed to make future
  extensions possible (and to avoid ambiguity on what out of range values
  would mean).

* Inside patch #6, "hvmloader: get guest memory map into memory_map[]", we
  move some codes related to e820 to that specific file, e820.c, and consolidate
  "printf()+BUG()" and "BUG_ON()", and also avoid another fixed width type for
  the parameter of get_mem_mapping_layout()

* Inside patch #7, "hvmloader/pci: skip reserved ranges"
  We have to re-design this as follows:

  #1. Goal

  MMIO region should exclude all reserved device memory

  #2. Requirements

  #2.1 Still need to make sure MMIO region is fit all pci devices as before

  #2.2 Accommodate the not aligned reserved memory regions

  If I'm missing something let me know.

  #3. How to

  #3.1 Address #2.1

  We need to either of populating more RAM, or of expanding more highmem. But
  we should know just 64bit-bar can work with highmem, and as you mentioned we
  also should avoid expanding highmem as possible. So my implementation is to 
  allocate 32bit-bar and 64bit-bar orderly.

  1>. The first allocation round just to 32bit-bar

  If we can finish allocating all 32bit-bar, we just go to allocate 64bit-bar
  with all remaining resources including low pci memory.

  If not, we need to calculate how much RAM should be populated to allocate the 
  remaining 32bit-bars, then populate sufficient RAM as exp_mem_resource to go
  to the second allocation round 2>.

  2>. The second allocation round to the remaining 32bit-bar

  We should can finish allocating all 32bit-bar in theory, then go to the third
  allocation round 3>.

  3>. The third allocation round to 64bit-bar

  We'll try to first allocate from the remaining low memory resource. If that
  isn't enough, we try to expand highmem to allocate for 64bit-bar. This process
  should be same as the original.

  #3.2 Address #2.2

  I'm trying to accommodate the not aligned reserved memory regions:

  We should skip all reserved device memory, but we also need to check if other
  smaller bars can be allocated if a mmio hole exists between resource->base and
  reserved device memory. If a hole exists between base and reserved device
  memory, lets go out simply to try allocate for next bar since all bars are in
  descending order of size. If not, we need to move resource->base to reserved_end
  just to reallocate this bar

* Inside of patch #8, "hvmloader/e820: construct guest e820 table", we need to
  adjust highmme if lowmem is changed such as hvmloader has to populate more
  RAM to allocate bars.

* Inside of patch #11, "tools: introduce some new parameters to set rdm policy",
  we don't define init_val for for libxl_rdm_reserve_type since its just zero,
  and grab those changes to xl/libxlu to as a final patch.

* Inside of patch #12, "passes rdm reservation policy", fix one typo,
  s/unkwon/unknown. And in command description, we should use "[]" to indicate 
  it's optional for that extended xl command, pci-attach.

* Patch #13 is separated from current patch #14 since this is specific to xc.

* Inside of patch #14, "tools/libxl: detect and avoid conflicts with RDM", and
  just unconditionally set *nr_entries to 0. And additionally, we grab to all
  stuffs to provide a parameter to set our predefined boundary dynamically to as
  a separated patch later

* Inside of patch #16, "tools/libxl: extend XENMEM_set_memory_map", we use
  goto style error handling, and instead of NOGC, we shoud use
  libxl__malloc(gc,XXX) to allocate local e820.

Overall, we refined several the patch head descriptions and code comments.

v3:

* Rearrange all patches orderly as Wei suggested
* Rebase on the latest tree
* Address some Wei's comments on tools side
* Two changes for runtime cycle
   patch #2,xen/x86/p2m: introduce set_identity_p2m_entry, on hypervisor side

  a>. Introduce paging_mode_translate()
  Otherwise, we'll see this error when boot Xen/Dom0

(XEN) Assertion 'paging_mode_translate(p2m->domain)' failed at p2m-pt.c:702
(XEN) ----[ Xen-4.6-unstable  x86_64  debug=y  Tainted:    C ]----
....
(XEN) Xen call trace:
(XEN)    [<ffff82d0801f53db>] p2m_pt_get_entry+0x29/0x558
(XEN)    [<ffff82d0801f0b5c>] set_identity_p2m_entry+0xfc/0x1f0
(XEN)    [<ffff82d08014ebc8>] rmrr_identity_mapping+0x154/0x1ce
(XEN)    [<ffff82d0802abb46>] intel_iommu_hwdom_init+0x76/0x158
(XEN)    [<ffff82d0802ab169>] iommu_hwdom_init+0x179/0x188
(XEN)    [<ffff82d0802cc608>] construct_dom0+0x2fed/0x35d8
(XEN)    [<ffff82d0802bdaa0>] __start_xen+0x22d8/0x2381
(XEN)    [<ffff82d080100067>] __high_start+0x53/0x55
(XEN)
(XEN)
(XEN) ****************************************
(XEN) Panic on CPU 0:
(XEN) Assertion 'paging_mode_translate(p2m->domain)' failed at p2m-pt.c:702

Note I don't copy all info since I think the above is enough.

  b>. Actually we still need to use "mfn_x(mfn) == INVALID_MFN" to confirm
  we're getting an invalid mfn.

* Add patch #16 to handle those devices which share same RMRR.

v2:

* Instead of that fixed predefined rdm memory boundary, we'd like to
  introduce a parameter, "rdm_mem_boundary", to set this threshold value.

* Remove that existing USB hack.

* Make sure the MMIO regions all fit in the available resource window

* Rename our policy, "force/try" -> "strict/relaxed"

* Indeed, Wei and Jan gave me more and more comments to refine codes
  * Code style
  * Better and reasonable code implementation
  * Correct or improve code comments.

* A little bit to work well with ARM.

Open:

* We should fail assigning device which has a shared RMRR with
another device. We can only do group assignment when RMRR is shared
among devices.

We need more time to figure a good policy/way out because something
is not clear to me.

As you know all devices are owned by Dom0 firstly before we create any
DomU, right? Do we allow Dom0 still own a group device while assign another
device in the same group?

Really appreciate any comments to policy.


v1:

RMRR is an acronym for Reserved Memory Region Reporting, expected to
be used for legacy usages (such as USB, UMA Graphics, etc.) requiring
reserved memory. Special treatment is required in system software to
setup those reserved regions in IOMMU translation structures, otherwise
passing through a device with RMRR reported may not work correctly.

This patch set tries to enhance existing Xen RMRR implementation to fix
various reported and theoretical problems. Most noteworthy changes are
to setup identity mapping in p2m layer and handle possible conflicts between
reported regions and gfn space. Initial proposal can be found at:
    http://lists.xenproject.org/archives/html/xen-devel/2015-01/msg00524.html
and after a long discussion a summarized agreement is here:
    http://lists.xen.org/archives/html/xen-devel/2015-01/msg01580.html

Below is a key summary of this patch set according to agreed proposal:

1. Use RDM (Reserved Device Memory) name in user space as a general 
description instead of using ACPI RMRR name directly.

2. Introduce configuration parameters to allow user control both per-device 
and global RDM resources along with desired policies upon a detected conflict.

3. Introduce a new hypercall to query global and per-device RDM resources.

4. Extend libxl to be a central place to manage RDM resources and handle 
potential conflicts between reserved regions and gfn space. One simplification
goal is made to keep existing lowmem / mmio / highmem layout which is
passed around various function blocks. So a reasonable assumption
is made, that conflicts falling into below areas are not re-arranged otherwise
it will result in a more scattered layout:
    a) in highmem region (>4G)
    b) in lowmem region, and below a predefined boundary (default 2G)
  a) is a new assumption not discussed before. From VT-d spec this is 
possible but no such observation in real-world. So we can make this
reasonable assumption until there's real usage on it.

5. Extend XENMEM_set_memory_map usable for HVM guest, and then have
libxl to use that hypercall to carry RDM information to hvmloader. There
is one difference from original discussion. Previously we discussed to
introduce a new E820 type specifically for RDM entries. After more thought
we think it's OK to just tag them as E820_reserved. Actually hvmloader
doesn't need to know whether the reserved entries come from RDM or
from other purposes. 

6. Then in hvmloader the change is generic for XENMEM_memory_map
change. Given a predefined memory layout, hvmloader should avoid
allocating all reserved entries for other usages (opregion, mmio, etc.)

7. Extend existing device passthrough hypercall to carry conflict handling
policy.

8. Setup identity map in p2m layer for RMRRs reported for the given
device. And conflicts are handled according to specified policy in hypercall.

Current patch set contains core enhancements calling for comments.
There are still several tasks not implemented now. We'll include them
in final version after RFC is agreed:

- remove existing USB hack
- detect and fail assigning device which has a shared RMRR with another device
- add a config parameter to configure that memory boundary flexibly
- In the case of hotplug we also need to figure out a way to fix that policy
  conflict between the per-pci policy and the global policy but firstly we think
  we'd better collect some good or correct ideas to step next in RFC. 

So here I made this as RFC to collect your any comments.

----------------------------------------------------------------
Jan Beulich (1):
      xen: introduce XENMEM_reserved_device_memory_map

Tiejun Chen (15):
      xen/vtd: create RMRR mapping
      xen/passthrough: extend hypercall to support rdm reservation policy
      xen: enable XENMEM_memory_map in hvm
      hvmloader: get guest memory map into memory_map[]
      hvmloader/pci: skip reserved ranges
      hvmloader/e820: construct guest e820 table
      tools/libxc: Expose new hypercall xc_reserved_device_memory_map
      tools: extend xc_assign_device() to support rdm reservation policy
      tools: introduce some new parameters to set rdm policy
      tools/libxl: detect and avoid conflicts with RDM
      tools: introduce a new parameter to set a predefined rdm boundary
      libxl: construct e820 map with RDM information for HVM guest
      xen/vtd: enable USB device assignment
      xen/vtd: prevent from assign the device with shared rmrr
      tools: parse to enable new rdm policy parameters

Jan Beulich (1):
      xen: introduce XENMEM_reserved_device_memory_map

 docs/man/xl.cfg.pod.5                       | 106 ++++++++
 docs/misc/vtd.txt                           |  24 ++
 tools/firmware/hvmloader/e820.c             | 115 ++++++++-
 tools/firmware/hvmloader/e820.h             |   7 +
 tools/firmware/hvmloader/hvmloader.c        |   2 +
 tools/firmware/hvmloader/pci.c              | 194 +++++++++++---
 tools/firmware/hvmloader/util.c             |  26 ++
 tools/firmware/hvmloader/util.h             |  12 +
 tools/libxc/include/xenctrl.h               |  11 +-
 tools/libxc/xc_domain.c                     |  45 +++-
 tools/libxl/libxl.h                         |   6 +
 tools/libxl/libxl_create.c                  |  13 +-
 tools/libxl/libxl_dm.c                      | 267 ++++++++++++++++++++
 tools/libxl/libxl_dom.c                     |  16 +-
 tools/libxl/libxl_internal.h                |  37 ++-
 tools/libxl/libxl_pci.c                     |  12 +-
 tools/libxl/libxl_types.idl                 |  26 ++
 tools/libxl/libxl_x86.c                     |  83 ++++++
 tools/libxl/libxlu_pci.c                    |  92 +++++++
 tools/libxl/libxlutil.h                     |   4 +
 tools/libxl/xl_cmdimpl.c                    |  16 ++
 tools/ocaml/libs/xc/xenctrl_stubs.c         |  16 +-
 tools/python/xen/lowlevel/xc/xc.c           |  30 ++-
 xen/arch/x86/hvm/hvm.c                      |   2 -
 xen/arch/x86/mm.c                           |   6 -
 xen/arch/x86/mm/p2m.c                       |  43 +++-
 xen/common/compat/memory.c                  |  66 +++++
 xen/common/memory.c                         |  64 +++++
 xen/drivers/passthrough/amd/pci_amd_iommu.c |   3 +-
 xen/drivers/passthrough/arm/smmu.c          |   2 +-
 xen/drivers/passthrough/device_tree.c       |   3 +-
 xen/drivers/passthrough/iommu.c             |  10 +
 xen/drivers/passthrough/pci.c               |  15 +-
 xen/drivers/passthrough/vtd/dmar.c          |  32 +++
 xen/drivers/passthrough/vtd/dmar.h          |   1 -
 xen/drivers/passthrough/vtd/extern.h        |   1 +
 xen/drivers/passthrough/vtd/iommu.c         |  87 +++++--
 xen/drivers/passthrough/vtd/utils.c         |   7 -
 xen/include/asm-x86/p2m.h                   |  13 +-
 xen/include/public/domctl.h                 |   3 +
 xen/include/public/memory.h                 |  32 ++-
 xen/include/xen/iommu.h                     |  12 +-
 xen/include/xen/pci.h                       |   2 +
 xen/include/xlat.lst                        |   3 +-
 44 files changed, 1450 insertions(+), 117 deletions(-)

Thanks
Tiejun

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

* [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07 11:17   ` Ian Jackson
  2015-07-07  6:17 ` [v5][PATCH 02/16] xen/vtd: create RMRR mapping Tiejun Chen
                   ` (14 subsequent siblings)
  15 siblings, 1 reply; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel; +Cc: Yang Zhang, Kevin Tian, Jan Beulich

From: Jan Beulich <jbeulich@suse.com>

This is a prerequisite for punching holes into HVM and PVH guests' P2M
to allow passing through devices that are associated with (on VT-d)
RMRRs.

CC: Jan Beulich <jbeulich@suse.com>
CC: Yang Zhang <yang.z.zhang@intel.com>
CC: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Jan Beulich <jbeulich@suse.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
---
v5:

* Nothing is changed.

v4:

* Nothing is changed.

 xen/common/compat/memory.c           | 66 ++++++++++++++++++++++++++++++++++++
 xen/common/memory.c                  | 64 ++++++++++++++++++++++++++++++++++
 xen/drivers/passthrough/iommu.c      | 10 ++++++
 xen/drivers/passthrough/vtd/dmar.c   | 32 +++++++++++++++++
 xen/drivers/passthrough/vtd/extern.h |  1 +
 xen/drivers/passthrough/vtd/iommu.c  |  1 +
 xen/include/public/memory.h          | 32 ++++++++++++++++-
 xen/include/xen/iommu.h              | 10 ++++++
 xen/include/xen/pci.h                |  2 ++
 xen/include/xlat.lst                 |  3 +-
 10 files changed, 219 insertions(+), 2 deletions(-)

diff --git a/xen/common/compat/memory.c b/xen/common/compat/memory.c
index b258138..b608496 100644
--- a/xen/common/compat/memory.c
+++ b/xen/common/compat/memory.c
@@ -17,6 +17,45 @@ CHECK_TYPE(domid);
 CHECK_mem_access_op;
 CHECK_vmemrange;
 
+#ifdef HAS_PASSTHROUGH
+struct get_reserved_device_memory {
+    struct compat_reserved_device_memory_map map;
+    unsigned int used_entries;
+};
+
+static int get_reserved_device_memory(xen_pfn_t start, xen_ulong_t nr,
+                                      u32 id, void *ctxt)
+{
+    struct get_reserved_device_memory *grdm = ctxt;
+    u32 sbdf;
+    struct compat_reserved_device_memory rdm = {
+        .start_pfn = start, .nr_pages = nr
+    };
+
+    sbdf = PCI_SBDF2(grdm->map.seg, grdm->map.bus, grdm->map.devfn);
+    if ( (grdm->map.flag & PCI_DEV_RDM_ALL) || (sbdf == id) )
+    {
+        if ( grdm->used_entries < grdm->map.nr_entries )
+        {
+            if ( rdm.start_pfn != start || rdm.nr_pages != nr )
+                return -ERANGE;
+
+            if ( __copy_to_compat_offset(grdm->map.buffer,
+                                         grdm->used_entries,
+                                         &rdm,
+                                         1) )
+            {
+                return -EFAULT;
+            }
+        }
+        ++grdm->used_entries;
+        return 1;
+    }
+
+    return 0;
+}
+#endif
+
 int compat_memory_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) compat)
 {
     int split, op = cmd & MEMOP_CMD_MASK;
@@ -303,6 +342,33 @@ int compat_memory_op(unsigned int cmd, XEN_GUEST_HANDLE_PARAM(void) compat)
             break;
         }
 
+#ifdef HAS_PASSTHROUGH
+        case XENMEM_reserved_device_memory_map:
+        {
+            struct get_reserved_device_memory grdm;
+
+            if ( copy_from_guest(&grdm.map, compat, 1) ||
+                 !compat_handle_okay(grdm.map.buffer, grdm.map.nr_entries) )
+                return -EFAULT;
+
+            grdm.used_entries = 0;
+            rc = iommu_get_reserved_device_memory(get_reserved_device_memory,
+                                                  &grdm);
+
+            if ( !rc && grdm.map.nr_entries < grdm.used_entries )
+                rc = -ENOBUFS;
+
+            grdm.map.nr_entries = grdm.used_entries;
+            if ( grdm.map.nr_entries )
+            {
+                if ( __copy_to_guest(compat, &grdm.map, 1) )
+                    rc = -EFAULT;
+            }
+
+            return rc;
+        }
+#endif
+
         default:
             return compat_arch_memory_op(cmd, compat);
         }
diff --git a/xen/common/memory.c b/xen/common/memory.c
index c84fcdd..7b6281b 100644
--- a/xen/common/memory.c
+++ b/xen/common/memory.c
@@ -748,6 +748,43 @@ static int construct_memop_from_reservation(
     return 0;
 }
 
+#ifdef HAS_PASSTHROUGH
+struct get_reserved_device_memory {
+    struct xen_reserved_device_memory_map map;
+    unsigned int used_entries;
+};
+
+static int get_reserved_device_memory(xen_pfn_t start, xen_ulong_t nr,
+                                      u32 id, void *ctxt)
+{
+    struct get_reserved_device_memory *grdm = ctxt;
+    u32 sbdf;
+
+    sbdf = PCI_SBDF2(grdm->map.seg, grdm->map.bus, grdm->map.devfn);
+    if ( (grdm->map.flag & PCI_DEV_RDM_ALL) || (sbdf == id) )
+    {
+        if ( grdm->used_entries < grdm->map.nr_entries )
+        {
+            struct xen_reserved_device_memory rdm = {
+                .start_pfn = start, .nr_pages = nr
+            };
+
+            if ( __copy_to_guest_offset(grdm->map.buffer,
+                                        grdm->used_entries,
+                                        &rdm,
+                                        1) )
+            {
+                return -EFAULT;
+            }
+        }
+        ++grdm->used_entries;
+        return 1;
+    }
+
+    return 0;
+}
+#endif
+
 long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
 {
     struct domain *d;
@@ -1162,6 +1199,33 @@ long do_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
         break;
     }
 
+#ifdef HAS_PASSTHROUGH
+    case XENMEM_reserved_device_memory_map:
+    {
+        struct get_reserved_device_memory grdm;
+
+        if ( copy_from_guest(&grdm.map, arg, 1) ||
+             !guest_handle_okay(grdm.map.buffer, grdm.map.nr_entries) )
+            return -EFAULT;
+
+        grdm.used_entries = 0;
+        rc = iommu_get_reserved_device_memory(get_reserved_device_memory,
+                                              &grdm);
+
+        if ( !rc && grdm.map.nr_entries < grdm.used_entries )
+            rc = -ENOBUFS;
+
+        grdm.map.nr_entries = grdm.used_entries;
+        if ( grdm.map.nr_entries )
+        {
+            if ( __copy_to_guest(arg, &grdm.map, 1) )
+                rc = -EFAULT;
+        }
+
+        break;
+    }
+#endif
+
     default:
         rc = arch_memory_op(cmd, arg);
         break;
diff --git a/xen/drivers/passthrough/iommu.c b/xen/drivers/passthrough/iommu.c
index 06cb38f..0b2ef52 100644
--- a/xen/drivers/passthrough/iommu.c
+++ b/xen/drivers/passthrough/iommu.c
@@ -375,6 +375,16 @@ void iommu_crash_shutdown(void)
     iommu_enabled = iommu_intremap = 0;
 }
 
+int iommu_get_reserved_device_memory(iommu_grdm_t *func, void *ctxt)
+{
+    const struct iommu_ops *ops = iommu_get_ops();
+
+    if ( !iommu_enabled || !ops->get_reserved_device_memory )
+        return 0;
+
+    return ops->get_reserved_device_memory(func, ctxt);
+}
+
 bool_t iommu_has_feature(struct domain *d, enum iommu_feature feature)
 {
     const struct hvm_iommu *hd = domain_hvm_iommu(d);
diff --git a/xen/drivers/passthrough/vtd/dmar.c b/xen/drivers/passthrough/vtd/dmar.c
index 2b07be9..a730de5 100644
--- a/xen/drivers/passthrough/vtd/dmar.c
+++ b/xen/drivers/passthrough/vtd/dmar.c
@@ -893,3 +893,35 @@ int platform_supports_x2apic(void)
     unsigned int mask = ACPI_DMAR_INTR_REMAP | ACPI_DMAR_X2APIC_OPT_OUT;
     return cpu_has_x2apic && ((dmar_flags & mask) == ACPI_DMAR_INTR_REMAP);
 }
+
+int intel_iommu_get_reserved_device_memory(iommu_grdm_t *func, void *ctxt)
+{
+    struct acpi_rmrr_unit *rmrr, *rmrr_cur = NULL;
+    int rc = 0;
+    unsigned int i;
+    u16 bdf;
+
+    for_each_rmrr_device ( rmrr, bdf, i )
+    {
+        if ( rmrr != rmrr_cur )
+        {
+            rc = func(PFN_DOWN(rmrr->base_address),
+                      PFN_UP(rmrr->end_address) -
+                        PFN_DOWN(rmrr->base_address),
+                      PCI_SBDF(rmrr->segment, bdf),
+                      ctxt);
+
+            if ( unlikely(rc < 0) )
+                return rc;
+
+            if ( !rc )
+                continue;
+
+            /* Just go next. */
+            if ( rc == 1 )
+                rmrr_cur = rmrr;
+        }
+    }
+
+    return 0;
+}
diff --git a/xen/drivers/passthrough/vtd/extern.h b/xen/drivers/passthrough/vtd/extern.h
index 5524dba..f9ee9b0 100644
--- a/xen/drivers/passthrough/vtd/extern.h
+++ b/xen/drivers/passthrough/vtd/extern.h
@@ -75,6 +75,7 @@ int domain_context_mapping_one(struct domain *domain, struct iommu *iommu,
                                u8 bus, u8 devfn, const struct pci_dev *);
 int domain_context_unmap_one(struct domain *domain, struct iommu *iommu,
                              u8 bus, u8 devfn);
+int intel_iommu_get_reserved_device_memory(iommu_grdm_t *func, void *ctxt);
 
 unsigned int io_apic_read_remap_rte(unsigned int apic, unsigned int reg);
 void io_apic_write_remap_rte(unsigned int apic,
diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c
index 48820ea..44ed23d 100644
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -2491,6 +2491,7 @@ const struct iommu_ops intel_iommu_ops = {
     .crash_shutdown = vtd_crash_shutdown,
     .iotlb_flush = intel_iommu_iotlb_flush,
     .iotlb_flush_all = intel_iommu_iotlb_flush_all,
+    .get_reserved_device_memory = intel_iommu_get_reserved_device_memory,
     .dump_p2m_table = vtd_dump_p2m_table,
 };
 
diff --git a/xen/include/public/memory.h b/xen/include/public/memory.h
index 832559a..7b25275 100644
--- a/xen/include/public/memory.h
+++ b/xen/include/public/memory.h
@@ -573,7 +573,37 @@ struct xen_vnuma_topology_info {
 typedef struct xen_vnuma_topology_info xen_vnuma_topology_info_t;
 DEFINE_XEN_GUEST_HANDLE(xen_vnuma_topology_info_t);
 
-/* Next available subop number is 27 */
+/*
+ * With some legacy devices, certain guest-physical addresses cannot safely
+ * be used for other purposes, e.g. to map guest RAM.  This hypercall
+ * enumerates those regions so the toolstack can avoid using them.
+ */
+#define XENMEM_reserved_device_memory_map   27
+struct xen_reserved_device_memory {
+    xen_pfn_t start_pfn;
+    xen_ulong_t nr_pages;
+};
+typedef struct xen_reserved_device_memory xen_reserved_device_memory_t;
+DEFINE_XEN_GUEST_HANDLE(xen_reserved_device_memory_t);
+
+struct xen_reserved_device_memory_map {
+    /* IN */
+    /* Currently just one bit to indicate checkng all Reserved Device Memory. */
+#define PCI_DEV_RDM_ALL   0x1
+    uint32_t        flag;
+    /* IN */
+    uint16_t        seg;
+    uint8_t         bus;
+    uint8_t         devfn;
+    /* IN/OUT */
+    unsigned int    nr_entries;
+    /* OUT */
+    XEN_GUEST_HANDLE(xen_reserved_device_memory_t) buffer;
+};
+typedef struct xen_reserved_device_memory_map xen_reserved_device_memory_map_t;
+DEFINE_XEN_GUEST_HANDLE(xen_reserved_device_memory_map_t);
+
+/* Next available subop number is 28 */
 
 #endif /* __XEN_PUBLIC_MEMORY_H__ */
 
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
index b30bf41..e2f584d 100644
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -126,6 +126,14 @@ int iommu_do_dt_domctl(struct xen_domctl *, struct domain *,
 
 struct page_info;
 
+/*
+ * Any non-zero value returned from callbacks of this type will cause the
+ * function the callback was handed to terminate its iteration. Assigning
+ * meaning of these non-zero values is left to the top level caller /
+ * callback pair.
+ */
+typedef int iommu_grdm_t(xen_pfn_t start, xen_ulong_t nr, u32 id, void *ctxt);
+
 struct iommu_ops {
     int (*init)(struct domain *d);
     void (*hwdom_init)(struct domain *d);
@@ -157,12 +165,14 @@ struct iommu_ops {
     void (*crash_shutdown)(void);
     void (*iotlb_flush)(struct domain *d, unsigned long gfn, unsigned int page_count);
     void (*iotlb_flush_all)(struct domain *d);
+    int (*get_reserved_device_memory)(iommu_grdm_t *, void *);
     void (*dump_p2m_table)(struct domain *d);
 };
 
 void iommu_suspend(void);
 void iommu_resume(void);
 void iommu_crash_shutdown(void);
+int iommu_get_reserved_device_memory(iommu_grdm_t *, void *);
 
 void iommu_share_p2m_table(struct domain *d);
 
diff --git a/xen/include/xen/pci.h b/xen/include/xen/pci.h
index 3908146..d176e8b 100644
--- a/xen/include/xen/pci.h
+++ b/xen/include/xen/pci.h
@@ -33,6 +33,8 @@
 #define PCI_DEVFN2(bdf) ((bdf) & 0xff)
 #define PCI_BDF(b,d,f)  ((((b) & 0xff) << 8) | PCI_DEVFN(d,f))
 #define PCI_BDF2(b,df)  ((((b) & 0xff) << 8) | ((df) & 0xff))
+#define PCI_SBDF(s,bdf) (((s & 0xffff) << 16) | (bdf & 0xffff))
+#define PCI_SBDF2(s,b,df) (((s & 0xffff) << 16) | PCI_BDF2(b,df))
 
 struct pci_dev_info {
     bool_t is_extfn;
diff --git a/xen/include/xlat.lst b/xen/include/xlat.lst
index 9c9fd9a..dd23559 100644
--- a/xen/include/xlat.lst
+++ b/xen/include/xlat.lst
@@ -61,9 +61,10 @@
 !	memory_exchange			memory.h
 !	memory_map			memory.h
 !	memory_reservation		memory.h
-?	mem_access_op		memory.h
+?	mem_access_op			memory.h
 !	pod_target			memory.h
 !	remove_from_physmap		memory.h
+!	reserved_device_memory_map	memory.h
 ?	vmemrange			memory.h
 !	vnuma_topology_info		memory.h
 ?	physdev_eoi			physdev.h
-- 
1.9.1

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

* [v5][PATCH 02/16] xen/vtd: create RMRR mapping
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 03/16] xen/passthrough: extend hypercall to support rdm reservation policy Tiejun Chen
                   ` (13 subsequent siblings)
  15 siblings, 0 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel
  Cc: Kevin Tian, Keir Fraser, Andrew Cooper, Tim Deegan, Jan Beulich,
	Yang Zhang

RMRR reserved regions must be setup in the pfn space with an identity
mapping to reported mfn. However existing code has problem to setup
correct mapping when VT-d shares EPT page table, so lead to problem
when assigning devices (e.g GPU) with RMRR reported. So instead, this
patch aims to setup identity mapping in p2m layer, regardless of
whether EPT is shared or not. And we still keep creating VT-d table.

And we also need to introduce a pair of helper to create/clear this
sort of identity mapping as follows:

set_identity_p2m_entry():

If the gfn space is unoccupied, we just set the mapping. If space
is already occupied by desired identity mapping, do nothing.
Otherwise, failure is returned.

clear_identity_p2m_entry():

We just define macro to wrapper guest_physmap_remove_page() with
a returning value as necessary.

CC: Tim Deegan <tim@xen.org>
CC: Keir Fraser <keir@xen.org>
CC: Jan Beulich <jbeulich@suse.com>
CC: Andrew Cooper <andrew.cooper3@citrix.com>
CC: Yang Zhang <yang.z.zhang@intel.com>
CC: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Reviewed-by: Tim Deegan <tim@xen.org>
Acked-by: George Dunlap <george.dunlap@eu.citrix.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
---
v5:

* Fold our original patch #2 and #3 as this new

* Introduce a new, clear_identity_p2m_entry, which can wrapper
  guest_physmap_remove_page(). And we use this to clean our
  identity mapping. 

v4:

* Change that orginal condition,

  if ( p2mt == p2m_invalid || p2mt == p2m_mmio_dm )
  
  to make sure we catch those invalid mfn mapping as we expected.

* To have

  if ( !paging_mode_translate(p2m->domain) )
    return 0;

  at the start, instead of indenting the whole body of the function
  in an inner scope. 

* extend guest_physmap_remove_page() to return a value as a proper
  unmapping helper

* Instead of intel_iommu_unmap_page(), we should use
  guest_physmap_remove_page() to unmap rmrr mapping correctly. 

* Drop iommu_map_page() since actually ept_set_entry() can do this
  internally.

 xen/arch/x86/mm/p2m.c               | 40 +++++++++++++++++++++++++++++++++++--
 xen/drivers/passthrough/vtd/iommu.c |  5 ++---
 xen/include/asm-x86/p2m.h           | 13 +++++++++---
 3 files changed, 50 insertions(+), 8 deletions(-)

diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 6b39733..99a26ca 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -584,14 +584,16 @@ p2m_remove_page(struct p2m_domain *p2m, unsigned long gfn, unsigned long mfn,
                          p2m->default_access);
 }
 
-void
+int
 guest_physmap_remove_page(struct domain *d, unsigned long gfn,
                           unsigned long mfn, unsigned int page_order)
 {
     struct p2m_domain *p2m = p2m_get_hostp2m(d);
+    int rc;
     gfn_lock(p2m, gfn, page_order);
-    p2m_remove_page(p2m, gfn, mfn, page_order);
+    rc = p2m_remove_page(p2m, gfn, mfn, page_order);
     gfn_unlock(p2m, gfn, page_order);
+    return rc;
 }
 
 int
@@ -898,6 +900,40 @@ int set_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
     return set_typed_p2m_entry(d, gfn, mfn, p2m_mmio_direct, access);
 }
 
+int set_identity_p2m_entry(struct domain *d, unsigned long gfn,
+                           p2m_access_t p2ma)
+{
+    p2m_type_t p2mt;
+    p2m_access_t a;
+    mfn_t mfn;
+    struct p2m_domain *p2m = p2m_get_hostp2m(d);
+    int ret;
+
+    if ( !paging_mode_translate(p2m->domain) )
+        return 0;
+
+    gfn_lock(p2m, gfn, 0);
+
+    mfn = p2m->get_entry(p2m, gfn, &p2mt, &a, 0, NULL);
+
+    if ( p2mt == p2m_invalid || p2mt == p2m_mmio_dm )
+        ret = p2m_set_entry(p2m, gfn, _mfn(gfn), PAGE_ORDER_4K,
+                            p2m_mmio_direct, p2ma);
+    else if ( mfn_x(mfn) == gfn && p2mt == p2m_mmio_direct && a == p2ma )
+        ret = 0;
+    else
+    {
+        ret = -EBUSY;
+        printk(XENLOG_G_WARNING
+               "Cannot setup identity map d%d:%lx,"
+               " gfn already mapped to %lx.\n",
+               d->domain_id, gfn, mfn_x(mfn));
+    }
+
+    gfn_unlock(p2m, gfn, 0);
+    return ret;
+}
+
 /* Returns: 0 for success, -errno for failure */
 int clear_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn)
 {
diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c
index 44ed23d..8415958 100644
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -1839,7 +1839,7 @@ static int rmrr_identity_mapping(struct domain *d, bool_t map,
 
             while ( base_pfn < end_pfn )
             {
-                if ( intel_iommu_unmap_page(d, base_pfn) )
+                if ( clear_identity_p2m_entry(d, base_pfn, 0) )
                     ret = -ENXIO;
                 base_pfn++;
             }
@@ -1855,8 +1855,7 @@ static int rmrr_identity_mapping(struct domain *d, bool_t map,
 
     while ( base_pfn < end_pfn )
     {
-        int err = intel_iommu_map_page(d, base_pfn, base_pfn,
-                                       IOMMUF_readable|IOMMUF_writable);
+        int err = set_identity_p2m_entry(d, base_pfn, p2m_access_rw);
 
         if ( err )
             return err;
diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
index b49c09b..190a286 100644
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -503,9 +503,9 @@ static inline int guest_physmap_add_page(struct domain *d,
 }
 
 /* Remove a page from a domain's p2m table */
-void guest_physmap_remove_page(struct domain *d,
-                               unsigned long gfn,
-                               unsigned long mfn, unsigned int page_order);
+int guest_physmap_remove_page(struct domain *d,
+                              unsigned long gfn,
+                              unsigned long mfn, unsigned int page_order);
 
 /* Set a p2m range as populate-on-demand */
 int guest_physmap_mark_populate_on_demand(struct domain *d, unsigned long gfn,
@@ -543,6 +543,13 @@ int set_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
                        p2m_access_t access);
 int clear_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn);
 
+/* Set identity addresses in the p2m table (for pass-through) */
+int set_identity_p2m_entry(struct domain *d, unsigned long gfn,
+                           p2m_access_t p2ma);
+
+#define clear_identity_p2m_entry(d, gfn, page_order) \
+                        guest_physmap_remove_page(d, gfn, gfn, page_order)
+
 /* Add foreign mapping to the guest's p2m table. */
 int p2m_add_foreign(struct domain *tdom, unsigned long fgfn,
                     unsigned long gpfn, domid_t foreign_domid);
-- 
1.9.1

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

* [v5][PATCH 03/16] xen/passthrough: extend hypercall to support rdm reservation policy
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 02/16] xen/vtd: create RMRR mapping Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 04/16] xen: enable XENMEM_memory_map in hvm Tiejun Chen
                   ` (12 subsequent siblings)
  15 siblings, 0 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel
  Cc: Kevin Tian, Keir Fraser, Jan Beulich, Andrew Cooper, Tim Deegan,
	Aravind Gopalakrishnan, Suravee Suthikulpanit, Yang Zhang,
	Stefano Stabellini, Ian Campbell

This patch extends the existing hypercall to support rdm reservation policy.
We return error or just throw out a warning message depending on whether
the policy is "strict" or "relaxed" when reserving RDM regions in pfn space.
Note in some special cases, e.g. add a device to hwdomain, and remove a
device from user domain, 'relaxed' is fine enough since this is always safe
to hwdomain.

CC: Tim Deegan <tim@xen.org>
CC: Keir Fraser <keir@xen.org>
CC: Jan Beulich <jbeulich@suse.com>
CC: Andrew Cooper <andrew.cooper3@citrix.com>
CC: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
CC: Aravind Gopalakrishnan <Aravind.Gopalakrishnan@amd.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Stefano Stabellini <stefano.stabellini@citrix.com>
CC: Yang Zhang <yang.z.zhang@intel.com>
CC: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
---
v5:

* Just leave one bit XEN_DOMCTL_DEV_RDM_RELAXED as our flag, so
  "0" means "strict" and "1" means "relaxed".

* So make DT device ignore the flag field

* Improve the code comments

v4:

* Add code comments to describer why we fix to set a policy flag in some
  cases like adding a device to hwdomain, and removing a device from user domain.

* Avoid using fixed width types for the parameter of set_identity_p2m_entry()

* Fix one judging condition
  domctl->u.assign_device.flag == XEN_DOMCTL_DEV_NO_RDM
  -> domctl->u.assign_device.flag != XEN_DOMCTL_DEV_NO_RDM

* Add to range check the flag passed to make future extensions possible
  (and to avoid ambiguity on what out of range values would mean).

 xen/arch/x86/mm/p2m.c                       |  7 +++--
 xen/drivers/passthrough/amd/pci_amd_iommu.c |  3 ++-
 xen/drivers/passthrough/arm/smmu.c          |  2 +-
 xen/drivers/passthrough/device_tree.c       |  3 ++-
 xen/drivers/passthrough/pci.c               | 15 ++++++++---
 xen/drivers/passthrough/vtd/iommu.c         | 40 +++++++++++++++++++++++------
 xen/include/asm-x86/p2m.h                   |  2 +-
 xen/include/public/domctl.h                 |  3 +++
 xen/include/xen/iommu.h                     |  2 +-
 9 files changed, 58 insertions(+), 19 deletions(-)

diff --git a/xen/arch/x86/mm/p2m.c b/xen/arch/x86/mm/p2m.c
index 99a26ca..47785dc 100644
--- a/xen/arch/x86/mm/p2m.c
+++ b/xen/arch/x86/mm/p2m.c
@@ -901,7 +901,7 @@ int set_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn,
 }
 
 int set_identity_p2m_entry(struct domain *d, unsigned long gfn,
-                           p2m_access_t p2ma)
+                           p2m_access_t p2ma, unsigned int flag)
 {
     p2m_type_t p2mt;
     p2m_access_t a;
@@ -923,7 +923,10 @@ int set_identity_p2m_entry(struct domain *d, unsigned long gfn,
         ret = 0;
     else
     {
-        ret = -EBUSY;
+        if ( flag & XEN_DOMCTL_DEV_RDM_RELAXED )
+            ret = 0;
+        else
+            ret = -EBUSY;
         printk(XENLOG_G_WARNING
                "Cannot setup identity map d%d:%lx,"
                " gfn already mapped to %lx.\n",
diff --git a/xen/drivers/passthrough/amd/pci_amd_iommu.c b/xen/drivers/passthrough/amd/pci_amd_iommu.c
index e83bb35..920b35a 100644
--- a/xen/drivers/passthrough/amd/pci_amd_iommu.c
+++ b/xen/drivers/passthrough/amd/pci_amd_iommu.c
@@ -394,7 +394,8 @@ static int reassign_device(struct domain *source, struct domain *target,
 }
 
 static int amd_iommu_assign_device(struct domain *d, u8 devfn,
-                                   struct pci_dev *pdev)
+                                   struct pci_dev *pdev,
+                                   u32 flag)
 {
     struct ivrs_mappings *ivrs_mappings = get_ivrs_mappings(pdev->seg);
     int bdf = PCI_BDF2(pdev->bus, devfn);
diff --git a/xen/drivers/passthrough/arm/smmu.c b/xen/drivers/passthrough/arm/smmu.c
index 6cc4394..9a667e9 100644
--- a/xen/drivers/passthrough/arm/smmu.c
+++ b/xen/drivers/passthrough/arm/smmu.c
@@ -2605,7 +2605,7 @@ static void arm_smmu_destroy_iommu_domain(struct iommu_domain *domain)
 }
 
 static int arm_smmu_assign_dev(struct domain *d, u8 devfn,
-			       struct device *dev)
+			       struct device *dev, u32 flag)
 {
 	struct iommu_domain *domain;
 	struct arm_smmu_xen_domain *xen_domain;
diff --git a/xen/drivers/passthrough/device_tree.c b/xen/drivers/passthrough/device_tree.c
index 5d3842a..7ff79f8 100644
--- a/xen/drivers/passthrough/device_tree.c
+++ b/xen/drivers/passthrough/device_tree.c
@@ -52,7 +52,8 @@ int iommu_assign_dt_device(struct domain *d, struct dt_device_node *dev)
             goto fail;
     }
 
-    rc = hd->platform_ops->assign_device(d, 0, dt_to_dev(dev));
+    /* The flag field doesn't matter to DT device. */
+    rc = hd->platform_ops->assign_device(d, 0, dt_to_dev(dev), 0);
 
     if ( rc )
         goto fail;
diff --git a/xen/drivers/passthrough/pci.c b/xen/drivers/passthrough/pci.c
index e30be43..6e23fc6 100644
--- a/xen/drivers/passthrough/pci.c
+++ b/xen/drivers/passthrough/pci.c
@@ -1335,7 +1335,7 @@ static int device_assigned(u16 seg, u8 bus, u8 devfn)
     return pdev ? 0 : -EBUSY;
 }
 
-static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn)
+static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn, u32 flag)
 {
     struct hvm_iommu *hd = domain_hvm_iommu(d);
     struct pci_dev *pdev;
@@ -1371,7 +1371,7 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn)
 
     pdev->fault.count = 0;
 
-    if ( (rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev))) )
+    if ( (rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev), flag)) )
         goto done;
 
     for ( ; pdev->phantom_stride; rc = 0 )
@@ -1379,7 +1379,7 @@ static int assign_device(struct domain *d, u16 seg, u8 bus, u8 devfn)
         devfn += pdev->phantom_stride;
         if ( PCI_SLOT(devfn) != PCI_SLOT(pdev->devfn) )
             break;
-        rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev));
+        rc = hd->platform_ops->assign_device(d, devfn, pci_to_dev(pdev), flag);
         if ( rc )
             printk(XENLOG_G_WARNING "d%d: assign %04x:%02x:%02x.%u failed (%d)\n",
                    d->domain_id, seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
@@ -1496,6 +1496,7 @@ int iommu_do_pci_domctl(
 {
     u16 seg;
     u8 bus, devfn;
+    u32 flag;
     int ret = 0;
     uint32_t machine_sbdf;
 
@@ -1577,9 +1578,15 @@ int iommu_do_pci_domctl(
         seg = machine_sbdf >> 16;
         bus = PCI_BUS(machine_sbdf);
         devfn = PCI_DEVFN2(machine_sbdf);
+        flag = domctl->u.assign_device.flag;
+        if ( flag > XEN_DOMCTL_DEV_RDM_RELAXED )
+        {
+            ret = -EINVAL;
+            break;
+        }
 
         ret = device_assigned(seg, bus, devfn) ?:
-              assign_device(d, seg, bus, devfn);
+              assign_device(d, seg, bus, devfn, flag);
         if ( ret == -ERESTART )
             ret = hypercall_create_continuation(__HYPERVISOR_domctl,
                                                 "h", u_domctl);
diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c
index 8415958..56f5911 100644
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -1807,7 +1807,8 @@ static void iommu_set_pgd(struct domain *d)
 }
 
 static int rmrr_identity_mapping(struct domain *d, bool_t map,
-                                 const struct acpi_rmrr_unit *rmrr)
+                                 const struct acpi_rmrr_unit *rmrr,
+                                 u32 flag)
 {
     unsigned long base_pfn = rmrr->base_address >> PAGE_SHIFT_4K;
     unsigned long end_pfn = PAGE_ALIGN_4K(rmrr->end_address) >> PAGE_SHIFT_4K;
@@ -1855,7 +1856,7 @@ static int rmrr_identity_mapping(struct domain *d, bool_t map,
 
     while ( base_pfn < end_pfn )
     {
-        int err = set_identity_p2m_entry(d, base_pfn, p2m_access_rw);
+        int err = set_identity_p2m_entry(d, base_pfn, p2m_access_rw, flag);
 
         if ( err )
             return err;
@@ -1898,7 +1899,14 @@ static int intel_iommu_add_device(u8 devfn, struct pci_dev *pdev)
              PCI_BUS(bdf) == pdev->bus &&
              PCI_DEVFN2(bdf) == devfn )
         {
-            ret = rmrr_identity_mapping(pdev->domain, 1, rmrr);
+            /*
+             * Here means we're add a device to the hardware domain
+             * so actually RMRR is always reserved on e820 so either
+             * of flag is fine for hardware domain and here we'd like
+             * to pass XEN_DOMCTL_DEV_RDM_RELAXED.
+             */
+            ret = rmrr_identity_mapping(pdev->domain, 1, rmrr,
+                                        XEN_DOMCTL_DEV_RDM_RELAXED);
             if ( ret )
                 dprintk(XENLOG_ERR VTDPREFIX, "d%d: RMRR mapping failed\n",
                         pdev->domain->domain_id);
@@ -1939,7 +1947,12 @@ static int intel_iommu_remove_device(u8 devfn, struct pci_dev *pdev)
              PCI_DEVFN2(bdf) != devfn )
             continue;
 
-        rmrr_identity_mapping(pdev->domain, 0, rmrr);
+        /*
+         * Any flag is nothing to clear these mappings so here
+         * its always safe to set XEN_DOMCTL_DEV_RDM_RELAXED.
+         */
+        rmrr_identity_mapping(pdev->domain, 0, rmrr,
+                              XEN_DOMCTL_DEV_RDM_RELAXED);
     }
 
     return domain_context_unmap(pdev->domain, devfn, pdev);
@@ -2098,7 +2111,13 @@ static void __hwdom_init setup_hwdom_rmrr(struct domain *d)
     spin_lock(&pcidevs_lock);
     for_each_rmrr_device ( rmrr, bdf, i )
     {
-        ret = rmrr_identity_mapping(d, 1, rmrr);
+        /*
+         * Here means we're add a device to the hardware domain
+         * so actually RMRR is always reserved on e820 so either
+         * of flag is fine for hardware domain and here we'd like
+         * to pass XEN_DOMCTL_DEV_RDM_RELAXED.
+         */
+        ret = rmrr_identity_mapping(d, 1, rmrr, XEN_DOMCTL_DEV_RDM_RELAXED);
         if ( ret )
             dprintk(XENLOG_ERR VTDPREFIX,
                      "IOMMU: mapping reserved region failed\n");
@@ -2241,7 +2260,12 @@ static int reassign_device_ownership(
                  PCI_BUS(bdf) == pdev->bus &&
                  PCI_DEVFN2(bdf) == devfn )
             {
-                ret = rmrr_identity_mapping(source, 0, rmrr);
+                /*
+                 * Any RMRR flag is always ignored when remove a device,
+                 * so just pass XEN_DOMCTL_DEV_RDM_RELAXED.
+                 */
+                ret = rmrr_identity_mapping(source, 0, rmrr,
+                                            XEN_DOMCTL_DEV_RDM_RELAXED);
                 if ( ret != -ENOENT )
                     return ret;
             }
@@ -2265,7 +2289,7 @@ static int reassign_device_ownership(
 }
 
 static int intel_iommu_assign_device(
-    struct domain *d, u8 devfn, struct pci_dev *pdev)
+    struct domain *d, u8 devfn, struct pci_dev *pdev, u32 flag)
 {
     struct acpi_rmrr_unit *rmrr;
     int ret = 0, i;
@@ -2294,7 +2318,7 @@ static int intel_iommu_assign_device(
              PCI_BUS(bdf) == bus &&
              PCI_DEVFN2(bdf) == devfn )
         {
-            ret = rmrr_identity_mapping(d, 1, rmrr);
+            ret = rmrr_identity_mapping(d, 1, rmrr, flag);
             if ( ret )
             {
                 reassign_device_ownership(d, hardware_domain, devfn, pdev);
diff --git a/xen/include/asm-x86/p2m.h b/xen/include/asm-x86/p2m.h
index 190a286..68da0a9 100644
--- a/xen/include/asm-x86/p2m.h
+++ b/xen/include/asm-x86/p2m.h
@@ -545,7 +545,7 @@ int clear_mmio_p2m_entry(struct domain *d, unsigned long gfn, mfn_t mfn);
 
 /* Set identity addresses in the p2m table (for pass-through) */
 int set_identity_p2m_entry(struct domain *d, unsigned long gfn,
-                           p2m_access_t p2ma);
+                           p2m_access_t p2ma, unsigned int flag);
 
 #define clear_identity_p2m_entry(d, gfn, page_order) \
                         guest_physmap_remove_page(d, gfn, gfn, page_order)
diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
index bc45ea5..bca25c9 100644
--- a/xen/include/public/domctl.h
+++ b/xen/include/public/domctl.h
@@ -478,6 +478,9 @@ struct xen_domctl_assign_device {
             XEN_GUEST_HANDLE_64(char) path; /* path to the device tree node */
         } dt;
     } u;
+    /* IN */
+#define XEN_DOMCTL_DEV_RDM_RELAXED      1
+    uint32_t  flag;   /* flag of assigned device */
 };
 typedef struct xen_domctl_assign_device xen_domctl_assign_device_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_assign_device_t);
diff --git a/xen/include/xen/iommu.h b/xen/include/xen/iommu.h
index e2f584d..02b2b02 100644
--- a/xen/include/xen/iommu.h
+++ b/xen/include/xen/iommu.h
@@ -140,7 +140,7 @@ struct iommu_ops {
     int (*add_device)(u8 devfn, device_t *dev);
     int (*enable_device)(device_t *dev);
     int (*remove_device)(u8 devfn, device_t *dev);
-    int (*assign_device)(struct domain *, u8 devfn, device_t *dev);
+    int (*assign_device)(struct domain *, u8 devfn, device_t *dev, u32 flag);
     int (*reassign_device)(struct domain *s, struct domain *t,
                            u8 devfn, device_t *dev);
 #ifdef HAS_PCI
-- 
1.9.1

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

* [v5][PATCH 04/16] xen: enable XENMEM_memory_map in hvm
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
                   ` (2 preceding siblings ...)
  2015-07-07  6:17 ` [v5][PATCH 03/16] xen/passthrough: extend hypercall to support rdm reservation policy Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 05/16] hvmloader: get guest memory map into memory_map[] Tiejun Chen
                   ` (11 subsequent siblings)
  15 siblings, 0 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel; +Cc: Andrew Cooper, Keir Fraser, Jan Beulich

This patch enables XENMEM_memory_map in hvm. So hvmloader can
use it to setup the e820 mappings.

CC: Keir Fraser <keir@xen.org>
CC: Jan Beulich <jbeulich@suse.com>
CC: Andrew Cooper <andrew.cooper3@citrix.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
Reviewed-by: Tim Deegan <tim@xen.org>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Acked-by: Jan Beulich <jbeulich@suse.com>
Acked-by: George Dunlap <george.dunlap@eu.citrix.com>
---
v5:

* Nothing is changed.

v4:

* Just refine the patch head description as Jan commented.

 xen/arch/x86/hvm/hvm.c | 2 --
 xen/arch/x86/mm.c      | 6 ------
 2 files changed, 8 deletions(-)

diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c
index 535d622..638daee 100644
--- a/xen/arch/x86/hvm/hvm.c
+++ b/xen/arch/x86/hvm/hvm.c
@@ -4741,7 +4741,6 @@ static long hvm_memory_op(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
 
     switch ( cmd & MEMOP_CMD_MASK )
     {
-    case XENMEM_memory_map:
     case XENMEM_machine_memory_map:
     case XENMEM_machphys_mapping:
         return -ENOSYS;
@@ -4817,7 +4816,6 @@ static long hvm_memory_op_compat32(int cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
 
     switch ( cmd & MEMOP_CMD_MASK )
     {
-    case XENMEM_memory_map:
     case XENMEM_machine_memory_map:
     case XENMEM_machphys_mapping:
         return -ENOSYS;
diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index fd151c6..92eccd0 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -4717,12 +4717,6 @@ long arch_memory_op(unsigned long cmd, XEN_GUEST_HANDLE_PARAM(void) arg)
             return rc;
         }
 
-        if ( is_hvm_domain(d) )
-        {
-            rcu_unlock_domain(d);
-            return -EPERM;
-        }
-
         e820 = xmalloc_array(e820entry_t, fmap.map.nr_entries);
         if ( e820 == NULL )
         {
-- 
1.9.1

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

* [v5][PATCH 05/16] hvmloader: get guest memory map into memory_map[]
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
                   ` (3 preceding siblings ...)
  2015-07-07  6:17 ` [v5][PATCH 04/16] xen: enable XENMEM_memory_map in hvm Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 06/16] hvmloader/pci: skip reserved ranges Tiejun Chen
                   ` (10 subsequent siblings)
  15 siblings, 0 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel
  Cc: Keir Fraser, Ian Campbell, Stefano Stabellini, Andrew Cooper,
	Ian Jackson, Jan Beulich, Wei Liu

Now we get this map layout by call XENMEM_memory_map then
save them into one global variable memory_map[]. It should
include lowmem range, rdm range and highmem range. Note
rdm range and highmem range may not exist in some cases.

And here we need to check if any reserved memory conflicts with
[RESERVED_MEMORY_DYNAMIC_START - 1, RESERVED_MEMORY_DYNAMIC_END].
This range is used to allocate memory in hvmloder level, and
we would lead hvmloader failed in case of conflict since its
another rare possibility in real world.

CC: Keir Fraser <keir@xen.org>
CC: Jan Beulich <jbeulich@suse.com>
CC: Andrew Cooper <andrew.cooper3@citrix.com>
CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
---
v5:

* Nothing is changed.

v4:

* Move some codes related to e820 to that specific file, e820.c.

* Consolidate "printf()+BUG()" and "BUG_ON()"

* Avoid another fixed width type for the parameter of get_mem_mapping_layout()

 tools/firmware/hvmloader/e820.c      | 35 +++++++++++++++++++++++++++++++++++
 tools/firmware/hvmloader/e820.h      |  7 +++++++
 tools/firmware/hvmloader/hvmloader.c |  2 ++
 tools/firmware/hvmloader/util.c      | 26 ++++++++++++++++++++++++++
 tools/firmware/hvmloader/util.h      | 12 ++++++++++++
 5 files changed, 82 insertions(+)

diff --git a/tools/firmware/hvmloader/e820.c b/tools/firmware/hvmloader/e820.c
index 2e05e93..3e53c47 100644
--- a/tools/firmware/hvmloader/e820.c
+++ b/tools/firmware/hvmloader/e820.c
@@ -23,6 +23,41 @@
 #include "config.h"
 #include "util.h"
 
+struct e820map memory_map;
+
+void memory_map_setup(void)
+{
+    unsigned int nr_entries = E820MAX, i;
+    int rc;
+    uint64_t alloc_addr = RESERVED_MEMORY_DYNAMIC_START - 1;
+    uint64_t alloc_size = RESERVED_MEMORY_DYNAMIC_END - alloc_addr;
+
+    rc = get_mem_mapping_layout(memory_map.map, &nr_entries);
+
+    if ( rc || !nr_entries )
+    {
+        printf("Get guest memory maps[%d] failed. (%d)\n", nr_entries, rc);
+        BUG();
+    }
+
+    memory_map.nr_map = nr_entries;
+
+    for ( i = 0; i < nr_entries; i++ )
+    {
+        if ( memory_map.map[i].type == E820_RESERVED )
+        {
+            if ( check_overlap(alloc_addr, alloc_size,
+                               memory_map.map[i].addr,
+                               memory_map.map[i].size) )
+            {
+                printf("Fail to setup memory map due to conflict");
+                printf(" on dynamic reserved memory range.\n");
+                BUG();
+            }
+        }
+    }
+}
+
 void dump_e820_table(struct e820entry *e820, unsigned int nr)
 {
     uint64_t last_end = 0, start, end;
diff --git a/tools/firmware/hvmloader/e820.h b/tools/firmware/hvmloader/e820.h
index b2ead7f..8b5a9e0 100644
--- a/tools/firmware/hvmloader/e820.h
+++ b/tools/firmware/hvmloader/e820.h
@@ -15,6 +15,13 @@ struct e820entry {
     uint32_t type;
 } __attribute__((packed));
 
+#define E820MAX	128
+
+struct e820map {
+    unsigned int nr_map;
+    struct e820entry map[E820MAX];
+};
+
 #endif /* __HVMLOADER_E820_H__ */
 
 /*
diff --git a/tools/firmware/hvmloader/hvmloader.c b/tools/firmware/hvmloader/hvmloader.c
index 25b7f08..84c588c 100644
--- a/tools/firmware/hvmloader/hvmloader.c
+++ b/tools/firmware/hvmloader/hvmloader.c
@@ -262,6 +262,8 @@ int main(void)
 
     init_hypercalls();
 
+    memory_map_setup();
+
     xenbus_setup();
 
     bios = detect_bios();
diff --git a/tools/firmware/hvmloader/util.c b/tools/firmware/hvmloader/util.c
index 80d822f..122e3fa 100644
--- a/tools/firmware/hvmloader/util.c
+++ b/tools/firmware/hvmloader/util.c
@@ -27,6 +27,17 @@
 #include <xen/memory.h>
 #include <xen/sched.h>
 
+/*
+ * Check whether there exists overlap in the specified memory range.
+ * Returns true if exists, else returns false.
+ */
+bool check_overlap(uint64_t start, uint64_t size,
+                   uint64_t reserved_start, uint64_t reserved_size)
+{
+    return (start + size > reserved_start) &&
+            (start < reserved_start + reserved_size);
+}
+
 void wrmsr(uint32_t idx, uint64_t v)
 {
     asm volatile (
@@ -368,6 +379,21 @@ uuid_to_string(char *dest, uint8_t *uuid)
     *p = '\0';
 }
 
+int get_mem_mapping_layout(struct e820entry entries[], uint32_t *max_entries)
+{
+    int rc;
+    struct xen_memory_map memmap = {
+        .nr_entries = *max_entries
+    };
+
+    set_xen_guest_handle(memmap.buffer, entries);
+
+    rc = hypercall_memory_op(XENMEM_memory_map, &memmap);
+    *max_entries = memmap.nr_entries;
+
+    return rc;
+}
+
 void mem_hole_populate_ram(xen_pfn_t mfn, uint32_t nr_mfns)
 {
     static int over_allocated;
diff --git a/tools/firmware/hvmloader/util.h b/tools/firmware/hvmloader/util.h
index f99c0f19..1100a3b 100644
--- a/tools/firmware/hvmloader/util.h
+++ b/tools/firmware/hvmloader/util.h
@@ -4,8 +4,10 @@
 #include <stdarg.h>
 #include <stdint.h>
 #include <stddef.h>
+#include <stdbool.h>
 #include <xen/xen.h>
 #include <xen/hvm/hvm_info_table.h>
+#include "e820.h"
 
 #define __STR(...) #__VA_ARGS__
 #define STR(...) __STR(__VA_ARGS__)
@@ -222,6 +224,9 @@ int hvm_param_set(uint32_t index, uint64_t value);
 /* Setup PCI bus */
 void pci_setup(void);
 
+/* Setup memory map  */
+void memory_map_setup(void);
+
 /* Prepare the 32bit BIOS */
 uint32_t rombios_highbios_setup(void);
 
@@ -249,6 +254,13 @@ void perform_tests(void);
 
 extern char _start[], _end[];
 
+int get_mem_mapping_layout(struct e820entry entries[],
+                           unsigned int *max_entries);
+
+extern struct e820map memory_map;
+bool check_overlap(uint64_t start, uint64_t size,
+                   uint64_t reserved_start, uint64_t reserved_size);
+
 #endif /* __HVMLOADER_UTIL_H__ */
 
 /*
-- 
1.9.1

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

* [v5][PATCH 06/16] hvmloader/pci: skip reserved ranges
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
                   ` (4 preceding siblings ...)
  2015-07-07  6:17 ` [v5][PATCH 05/16] hvmloader: get guest memory map into memory_map[] Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 07/16] hvmloader/e820: construct guest e820 table Tiejun Chen
                   ` (9 subsequent siblings)
  15 siblings, 0 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel
  Cc: Keir Fraser, Ian Campbell, Stefano Stabellini, Andrew Cooper,
	Ian Jackson, Jan Beulich, Wei Liu

When allocating mmio address for PCI bars, we need to make
sure they don't overlap with reserved regions.

CC: Keir Fraser <keir@xen.org>
CC: Jan Beulich <jbeulich@suse.com>
CC: Andrew Cooper <andrew.cooper3@citrix.com>
CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
---
v5:

* Rename that field, is_64bar, inside struct bars with flag, and
  then extend to also indicate if this bar is already allocated.

v4:

* We have to re-design this as follows:

  #1. Goal

  MMIO region should exclude all reserved device memory

  #2. Requirements

  #2.1 Still need to make sure MMIO region is fit all pci devices as before

  #2.2 Accommodate the not aligned reserved memory regions

  If I'm missing something let me know.

  #3. How to

  #3.1 Address #2.1

  We need to either of populating more RAM, or of expanding more highmem. But
  we should know just 64bit-bar can work with highmem, and as you mentioned we
  also should avoid expanding highmem as possible. So my implementation is to 
  allocate 32bit-bar and 64bit-bar orderly.

  1>. The first allocation round just to 32bit-bar

  If we can finish allocating all 32bit-bar, we just go to allocate 64bit-bar
  with all remaining resources including low pci memory.

  If not, we need to calculate how much RAM should be populated to allocate the 
  remaining 32bit-bars, then populate sufficient RAM as exp_mem_resource to go
  to the second allocation round 2>.

  2>. The second allocation round to the remaining 32bit-bar

  We should can finish allocating all 32bit-bar in theory, then go to the third
  allocation round 3>.

  3>. The third allocation round to 64bit-bar

  We'll try to first allocate from the remaining low memory resource. If that
  isn't enough, we try to expand highmem to allocate for 64bit-bar. This process
  should be same as the original.

  #3.2 Address #2.2

  I'm trying to accommodate the not aligned reserved memory regions:

  We should skip all reserved device memory, but we also need to check if other
  smaller bars can be allocated if a mmio hole exists between resource->base and
  reserved device memory. If a hole exists between base and reserved device
  memory, lets go out simply to try allocate for next bar since all bars are in
  descending order of size. If not, we need to move resource->base to reserved_end
  just to reallocate this bar.

 tools/firmware/hvmloader/pci.c | 194 ++++++++++++++++++++++++++++++++++-------
 1 file changed, 164 insertions(+), 30 deletions(-)

diff --git a/tools/firmware/hvmloader/pci.c b/tools/firmware/hvmloader/pci.c
index 5ff87a7..397f3b7 100644
--- a/tools/firmware/hvmloader/pci.c
+++ b/tools/firmware/hvmloader/pci.c
@@ -38,6 +38,31 @@ uint64_t pci_hi_mem_start = 0, pci_hi_mem_end = 0;
 enum virtual_vga virtual_vga = VGA_none;
 unsigned long igd_opregion_pgbase = 0;
 
+static void relocate_ram_for_pci_memory(unsigned long cur_pci_mem_start)
+{
+    struct xen_add_to_physmap xatp;
+    unsigned int nr_pages = min_t(
+        unsigned int,
+        hvm_info->low_mem_pgend - (cur_pci_mem_start >> PAGE_SHIFT),
+        (1u << 16) - 1);
+    if ( hvm_info->high_mem_pgend == 0 )
+        hvm_info->high_mem_pgend = 1ull << (32 - PAGE_SHIFT);
+    hvm_info->low_mem_pgend -= nr_pages;
+    printf("Relocating 0x%x pages from "PRIllx" to "PRIllx\
+           " for lowmem MMIO hole\n",
+           nr_pages,
+           PRIllx_arg(((uint64_t)hvm_info->low_mem_pgend)<<PAGE_SHIFT),
+           PRIllx_arg(((uint64_t)hvm_info->high_mem_pgend)<<PAGE_SHIFT));
+    xatp.domid = DOMID_SELF;
+    xatp.space = XENMAPSPACE_gmfn_range;
+    xatp.idx   = hvm_info->low_mem_pgend;
+    xatp.gpfn  = hvm_info->high_mem_pgend;
+    xatp.size  = nr_pages;
+    if ( hypercall_memory_op(XENMEM_add_to_physmap, &xatp) != 0 )
+        BUG();
+    hvm_info->high_mem_pgend += nr_pages;
+}
+
 void pci_setup(void)
 {
     uint8_t is_64bar, using_64bar, bar64_relocate = 0;
@@ -50,17 +75,22 @@ void pci_setup(void)
     /* Resources assignable to PCI devices via BARs. */
     struct resource {
         uint64_t base, max;
-    } *resource, mem_resource, high_mem_resource, io_resource;
+    } *resource, mem_resource, high_mem_resource, io_resource, exp_mem_resource;
 
     /* Create a list of device BARs in descending order of size. */
     struct bars {
-        uint32_t is_64bar;
+#define PCI_BAR_IS_64BIT        0x1
+#define PCI_BAR_IS_ALLOCATED    0x2
+        uint32_t flag;
         uint32_t devfn;
         uint32_t bar_reg;
         uint64_t bar_sz;
     } *bars = (struct bars *)scratch_start;
-    unsigned int i, nr_bars = 0;
-    uint64_t mmio_hole_size = 0;
+    unsigned int i, j, n, nr_bars = 0;
+    uint64_t mmio_hole_size = 0, reserved_start, reserved_end, reserved_size;
+    bool bar32_allocating = 0;
+    uint64_t mmio32_unallocated_total = 0;
+    unsigned long cur_pci_mem_start = 0;
 
     const char *s;
     /*
@@ -222,7 +252,7 @@ void pci_setup(void)
             if ( i != nr_bars )
                 memmove(&bars[i+1], &bars[i], (nr_bars-i) * sizeof(*bars));
 
-            bars[i].is_64bar = is_64bar;
+            bars[i].flag = is_64bar ? PCI_BAR_IS_64BIT : 0;
             bars[i].devfn   = devfn;
             bars[i].bar_reg = bar_reg;
             bars[i].bar_sz  = bar_sz;
@@ -309,29 +339,31 @@ void pci_setup(void)
     }
 
     /* Relocate RAM that overlaps PCI space (in 64k-page chunks). */
+    cur_pci_mem_start = pci_mem_start;
     while ( (pci_mem_start >> PAGE_SHIFT) < hvm_info->low_mem_pgend )
+        relocate_ram_for_pci_memory(cur_pci_mem_start);
+
+    /*
+     * Check if reserved device memory conflicts current pci memory.
+     * If yes, we need to first allocate bar32 since reserved devices
+     * always occupy low memory, and also enable relocating some BARs
+     * to 64bit as possible.
+     */
+    for ( i = 0; i < memory_map.nr_map ; i++ )
     {
-        struct xen_add_to_physmap xatp;
-        unsigned int nr_pages = min_t(
-            unsigned int,
-            hvm_info->low_mem_pgend - (pci_mem_start >> PAGE_SHIFT),
-            (1u << 16) - 1);
-        if ( hvm_info->high_mem_pgend == 0 )
-            hvm_info->high_mem_pgend = 1ull << (32 - PAGE_SHIFT);
-        hvm_info->low_mem_pgend -= nr_pages;
-        printf("Relocating 0x%x pages from "PRIllx" to "PRIllx\
-               " for lowmem MMIO hole\n",
-               nr_pages,
-               PRIllx_arg(((uint64_t)hvm_info->low_mem_pgend)<<PAGE_SHIFT),
-               PRIllx_arg(((uint64_t)hvm_info->high_mem_pgend)<<PAGE_SHIFT));
-        xatp.domid = DOMID_SELF;
-        xatp.space = XENMAPSPACE_gmfn_range;
-        xatp.idx   = hvm_info->low_mem_pgend;
-        xatp.gpfn  = hvm_info->high_mem_pgend;
-        xatp.size  = nr_pages;
-        if ( hypercall_memory_op(XENMEM_add_to_physmap, &xatp) != 0 )
-            BUG();
-        hvm_info->high_mem_pgend += nr_pages;
+        reserved_start = memory_map.map[i].addr;
+        reserved_size = memory_map.map[i].size;
+        reserved_end = reserved_start + reserved_size;
+        if ( check_overlap(pci_mem_start, pci_mem_end - pci_mem_start,
+                           reserved_start, reserved_size) )
+        {
+            printf("Reserved device memory conflicts current PCI memory,"
+                   " so first to allocate 32-bit BAR and trying to"
+                   " relocating some BARs to 64-bit\n");
+            bar32_allocating = 1;
+            if ( !bar64_relocate )
+                bar64_relocate = 1;
+        }
     }
 
     high_mem_resource.base = ((uint64_t)hvm_info->high_mem_pgend) << PAGE_SHIFT;
@@ -352,6 +384,7 @@ void pci_setup(void)
     io_resource.base = 0xc000;
     io_resource.max = 0x10000;
 
+ further_allocate:
     /* Assign iomem and ioport resources in descending order of size. */
     for ( i = 0; i < nr_bars; i++ )
     {
@@ -359,6 +392,17 @@ void pci_setup(void)
         bar_reg = bars[i].bar_reg;
         bar_sz  = bars[i].bar_sz;
 
+        /* Check if this bar is allocated. */
+        if ( bars[i].flag & PCI_BAR_IS_ALLOCATED )
+            continue;
+
+        /*
+         * This means we'd like to first allocate 32bit bar to make sure
+         * all 32bit bars can be allocated as possible.
+         */
+        if ( (bars[i].flag & PCI_BAR_IS_64BIT) && bar32_allocating )
+            continue;
+
         /*
          * Relocate to high memory if the total amount of MMIO needed
          * is more than the low MMIO available.  Because devices are
@@ -377,7 +421,7 @@ void pci_setup(void)
          *   the code here assumes it to be.)
          * Should either of those two conditions change, this code will break.
          */
-        using_64bar = bars[i].is_64bar && bar64_relocate
+        using_64bar = (bars[i].flag & PCI_BAR_IS_64BIT) && bar64_relocate
             && (mmio_total > (mem_resource.max - mem_resource.base));
         bar_data = pci_readl(devfn, bar_reg);
 
@@ -395,7 +439,14 @@ void pci_setup(void)
                 bar_data &= ~PCI_BASE_ADDRESS_MEM_MASK;
             } 
             else {
-                resource = &mem_resource;
+                /*
+                 * This menas we're trying to use that expanded
+                 * memory to reallocate 32bars.
+                 */
+                if ( mmio32_unallocated_total )
+                    resource = &exp_mem_resource;
+                else
+                    resource = &mem_resource;
                 bar_data &= ~PCI_BASE_ADDRESS_MEM_MASK;
             }
             mmio_total -= bar_sz;
@@ -406,9 +457,44 @@ void pci_setup(void)
             bar_data &= ~PCI_BASE_ADDRESS_IO_MASK;
         }
 
-        base = (resource->base  + bar_sz - 1) & ~(uint64_t)(bar_sz - 1);
+ reallocate_bar:
+        base = (resource->base + bar_sz - 1) & ~(uint64_t)(bar_sz - 1);
         bar_data |= (uint32_t)base;
         bar_data_upper = (uint32_t)(base >> 32);
+        /*
+         * We should skip all reserved device memory, but we also need
+         * to check if other smaller bars can be allocated if a mmio hole
+         * exists between resource->base and reserved device memory.
+         */
+        for ( j = 0; j < memory_map.nr_map ; j++ )
+        {
+            if ( memory_map.map[j].type != E820_RAM )
+            {
+                reserved_start = memory_map.map[i].addr;
+                reserved_size = memory_map.map[i].size;
+                reserved_end = reserved_start + reserved_size;
+                if ( check_overlap(base, bar_sz,
+                                   reserved_start, reserved_size) )
+                {
+                    /*
+                     * If a hole exists between base and reserved device
+                     * memory, lets go out simply to try allocate for next
+                     * bar since all bars are in descending order of size.
+                     */
+                    if ( resource->base < reserved_start )
+                        continue;
+                    /*
+                     * If not, we need to move resource->base to
+                     * reserved_end just to reallocate this bar.
+                     */
+                    else
+                    {
+                        resource->base = reserved_end;
+                        goto reallocate_bar;
+                    }
+                }
+            }
+        }
         base += bar_sz;
 
         if ( (base < resource->base) || (base > resource->max) )
@@ -428,7 +514,7 @@ void pci_setup(void)
                devfn>>3, devfn&7, bar_reg,
                PRIllx_arg(bar_sz),
                bar_data_upper, bar_data);
-			
+        bars[i].flag |= PCI_BAR_IS_ALLOCATED;
 
         /* Now enable the memory or I/O mapping. */
         cmd = pci_readw(devfn, PCI_COMMAND);
@@ -439,6 +525,54 @@ void pci_setup(void)
         else
             cmd |= PCI_COMMAND_IO;
         pci_writew(devfn, PCI_COMMAND, cmd);
+
+        /* If we finish allocating bar32 at the first time. */
+        if ( i == nr_bars && bar32_allocating )
+        {
+            /*
+             * We won't repeat to populate more RAM to finalize
+             * allocate all 32bars, so just go to allocate 64bit-bars.
+             */
+            if ( mmio32_unallocated_total )
+            {
+                bar32_allocating = 0;
+                mmio32_unallocated_total = 0;
+                high_mem_resource.base =
+                        ((uint64_t)hvm_info->high_mem_pgend) << PAGE_SHIFT;
+                goto further_allocate;
+            }
+
+            /* Calculate the remaining 32bars. */
+            for ( n = 0; n < nr_bars ; n++ )
+            {
+                if ( !(bars[n].flag & PCI_BAR_IS_64BIT) )
+                {
+                    uint32_t devfn32, bar_reg32, bar_data32;
+                    uint64_t bar_sz32;
+                    devfn32   = bars[n].devfn;
+                    bar_reg32 = bars[n].bar_reg;
+                    bar_sz32  = bars[n].bar_sz;
+                    bar_data32 = pci_readl(devfn32, bar_reg32);
+                    if ( !bar_data32 )
+                        mmio32_unallocated_total  += bar_sz32;
+                }
+            }
+
+            /*
+             * We have to populate more RAM to further allocate
+             * the remaining 32bars.
+             */
+            if ( mmio32_unallocated_total )
+            {
+                cur_pci_mem_start = pci_mem_start - mmio32_unallocated_total;
+                relocate_ram_for_pci_memory(cur_pci_mem_start);
+                exp_mem_resource.base = cur_pci_mem_start;
+                exp_mem_resource.max = pci_mem_start;
+            }
+            else
+                bar32_allocating = 0;
+            goto further_allocate;
+        }
     }
 
     if ( pci_hi_mem_start )
-- 
1.9.1

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

* [v5][PATCH 07/16] hvmloader/e820: construct guest e820 table
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
                   ` (5 preceding siblings ...)
  2015-07-07  6:17 ` [v5][PATCH 06/16] hvmloader/pci: skip reserved ranges Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 08/16] tools/libxc: Expose new hypercall xc_reserved_device_memory_map Tiejun Chen
                   ` (8 subsequent siblings)
  15 siblings, 0 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel
  Cc: Keir Fraser, Ian Campbell, Stefano Stabellini, Andrew Cooper,
	Ian Jackson, Jan Beulich, Wei Liu

Now we can use that memory map to build our final
e820 table but it may need to reorder all e820
entries.

CC: Keir Fraser <keir@xen.org>
CC: Jan Beulich <jbeulich@suse.com>
CC: Andrew Cooper <andrew.cooper3@citrix.com>
CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
---
v5:

* Nothing is changed.

v4:

* Rename local variable, low_mem_pgend, to low_mem_end.

* Improve some code comments

* Adjust highmem after lowmem is changed.

 tools/firmware/hvmloader/e820.c | 80 +++++++++++++++++++++++++++++++++--------
 1 file changed, 66 insertions(+), 14 deletions(-)

diff --git a/tools/firmware/hvmloader/e820.c b/tools/firmware/hvmloader/e820.c
index 3e53c47..aa2569f 100644
--- a/tools/firmware/hvmloader/e820.c
+++ b/tools/firmware/hvmloader/e820.c
@@ -108,7 +108,9 @@ int build_e820_table(struct e820entry *e820,
                      unsigned int lowmem_reserved_base,
                      unsigned int bios_image_base)
 {
-    unsigned int nr = 0;
+    unsigned int nr = 0, i, j;
+    uint64_t add_high_mem = 0;
+    uint64_t low_mem_end = hvm_info->low_mem_pgend << PAGE_SHIFT;
 
     if ( !lowmem_reserved_base )
             lowmem_reserved_base = 0xA0000;
@@ -152,13 +154,6 @@ int build_e820_table(struct e820entry *e820,
     e820[nr].type = E820_RESERVED;
     nr++;
 
-    /* Low RAM goes here. Reserve space for special pages. */
-    BUG_ON((hvm_info->low_mem_pgend << PAGE_SHIFT) < (2u << 20));
-    e820[nr].addr = 0x100000;
-    e820[nr].size = (hvm_info->low_mem_pgend << PAGE_SHIFT) - e820[nr].addr;
-    e820[nr].type = E820_RAM;
-    nr++;
-
     /*
      * Explicitly reserve space for special pages.
      * This space starts at RESERVED_MEMBASE an extends to cover various
@@ -194,16 +189,73 @@ int build_e820_table(struct e820entry *e820,
         nr++;
     }
 
-
-    if ( hvm_info->high_mem_pgend )
+    /*
+     * Construct E820 table according to recorded memory map.
+     *
+     * The memory map created by toolstack may include,
+     *
+     * #1. Low memory region
+     *
+     * Low RAM starts at least from 1M to make sure all standard regions
+     * of the PC memory map, like BIOS, VGA memory-mapped I/O and vgabios,
+     * have enough space.
+     *
+     * #2. Reserved regions if they exist
+     *
+     * #3. High memory region if it exists
+     */
+    for ( i = 0; i < memory_map.nr_map; i++ )
     {
-        e820[nr].addr = ((uint64_t)1 << 32);
-        e820[nr].size =
-            ((uint64_t)hvm_info->high_mem_pgend << PAGE_SHIFT) - e820[nr].addr;
-        e820[nr].type = E820_RAM;
+        e820[nr] = memory_map.map[i];
         nr++;
     }
 
+    /* Low RAM goes here. Reserve space for special pages. */
+    BUG_ON(low_mem_end < (2u << 20));
+
+    /*
+     * We may need to adjust real lowmem end since we may
+     * populate RAM to get enough MMIO previously.
+     */
+    for ( i = 0; i < memory_map.nr_map; i++ )
+    {
+        uint64_t end = e820[i].addr + e820[i].size;
+        if ( e820[i].type == E820_RAM &&
+             low_mem_end > e820[i].addr && low_mem_end < end )
+        {
+            add_high_mem = end - low_mem_end;
+            e820[i].size = low_mem_end - e820[i].addr;
+        }
+    }
+
+    /*
+     * And then we also need to adjust highmem.
+     */
+    if ( add_high_mem )
+    {
+        for ( i = 0; i < memory_map.nr_map; i++ )
+        {
+            if ( e820[i].type == E820_RAM &&
+                 e820[i].addr > (1ull << 32))
+                e820[i].size += add_high_mem;
+        }
+    }
+
+    /* Finally we need to reorder all e820 entries. */
+    for ( j = 0; j < nr-1; j++ )
+    {
+        for ( i = j+1; i < nr; i++ )
+        {
+            if ( e820[j].addr > e820[i].addr )
+            {
+                struct e820entry tmp;
+                tmp = e820[j];
+                e820[j] = e820[i];
+                e820[i] = tmp;
+            }
+        }
+    }
+
     return nr;
 }
 
-- 
1.9.1

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

* [v5][PATCH 08/16] tools/libxc: Expose new hypercall xc_reserved_device_memory_map
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
                   ` (6 preceding siblings ...)
  2015-07-07  6:17 ` [v5][PATCH 07/16] hvmloader/e820: construct guest e820 table Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 09/16] tools: extend xc_assign_device() to support rdm reservation policy Tiejun Chen
                   ` (7 subsequent siblings)
  15 siblings, 0 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Ian Jackson, Ian Campbell, Stefano Stabellini

We will introduce the hypercall xc_reserved_device_memory_map
approach to libxc. This helps us get rdm entry info according to
different parameters. If flag == PCI_DEV_RDM_ALL, all entries
should be exposed. Or we just expose that rdm entry specific to
a SBDF.

CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Wei Liu <wei.liu2@citrix.com>
Reviewed-by: Kevin Tian <kevin.tian@intel.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
---
v5:

* Nothing is changed.

v4:

* Nothing is changed.

 tools/libxc/include/xenctrl.h |  8 ++++++++
 tools/libxc/xc_domain.c       | 36 ++++++++++++++++++++++++++++++++++++
 2 files changed, 44 insertions(+)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index d1d2ab3..9160623 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -1326,6 +1326,14 @@ int xc_domain_set_memory_map(xc_interface *xch,
 int xc_get_machine_memory_map(xc_interface *xch,
                               struct e820entry entries[],
                               uint32_t max_entries);
+
+int xc_reserved_device_memory_map(xc_interface *xch,
+                                  uint32_t flag,
+                                  uint16_t seg,
+                                  uint8_t bus,
+                                  uint8_t devfn,
+                                  struct xen_reserved_device_memory entries[],
+                                  uint32_t *max_entries);
 #endif
 int xc_domain_set_time_offset(xc_interface *xch,
                               uint32_t domid,
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index ce51e69..0951291 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -684,6 +684,42 @@ int xc_domain_set_memory_map(xc_interface *xch,
 
     return rc;
 }
+
+int xc_reserved_device_memory_map(xc_interface *xch,
+                                  uint32_t flag,
+                                  uint16_t seg,
+                                  uint8_t bus,
+                                  uint8_t devfn,
+                                  struct xen_reserved_device_memory entries[],
+                                  uint32_t *max_entries)
+{
+    int rc;
+    struct xen_reserved_device_memory_map xrdmmap = {
+        .flag = flag,
+        .seg = seg,
+        .bus = bus,
+        .devfn = devfn,
+        .nr_entries = *max_entries
+    };
+    DECLARE_HYPERCALL_BOUNCE(entries,
+                             sizeof(struct xen_reserved_device_memory) *
+                             *max_entries, XC_HYPERCALL_BUFFER_BOUNCE_OUT);
+
+    if ( xc_hypercall_bounce_pre(xch, entries) )
+        return -1;
+
+    set_xen_guest_handle(xrdmmap.buffer, entries);
+
+    rc = do_memory_op(xch, XENMEM_reserved_device_memory_map,
+                      &xrdmmap, sizeof(xrdmmap));
+
+    xc_hypercall_bounce_post(xch, entries);
+
+    *max_entries = xrdmmap.nr_entries;
+
+    return rc;
+}
+
 int xc_get_machine_memory_map(xc_interface *xch,
                               struct e820entry entries[],
                               uint32_t max_entries)
-- 
1.9.1

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

* [v5][PATCH 09/16] tools: extend xc_assign_device() to support rdm reservation policy
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
                   ` (7 preceding siblings ...)
  2015-07-07  6:17 ` [v5][PATCH 08/16] tools/libxc: Expose new hypercall xc_reserved_device_memory_map Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy Tiejun Chen
                   ` (6 subsequent siblings)
  15 siblings, 0 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel
  Cc: Wei Liu, David Scott, Ian Jackson, Ian Campbell,
	Stefano Stabellini

This patch passes rdm reservation policy to xc_assign_device() so the policy
is checked when assigning devices to a VM.

Note this also bring some fallout to python usage of xc_assign_device().

CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Wei Liu <wei.liu2@citrix.com>
CC: David Scott <dave.scott@eu.citrix.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
---
v5:

* Fix the flag field as "0" to DT device

v4:

* In the patch head description, I add to explain why we need to sync
  the xc.c file

 tools/libxc/include/xenctrl.h       |  3 ++-
 tools/libxc/xc_domain.c             |  9 ++++++++-
 tools/libxl/libxl_pci.c             |  3 ++-
 tools/ocaml/libs/xc/xenctrl_stubs.c | 16 ++++++++++++----
 tools/python/xen/lowlevel/xc/xc.c   | 30 ++++++++++++++++++++----------
 5 files changed, 44 insertions(+), 17 deletions(-)

diff --git a/tools/libxc/include/xenctrl.h b/tools/libxc/include/xenctrl.h
index 9160623..89cbc5a 100644
--- a/tools/libxc/include/xenctrl.h
+++ b/tools/libxc/include/xenctrl.h
@@ -2079,7 +2079,8 @@ int xc_hvm_destroy_ioreq_server(xc_interface *xch,
 /* HVM guest pass-through */
 int xc_assign_device(xc_interface *xch,
                      uint32_t domid,
-                     uint32_t machine_sbdf);
+                     uint32_t machine_sbdf,
+                     uint32_t flag);
 
 int xc_get_device_group(xc_interface *xch,
                      uint32_t domid,
diff --git a/tools/libxc/xc_domain.c b/tools/libxc/xc_domain.c
index 0951291..ef41228 100644
--- a/tools/libxc/xc_domain.c
+++ b/tools/libxc/xc_domain.c
@@ -1697,7 +1697,8 @@ int xc_domain_setdebugging(xc_interface *xch,
 int xc_assign_device(
     xc_interface *xch,
     uint32_t domid,
-    uint32_t machine_sbdf)
+    uint32_t machine_sbdf,
+    uint32_t flag)
 {
     DECLARE_DOMCTL;
 
@@ -1705,6 +1706,7 @@ int xc_assign_device(
     domctl.domain = domid;
     domctl.u.assign_device.dev = XEN_DOMCTL_DEV_PCI;
     domctl.u.assign_device.u.pci.machine_sbdf = machine_sbdf;
+    domctl.u.assign_device.flag = flag;
 
     return do_domctl(xch, &domctl);
 }
@@ -1792,6 +1794,11 @@ int xc_assign_dt_device(
 
     domctl.u.assign_device.dev = XEN_DOMCTL_DEV_DT;
     domctl.u.assign_device.u.dt.size = size;
+    /*
+     * DT doesn't own any RDM so actually DT has nothing to do
+     * for any flag and here just fix that as 0.
+     */
+    domctl.u.assign_device.flag = 0;
     set_xen_guest_handle(domctl.u.assign_device.u.dt.path, path);
 
     rc = do_domctl(xch, &domctl);
diff --git a/tools/libxl/libxl_pci.c b/tools/libxl/libxl_pci.c
index e0743f8..632c15e 100644
--- a/tools/libxl/libxl_pci.c
+++ b/tools/libxl/libxl_pci.c
@@ -894,6 +894,7 @@ static int do_pci_add(libxl__gc *gc, uint32_t domid, libxl_device_pci *pcidev, i
     FILE *f;
     unsigned long long start, end, flags, size;
     int irq, i, rc, hvm = 0;
+    uint32_t flag = XEN_DOMCTL_DEV_RDM_RELAXED;
 
     if (type == LIBXL_DOMAIN_TYPE_INVALID)
         return ERROR_FAIL;
@@ -987,7 +988,7 @@ static int do_pci_add(libxl__gc *gc, uint32_t domid, libxl_device_pci *pcidev, i
 
 out:
     if (!libxl_is_stubdom(ctx, domid, NULL)) {
-        rc = xc_assign_device(ctx->xch, domid, pcidev_encode_bdf(pcidev));
+        rc = xc_assign_device(ctx->xch, domid, pcidev_encode_bdf(pcidev), flag);
         if (rc < 0 && (hvm || errno != ENOSYS)) {
             LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_assign_device failed");
             return ERROR_FAIL;
diff --git a/tools/ocaml/libs/xc/xenctrl_stubs.c b/tools/ocaml/libs/xc/xenctrl_stubs.c
index 64f1137..b7de615 100644
--- a/tools/ocaml/libs/xc/xenctrl_stubs.c
+++ b/tools/ocaml/libs/xc/xenctrl_stubs.c
@@ -1172,12 +1172,17 @@ CAMLprim value stub_xc_domain_test_assign_device(value xch, value domid, value d
 	CAMLreturn(Val_bool(ret == 0));
 }
 
-CAMLprim value stub_xc_domain_assign_device(value xch, value domid, value desc)
+static int domain_assign_device_rdm_flag_table[] = {
+    XEN_DOMCTL_DEV_RDM_RELAXED,
+};
+
+CAMLprim value stub_xc_domain_assign_device(value xch, value domid, value desc,
+                                            value rflag)
 {
-	CAMLparam3(xch, domid, desc);
+	CAMLparam4(xch, domid, desc, rflag);
 	int ret;
 	int domain, bus, dev, func;
-	uint32_t sbdf;
+	uint32_t sbdf, flag;
 
 	domain = Int_val(Field(desc, 0));
 	bus = Int_val(Field(desc, 1));
@@ -1185,7 +1190,10 @@ CAMLprim value stub_xc_domain_assign_device(value xch, value domid, value desc)
 	func = Int_val(Field(desc, 3));
 	sbdf = encode_sbdf(domain, bus, dev, func);
 
-	ret = xc_assign_device(_H(xch), _D(domid), sbdf);
+	ret = Int_val(Field(rflag, 0));
+	flag = domain_assign_device_rdm_flag_table[ret];
+
+	ret = xc_assign_device(_H(xch), _D(domid), sbdf, flag);
 
 	if (ret < 0)
 		failwith_xc(_H(xch));
diff --git a/tools/python/xen/lowlevel/xc/xc.c b/tools/python/xen/lowlevel/xc/xc.c
index c77e15b..a4928c6 100644
--- a/tools/python/xen/lowlevel/xc/xc.c
+++ b/tools/python/xen/lowlevel/xc/xc.c
@@ -592,7 +592,8 @@ static int token_value(char *token)
     return strtol(token, NULL, 16);
 }
 
-static int next_bdf(char **str, int *seg, int *bus, int *dev, int *func)
+static int next_bdf(char **str, int *seg, int *bus, int *dev, int *func,
+                    int *flag)
 {
     char *token;
 
@@ -607,8 +608,17 @@ static int next_bdf(char **str, int *seg, int *bus, int *dev, int *func)
     *dev  = token_value(token);
     token = strchr(token, ',') + 1;
     *func  = token_value(token);
-    token = strchr(token, ',');
-    *str = token ? token + 1 : NULL;
+    token = strchr(token, ',') + 1;
+    if ( token ) {
+        *flag = token_value(token);
+        *str = token + 1;
+    }
+    else
+    {
+        /* O means we take "strict" as our default policy. */
+        *flag = 0;
+        *str = NULL;
+    }
 
     return 1;
 }
@@ -620,14 +630,14 @@ static PyObject *pyxc_test_assign_device(XcObject *self,
     uint32_t dom;
     char *pci_str;
     int32_t sbdf = 0;
-    int seg, bus, dev, func;
+    int seg, bus, dev, func, flag;
 
     static char *kwd_list[] = { "domid", "pci", NULL };
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is", kwd_list,
                                       &dom, &pci_str) )
         return NULL;
 
-    while ( next_bdf(&pci_str, &seg, &bus, &dev, &func) )
+    while ( next_bdf(&pci_str, &seg, &bus, &dev, &func, &flag) )
     {
         sbdf = seg << 16;
         sbdf |= (bus & 0xff) << 8;
@@ -653,21 +663,21 @@ static PyObject *pyxc_assign_device(XcObject *self,
     uint32_t dom;
     char *pci_str;
     int32_t sbdf = 0;
-    int seg, bus, dev, func;
+    int seg, bus, dev, func, flag;
 
     static char *kwd_list[] = { "domid", "pci", NULL };
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is", kwd_list,
                                       &dom, &pci_str) )
         return NULL;
 
-    while ( next_bdf(&pci_str, &seg, &bus, &dev, &func) )
+    while ( next_bdf(&pci_str, &seg, &bus, &dev, &func, &flag) )
     {
         sbdf = seg << 16;
         sbdf |= (bus & 0xff) << 8;
         sbdf |= (dev & 0x1f) << 3;
         sbdf |= (func & 0x7);
 
-        if ( xc_assign_device(self->xc_handle, dom, sbdf) != 0 )
+        if ( xc_assign_device(self->xc_handle, dom, sbdf, flag) != 0 )
         {
             if (errno == ENOSYS)
                 sbdf = -1;
@@ -686,14 +696,14 @@ static PyObject *pyxc_deassign_device(XcObject *self,
     uint32_t dom;
     char *pci_str;
     int32_t sbdf = 0;
-    int seg, bus, dev, func;
+    int seg, bus, dev, func, flag;
 
     static char *kwd_list[] = { "domid", "pci", NULL };
     if ( !PyArg_ParseTupleAndKeywords(args, kwds, "is", kwd_list,
                                       &dom, &pci_str) )
         return NULL;
 
-    while ( next_bdf(&pci_str, &seg, &bus, &dev, &func) )
+    while ( next_bdf(&pci_str, &seg, &bus, &dev, &func, &flag) )
     {
         sbdf = seg << 16;
         sbdf |= (bus & 0xff) << 8;
-- 
1.9.1

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

* [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
                   ` (8 preceding siblings ...)
  2015-07-07  6:17 ` [v5][PATCH 09/16] tools: extend xc_assign_device() to support rdm reservation policy Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07 10:21   ` Wei Liu
  2015-07-07 11:47   ` Ian Jackson
  2015-07-07  6:17 ` [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM Tiejun Chen
                   ` (5 subsequent siblings)
  15 siblings, 2 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Ian Jackson, Ian Campbell, Stefano Stabellini

This patch introduces user configurable parameters to specify RDM
resource and according policies,

Global RDM parameter:
    rdm = "type=none/host,reserve=strict/relaxed"
Per-device RDM parameter:
    pci = [ 'sbdf, rdm_reserve=strict/relaxed' ]

Global RDM parameter, "type", allows user to specify reserved regions
explicitly, e.g. using 'host' to include all reserved regions reported
on this platform which is good to handle hotplug scenario. In the future
this parameter may be further extended to allow specifying random regions,
e.g. even those belonging to another platform as a preparation for live
migration with passthrough devices. Instead, 'none' means we have nothing
to do all reserved regions and ignore all policies, so guest work as before.

'strict/relaxed' policy decides how to handle conflict when reserving RDM
regions in pfn space. If conflict exists, 'strict' means an immediate error
so VM can't keep running, while 'relaxed' allows moving forward with a
warning message thrown out.

Default per-device RDM policy is 'strict', while default global RDM policy
is 'relaxed'. And the per-device policy would override the global policy like
others.

CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
---
v5:

* Just make sure the per-device plicy always override the global policy,
  and so cleanup some associated comments and the patch head description.
* A little change to follow one bit, XEN_DOMCTL_DEV_RDM_RELAXED.
* Improve all descriptions in doc.
* Make all rdm variables specific to .hvm

v4:

* No need to define init_val for libxl_rdm_reserve_type since its just zero
* Grab those changes to xl/libxlu to as a final patch

 docs/man/xl.cfg.pod.5        | 84 ++++++++++++++++++++++++++++++++++++++++++++
 docs/misc/vtd.txt            | 24 +++++++++++++
 tools/libxl/libxl_create.c   |  7 ++++
 tools/libxl/libxl_internal.h |  2 ++
 tools/libxl/libxl_pci.c      |  9 +++++
 tools/libxl/libxl_types.idl  | 18 ++++++++++
 6 files changed, 144 insertions(+)

diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5
index a3e0e2e..a2dc343 100644
--- a/docs/man/xl.cfg.pod.5
+++ b/docs/man/xl.cfg.pod.5
@@ -655,6 +655,83 @@ assigned slave device.
 
 =back
 
+=item B<rdm="RDM_RESERVATION_STRING">
+
+(HVM/x86 only) Specifies information about Reserved Device Memory (RDM),
+which is necessary to enable robust device passthrough. One example of RDM
+is reported through ACPI Reserved Memory Region Reporting (RMRR) structure
+on x86 platform.
+
+B<RDM_RESERVE_STRING> has the form C<[KEY=VALUE,KEY=VALUE,...> where:
+
+=over 4
+
+=item B<KEY=VALUE>
+
+Possible B<KEY>s are:
+
+=over 4
+
+=item B<type="STRING">
+
+Currently there are only two valid types:
+
+"host" means all reserved device memory on this platform should be checked to
+reserve regions in this VM's guest address space. This global RDM parameter
+allows user to specify reserved regions explicitly, and using "host" includes
+all reserved regions reported on this platform, which is useful when doing
+hotplug.
+
+"none" is the default value and it means we don't check any reserved regions
+and then all rdm policies would be ignored. Guest just works as before and
+the conflict of RDM and guest address space wouldn't be handled, and then
+this may result in the associated device not being able to work or even crash
+the VM. So if you're assigning this kind of device, this option is not
+recommended unless you can make sure any conflict doesn't exist.
+
+For example, you're trying to set "memory = 2800" to allocate memory to one
+given VM but the platform owns two RDM regions like,
+
+RMRR region: base_addr ac6d3000 end_address ac6e6fff
+RMRR region: base_addr ad800000 end_address afffffff
+
+In this conflict case,
+
+#1. If the type options is set with "none",
+
+rdm = "type=none,reserve=strict" or rdm = "type=none,reserve=relaxed"
+
+mean we don't handle any conflict just to make VM keep running as before.
+Note this is our default behavior.
+
+#2. If the type options is set with "host",
+
+rdm = "type=host,reserve=strict" or rdm = "type=host,reserve=relaxed"
+
+mean all conflict would be handled according to our policies which is
+introduced by the reserve option as described below.
+
+=item B<reserve="STRING">
+
+Specifies how to deal with conflicts discovered when reserving reserved device
+memory in the guest address space.
+
+When that conflict is unsolved,
+
+"strict" means this VM can't be created successfully, or the associated device
+can't be attached in the case of hotplug;
+
+"relaxed" allows a VM to be created to keep running with a warning message
+thrown out. But this may crash this VM if this device accesses RDM. For example,
+Windows IGD GFX driver always access these regions so this lead to a blue screen
+to crash VM in such a case.
+
+Note this may be overridden by rdm_reserve option in PCI device configuration.
+
+=back
+
+=back
+
 =item B<pci=[ "PCI_SPEC_STRING", "PCI_SPEC_STRING", ... ]>
 
 Specifies the host PCI devices to passthrough to this guest. Each B<PCI_SPEC_STRING>
@@ -717,6 +794,13 @@ dom0 without confirmation.  Please use with care.
 D0-D3hot power management states for the PCI device. False (0) by
 default.
 
+=item B<rdm_reserve="STRING">
+
+(HVM/x86 only) This is same as reserve option inside the rdm option
+but just specific to a given device, and "strict" is default here.
+
+Note this would override global B<rdm> option.
+
 =back
 
 =back
diff --git a/docs/misc/vtd.txt b/docs/misc/vtd.txt
index 9af0e99..7d63c47 100644
--- a/docs/misc/vtd.txt
+++ b/docs/misc/vtd.txt
@@ -111,6 +111,30 @@ in the config file:
 To override for a specific device:
 	pci = [ '01:00.0,msitranslate=0', '03:00.0' ]
 
+RDM, 'reserved device memory', for PCI Device Passthrough
+---------------------------------------------------------
+
+There are some devices the BIOS controls, for e.g. USB devices to perform
+PS2 emulation. The regions of memory used for these devices are marked
+reserved in the e820 map. When we turn on DMA translation, DMA to those
+regions will fail. Hence BIOS uses RMRR to specify these regions along with
+devices that need to access these regions. OS is expected to setup
+identity mappings for these regions for these devices to access these regions.
+
+While creating a VM we should reserve them in advance, and avoid any conflicts.
+So we introduce user configurable parameters to specify RDM resource and
+according policies,
+
+To enable this globally, add "rdm" in the config file:
+
+    rdm = "type=host, reserve=relaxed"   (default policy is "relaxed")
+
+Or just for a specific device:
+
+    pci = [ '01:00.0,rdm_reserve=relaxed', '03:00.0,rdm_reserve=strict' ]
+
+For all the options available to RDM, see xl.cfg(5).
+
 
 Caveat on Conventional PCI Device Passthrough
 ---------------------------------------------
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index f366a09..b884fa1 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -105,6 +105,12 @@ static int sched_params_valid(libxl__gc *gc,
     return 1;
 }
 
+void libxl__rdm_setdefault(libxl__gc *gc, libxl_domain_build_info *b_info)
+{
+    if (b_info->u.hvm.rdm.reserve == LIBXL_RDM_RESERVE_FLAG_INVALID)
+        b_info->u.hvm.rdm.reserve = LIBXL_RDM_RESERVE_FLAG_RELAXED;
+}
+
 int libxl__domain_build_info_setdefault(libxl__gc *gc,
                                         libxl_domain_build_info *b_info)
 {
@@ -384,6 +390,7 @@ int libxl__domain_build_info_setdefault(libxl__gc *gc,
 
         libxl_defbool_setdefault(&b_info->u.hvm.gfx_passthru, false);
 
+        libxl__rdm_setdefault(gc, b_info);
         break;
     case LIBXL_DOMAIN_TYPE_PV:
         libxl_defbool_setdefault(&b_info->u.pv.e820_host, false);
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index d52589e..d397143 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1154,6 +1154,8 @@ _hidden int libxl__device_vtpm_setdefault(libxl__gc *gc, libxl_device_vtpm *vtpm
 _hidden int libxl__device_vfb_setdefault(libxl__gc *gc, libxl_device_vfb *vfb);
 _hidden int libxl__device_vkb_setdefault(libxl__gc *gc, libxl_device_vkb *vkb);
 _hidden int libxl__device_pci_setdefault(libxl__gc *gc, libxl_device_pci *pci);
+_hidden void libxl__rdm_setdefault(libxl__gc *gc,
+                                   libxl_domain_build_info *b_info);
 
 _hidden const char *libxl__device_nic_devname(libxl__gc *gc,
                                               uint32_t domid,
diff --git a/tools/libxl/libxl_pci.c b/tools/libxl/libxl_pci.c
index 632c15e..f0a32fa 100644
--- a/tools/libxl/libxl_pci.c
+++ b/tools/libxl/libxl_pci.c
@@ -988,6 +988,12 @@ static int do_pci_add(libxl__gc *gc, uint32_t domid, libxl_device_pci *pcidev, i
 
 out:
     if (!libxl_is_stubdom(ctx, domid, NULL)) {
+        if (pcidev->rdm_reserve == LIBXL_RDM_RESERVE_FLAG_STRICT) {
+            flag &= ~XEN_DOMCTL_DEV_RDM_RELAXED;
+        } else if (pcidev->rdm_reserve != LIBXL_RDM_RESERVE_FLAG_RELAXED) {
+            LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "unknown rdm check flag.");
+            return ERROR_FAIL;
+        }
         rc = xc_assign_device(ctx->xch, domid, pcidev_encode_bdf(pcidev), flag);
         if (rc < 0 && (hvm || errno != ENOSYS)) {
             LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "xc_assign_device failed");
@@ -1040,6 +1046,9 @@ static int libxl__device_pci_reset(libxl__gc *gc, unsigned int domain, unsigned
 
 int libxl__device_pci_setdefault(libxl__gc *gc, libxl_device_pci *pci)
 {
+    /* We'd like to force reserve rdm specific to a device by default.*/
+    if ( pci->rdm_reserve == LIBXL_RDM_RESERVE_FLAG_INVALID)
+        pci->rdm_reserve = LIBXL_RDM_RESERVE_FLAG_STRICT;
     return 0;
 }
 
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index e1632fa..0602fff 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -76,6 +76,17 @@ libxl_domain_type = Enumeration("domain_type", [
     (2, "PV"),
     ], init_val = "LIBXL_DOMAIN_TYPE_INVALID")
 
+libxl_rdm_reserve_type = Enumeration("rdm_reserve_type", [
+    (0, "none"),
+    (1, "host"),
+    ])
+
+libxl_rdm_reserve_flag = Enumeration("rdm_reserve_flag", [
+    (-1, "invalid"),
+    (0, "strict"),
+    (1, "relaxed"),
+    ], init_val = "LIBXL_RDM_RESERVE_FLAG_INVALID")
+
 libxl_channel_connection = Enumeration("channel_connection", [
     (0, "UNKNOWN"),
     (1, "PTY"),
@@ -369,6 +380,11 @@ libxl_vnode_info = Struct("vnode_info", [
     ("vcpus", libxl_bitmap), # vcpus in this node
     ])
 
+libxl_rdm_reserve = Struct("rdm_reserve", [
+    ("type",    libxl_rdm_reserve_type),
+    ("reserve",   libxl_rdm_reserve_flag),
+    ])
+
 libxl_domain_build_info = Struct("domain_build_info",[
     ("max_vcpus",       integer),
     ("avail_vcpus",     libxl_bitmap),
@@ -467,6 +483,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
                                        # See libxl_ms_vm_genid_generate()
                                        ("ms_vm_genid",      libxl_ms_vm_genid),
                                        ("serial_list",      libxl_string_list),
+                                       ("rdm", libxl_rdm_reserve),
                                        ])),
                  ("pv", Struct(None, [("kernel", string),
                                       ("slack_memkb", MemKB),
@@ -542,6 +559,7 @@ libxl_device_pci = Struct("device_pci", [
     ("power_mgmt", bool),
     ("permissive", bool),
     ("seize", bool),
+    ("rdm_reserve",   libxl_rdm_reserve_flag),
     ])
 
 libxl_device_dtdev = Struct("device_dtdev", [
-- 
1.9.1

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

* [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
                   ` (9 preceding siblings ...)
  2015-07-07  6:17 ` [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07 11:20   ` Wei Liu
                     ` (2 more replies)
  2015-07-07  6:17 ` [v5][PATCH 12/16] tools: introduce a new parameter to set a predefined rdm boundary Tiejun Chen
                   ` (4 subsequent siblings)
  15 siblings, 3 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Ian Jackson, Ian Campbell, Stefano Stabellini

While building a VM, HVM domain builder provides struct hvm_info_table{}
to help hvmloader. Currently it includes two fields to construct guest
e820 table by hvmloader, low_mem_pgend and high_mem_pgend. So we should
check them to fix any conflict with RDM.

RMRR can reside in address space beyond 4G theoretically, but we never
see this in real world. So in order to avoid breaking highmem layout
we don't solve highmem conflict. Note this means highmem rmrr could still
be supported if no conflict.

But in the case of lowmem, RMRR probably scatter the whole RAM space.
Especially multiple RMRR entries would worsen this to lead a complicated
memory layout. And then its hard to extend hvm_info_table{} to work
hvmloader out. So here we're trying to figure out a simple solution to
avoid breaking existing layout. So when a conflict occurs,

    #1. Above a predefined boundary (2G)
        - move lowmem_end below reserved region to solve conflict;

    #2. Below a predefined boundary (2G)
        - Check strict/relaxed policy.
        "strict" policy leads to fail libxl. Note when both policies
        are specified on a given region, 'strict' is always preferred.
        "relaxed" policy issue a warning message and also mask this entry INVALID
        to indicate we shouldn't expose this entry to hvmloader.

Note later we need to provide a parameter to set that predefined boundary
dynamically.

CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
Reviewed-by: Kevin Tian <kevint.tian@intel.com>
---
v5:

* A little change to make sure the per-device policy always override the global
  policy and correct its associated code comments.
* Fix one typo in the patch head description
* Rename xc_device_get_rdm() with libxl__xc_device_get_rdm(), and then replace
  malloc() with libxl__malloc(), and finally cleanup this fallout.
* libxl__xc_device_get_rdm() should return proper libxl error code, ERROR_FAIL.
  Then instead, the allocated RDM entries would be returned with an out parameter.

v4:

* Consistent to use term "RDM".
* Unconditionally set *nr_entries to 0
* Grab to all sutffs to provide a parameter to set our predefined boundary
  dynamically to as a separated patch later

 tools/libxl/libxl_create.c   |   2 +-
 tools/libxl/libxl_dm.c       | 267 +++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxl_dom.c      |  17 ++-
 tools/libxl/libxl_internal.h |  11 +-
 tools/libxl/libxl_types.idl  |   7 ++
 5 files changed, 301 insertions(+), 3 deletions(-)

diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index b884fa1..7a0c57d 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -459,7 +459,7 @@ int libxl__domain_build(libxl__gc *gc,
 
     switch (info->type) {
     case LIBXL_DOMAIN_TYPE_HVM:
-        ret = libxl__build_hvm(gc, domid, info, state);
+        ret = libxl__build_hvm(gc, domid, d_config, state);
         if (ret)
             goto out;
 
diff --git a/tools/libxl/libxl_dm.c b/tools/libxl/libxl_dm.c
index 317a8eb..71b602e 100644
--- a/tools/libxl/libxl_dm.c
+++ b/tools/libxl/libxl_dm.c
@@ -90,6 +90,273 @@ const char *libxl__domain_device_model(libxl__gc *gc,
     return dm;
 }
 
+static int
+libxl__xc_device_get_rdm(libxl__gc *gc,
+                         uint32_t flag,
+                         uint16_t seg,
+                         uint8_t bus,
+                         uint8_t devfn,
+                         unsigned int *nr_entries,
+                         struct xen_reserved_device_memory **xrdm)
+{
+    int rc;
+
+    /*
+     * We really can't presume how many entries we can get in advance.
+     */
+    *nr_entries = 0;
+    rc = xc_reserved_device_memory_map(CTX->xch, flag, seg, bus, devfn,
+                                       NULL, nr_entries);
+    assert(rc <= 0);
+    /* "0" means we have no any rdm entry. */
+    if (!rc)
+        goto out;
+
+    if (errno == ENOBUFS) {
+        *xrdm = libxl__malloc(gc,
+                              *nr_entries *
+                              sizeof(xen_reserved_device_memory_t));
+        rc = xc_reserved_device_memory_map(CTX->xch, flag, seg, bus, devfn,
+                                           *xrdm, nr_entries);
+        if (rc) {
+            LOG(ERROR, "Could not get reserved device memory maps.\n");
+            rc = ERROR_FAIL;
+        }
+    } else {
+        LOG(ERROR, "Could not get reserved device memory maps.\n");
+        rc = ERROR_FAIL;
+    }
+
+ out:
+    if (rc) {
+        *nr_entries = 0;
+        *xrdm = NULL;
+    }
+    return rc;
+}
+
+/*
+ * Check whether there exists rdm hole in the specified memory range.
+ * Returns true if exists, else returns false.
+ */
+static bool overlaps_rdm(uint64_t start, uint64_t memsize,
+                         uint64_t rdm_start, uint64_t rdm_size)
+{
+    return (start + memsize > rdm_start) && (start < rdm_start + rdm_size);
+}
+
+/*
+ * Check reported RDM regions and handle potential gfn conflicts according
+ * to user preferred policy.
+ *
+ * RDM can reside in address space beyond 4G theoretically, but we never
+ * see this in real world. So in order to avoid breaking highmem layout
+ * we don't solve highmem conflict. Note this means highmem rmrr could still
+ * be supported if no conflict.
+ *
+ * But in the case of lowmem, RDM probably scatter the whole RAM space.
+ * Especially multiple RDM entries would worsen this to lead a complicated
+ * memory layout. And then its hard to extend hvm_info_table{} to work
+ * hvmloader out. So here we're trying to figure out a simple solution to
+ * avoid breaking existing layout. So when a conflict occurs,
+ *
+ * #1. Above a predefined boundary (default 2G)
+ * - Move lowmem_end below reserved region to solve conflict;
+ *
+ * #2. Below a predefined boundary (default 2G)
+ * - Check strict/relaxed policy.
+ * "strict" policy leads to fail libxl.
+ * "relaxed" policy issue a warning message and also mask this entry
+ * INVALID to indicate we shouldn't expose this entry to hvmloader.
+ * Note when both policies are specified on a given region, the per-device
+ * policy should override the global policy.
+ */
+int libxl__domain_device_construct_rdm(libxl__gc *gc,
+                                       libxl_domain_config *d_config,
+                                       uint64_t rdm_mem_boundary,
+                                       struct xc_hvm_build_args *args)
+{
+    int i, j, conflict, rc;
+    struct xen_reserved_device_memory *xrdm = NULL;
+    uint32_t type = d_config->b_info.u.hvm.rdm.type;
+    uint16_t seg;
+    uint8_t bus, devfn;
+    uint64_t rdm_start, rdm_size;
+    uint64_t highmem_end = args->highmem_end ? args->highmem_end : (1ull<<32);
+
+    /* Might not expose rdm. */
+    if (type == LIBXL_RDM_RESERVE_TYPE_NONE && !d_config->num_pcidevs)
+        return 0;
+
+    /* Query all RDM entries in this platform */
+    if (type == LIBXL_RDM_RESERVE_TYPE_HOST) {
+        unsigned int nr_entries;
+
+        /* Collect all rdm info if exist. */
+        rc = libxl__xc_device_get_rdm(gc, PCI_DEV_RDM_ALL,
+                                      0, 0, 0, &nr_entries, &xrdm);
+        if (rc)
+            goto out;
+        if (!nr_entries)
+            return 0;
+
+        assert(xrdm);
+
+        d_config->num_rdms = nr_entries;
+        d_config->rdms = libxl__realloc(NOGC, d_config->rdms,
+                                d_config->num_rdms * sizeof(libxl_device_rdm));
+
+        for (i = 0; i < d_config->num_rdms; i++) {
+            d_config->rdms[i].start =
+                                (uint64_t)xrdm[i].start_pfn << XC_PAGE_SHIFT;
+            d_config->rdms[i].size =
+                                (uint64_t)xrdm[i].nr_pages << XC_PAGE_SHIFT;
+            d_config->rdms[i].flag = d_config->b_info.u.hvm.rdm.reserve;
+        }
+    } else
+        d_config->num_rdms = 0;
+
+    /* Query RDM entries per-device */
+    for (i = 0; i < d_config->num_pcidevs; i++) {
+        unsigned int nr_entries;
+        bool new = true;
+
+        seg = d_config->pcidevs[i].domain;
+        bus = d_config->pcidevs[i].bus;
+        devfn = PCI_DEVFN(d_config->pcidevs[i].dev, d_config->pcidevs[i].func);
+        nr_entries = 0;
+        rc = libxl__xc_device_get_rdm(gc, ~PCI_DEV_RDM_ALL,
+                                      seg, bus, devfn, &nr_entries, &xrdm);
+        if (rc)
+            goto out;
+        /* No RDM to associated with this device. */
+        if (!nr_entries)
+            continue;
+
+        assert(xrdm);
+
+        /*
+         * Need to check whether this entry is already saved in the array.
+         * This could come from two cases:
+         *
+         *   - user may configure to get all RDMs in this platform, which
+         *   is already queried before this point
+         *   - or two assigned devices may share one RDM entry
+         *
+         * Different policies may be configured on the same RDM due to above
+         * two cases. But we don't allow to assign such a group devies right
+         * now so it doesn't come true in our case.
+         */
+        for (j = 0; j < d_config->num_rdms; j++) {
+            if (d_config->rdms[j].start ==
+                                (uint64_t)xrdm[0].start_pfn << XC_PAGE_SHIFT)
+            {
+                /*
+                 * So the per-device policy always override the global policy
+                 * in this case.
+                 */
+                d_config->rdms[j].flag = d_config->pcidevs[i].rdm_reserve;
+                new = false;
+                break;
+            }
+        }
+
+        if (new) {
+            d_config->num_rdms++;
+            d_config->rdms = libxl__realloc(NOGC, d_config->rdms,
+                                d_config->num_rdms * sizeof(libxl_device_rdm));
+
+            d_config->rdms[d_config->num_rdms - 1].start =
+                                (uint64_t)xrdm[0].start_pfn << XC_PAGE_SHIFT;
+            d_config->rdms[d_config->num_rdms - 1].size =
+                                (uint64_t)xrdm[0].nr_pages << XC_PAGE_SHIFT;
+            d_config->rdms[d_config->num_rdms - 1].flag =
+                                d_config->pcidevs[i].rdm_reserve;
+        }
+    }
+
+    /*
+     * Next step is to check and avoid potential conflict between RDM entries
+     * and guest RAM. To avoid intrusive impact to existing memory layout
+     * {lowmem, mmio, highmem} which is passed around various function blocks,
+     * below conflicts are not handled which are rare and handling them would
+     * lead to a more scattered layout:
+     *  - RDM  in highmem area (>4G)
+     *  - RDM lower than a defined memory boundary (e.g. 2G)
+     * Otherwise for conflicts between boundary and 4G, we'll simply move lowmem
+     * end below reserved region to solve conflict.
+     *
+     * If a conflict is detected on a given RDM entry, an error will be
+     * returned if 'strict' policy is specified. Instead, if 'relaxed' policy
+     * specified, this conflict is treated just as a warning, but we mark this
+     * RDM entry as INVALID to indicate that this entry shouldn't be exposed
+     * to hvmloader.
+     *
+     * Firstly we should check the case of rdm < 4G because we may need to
+     * expand highmem_end.
+     */
+    for (i = 0; i < d_config->num_rdms; i++) {
+        rdm_start = d_config->rdms[i].start;
+        rdm_size = d_config->rdms[i].size;
+        conflict = overlaps_rdm(0, args->lowmem_end, rdm_start, rdm_size);
+
+        if (!conflict)
+            continue;
+
+        /* Just check if RDM > our memory boundary. */
+        if (rdm_start > rdm_mem_boundary) {
+            /*
+             * We will move downwards lowmem_end so we have to expand
+             * highmem_end.
+             */
+            highmem_end += (args->lowmem_end - rdm_start);
+            /* Now move downwards lowmem_end. */
+            args->lowmem_end = rdm_start;
+        }
+    }
+
+    /* Sync highmem_end. */
+    args->highmem_end = highmem_end;
+
+    /*
+     * Finally we can take same policy to check lowmem(< 2G) and
+     * highmem adjusted above.
+     */
+    for (i = 0; i < d_config->num_rdms; i++) {
+        rdm_start = d_config->rdms[i].start;
+        rdm_size = d_config->rdms[i].size;
+        /* Does this entry conflict with lowmem? */
+        conflict = overlaps_rdm(0, args->lowmem_end,
+                                rdm_start, rdm_size);
+        /* Does this entry conflict with highmem? */
+        conflict |= overlaps_rdm((1ULL<<32),
+                                 args->highmem_end - (1ULL<<32),
+                                 rdm_start, rdm_size);
+
+        if (!conflict)
+            continue;
+
+        if(d_config->rdms[i].flag == LIBXL_RDM_RESERVE_FLAG_STRICT) {
+            LOG(ERROR, "RDM conflict at 0x%lx.\n", d_config->rdms[i].start);
+            goto out;
+        } else {
+            LOG(WARN, "Ignoring RDM conflict at 0x%lx.\n",
+                      d_config->rdms[i].start);
+
+            /*
+             * Then mask this INVALID to indicate we shouldn't expose this
+             * to hvmloader.
+             */
+            d_config->rdms[i].flag = LIBXL_RDM_RESERVE_FLAG_INVALID;
+        }
+    }
+
+    return 0;
+
+ out:
+    return ERROR_FAIL;
+}
+
 const libxl_vnc_info *libxl__dm_vnc(const libxl_domain_config *guest_config)
 {
     const libxl_vnc_info *vnc = NULL;
diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
index bdc0465..f3c39a0 100644
--- a/tools/libxl/libxl_dom.c
+++ b/tools/libxl/libxl_dom.c
@@ -914,13 +914,20 @@ out:
 }
 
 int libxl__build_hvm(libxl__gc *gc, uint32_t domid,
-              libxl_domain_build_info *info,
+              libxl_domain_config *d_config,
               libxl__domain_build_state *state)
 {
     libxl_ctx *ctx = libxl__gc_owner(gc);
     struct xc_hvm_build_args args = {};
     int ret, rc = ERROR_FAIL;
     uint64_t mmio_start, lowmem_end, highmem_end;
+    libxl_domain_build_info *const info = &d_config->b_info;
+    /*
+     * Currently we fix this as 2G to guarantte how to handle
+     * our rdm policy. But we'll provide a parameter to set
+     * this dynamically.
+     */
+    uint64_t rdm_mem_boundary = 0x80000000;
 
     memset(&args, 0, sizeof(struct xc_hvm_build_args));
     /* The params from the configuration file are in Mb, which are then
@@ -958,6 +965,14 @@ int libxl__build_hvm(libxl__gc *gc, uint32_t domid,
     args.highmem_end = highmem_end;
     args.mmio_start = mmio_start;
 
+    ret = libxl__domain_device_construct_rdm(gc, d_config,
+                                             rdm_mem_boundary,
+                                             &args);
+    if (ret) {
+        LOG(ERROR, "checking reserved device memory failed");
+        goto out;
+    }
+
     if (info->num_vnuma_nodes != 0) {
         int i;
 
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index d397143..b4d8419 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -1057,7 +1057,7 @@ _hidden int libxl__build_post(libxl__gc *gc, uint32_t domid,
 _hidden int libxl__build_pv(libxl__gc *gc, uint32_t domid,
              libxl_domain_build_info *info, libxl__domain_build_state *state);
 _hidden int libxl__build_hvm(libxl__gc *gc, uint32_t domid,
-              libxl_domain_build_info *info,
+              libxl_domain_config *d_config,
               libxl__domain_build_state *state);
 
 _hidden int libxl__qemu_traditional_cmd(libxl__gc *gc, uint32_t domid,
@@ -1565,6 +1565,15 @@ _hidden int libxl__need_xenpv_qemu(libxl__gc *gc,
         int nr_channels, libxl_device_channel *channels);
 
 /*
+ * This function will fix reserved device memory conflict
+ * according to user's configuration.
+ */
+_hidden int libxl__domain_device_construct_rdm(libxl__gc *gc,
+                                   libxl_domain_config *d_config,
+                                   uint64_t rdm_mem_guard,
+                                   struct xc_hvm_build_args *args);
+
+/*
  * This function will cause the whole libxl process to hang
  * if the device model does not respond.  It is deprecated.
  *
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 0602fff..1a8a180 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -562,6 +562,12 @@ libxl_device_pci = Struct("device_pci", [
     ("rdm_reserve",   libxl_rdm_reserve_flag),
     ])
 
+libxl_device_rdm = Struct("device_rdm", [
+    ("start", uint64),
+    ("size", uint64),
+    ("flag", libxl_rdm_reserve_flag),
+    ])
+
 libxl_device_dtdev = Struct("device_dtdev", [
     ("path", string),
     ])
@@ -592,6 +598,7 @@ libxl_domain_config = Struct("domain_config", [
     ("disks", Array(libxl_device_disk, "num_disks")),
     ("nics", Array(libxl_device_nic, "num_nics")),
     ("pcidevs", Array(libxl_device_pci, "num_pcidevs")),
+    ("rdms", Array(libxl_device_rdm, "num_rdms")),
     ("dtdevs", Array(libxl_device_dtdev, "num_dtdevs")),
     ("vfbs", Array(libxl_device_vfb, "num_vfbs")),
     ("vkbs", Array(libxl_device_vkb, "num_vkbs")),
-- 
1.9.1

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

* [v5][PATCH 12/16] tools: introduce a new parameter to set a predefined rdm boundary
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
                   ` (10 preceding siblings ...)
  2015-07-07  6:17 ` [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07 11:22   ` Wei Liu
  2015-07-07  6:17 ` [v5][PATCH 13/16] libxl: construct e820 map with RDM information for HVM guest Tiejun Chen
                   ` (3 subsequent siblings)
  15 siblings, 1 reply; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Ian Jackson, Ian Campbell, Stefano Stabellini

Previously we always fix that predefined boundary as 2G to handle
conflict between memory and rdm, but now this predefined boundar
can be changes with the parameter "rdm_mem_boundary" in .cfg file.

CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
---
v5:

* Make this variable "rdm_mem_boundary_memkb" specific to .hvm 

v4:

* Separated from the previous patch to provide a parameter to set that
  predefined boundary dynamically.

 docs/man/xl.cfg.pod.5       | 22 ++++++++++++++++++++++
 tools/libxl/libxl.h         |  6 ++++++
 tools/libxl/libxl_create.c  |  4 ++++
 tools/libxl/libxl_dom.c     |  8 +-------
 tools/libxl/libxl_types.idl |  1 +
 tools/libxl/xl_cmdimpl.c    |  3 +++
 6 files changed, 37 insertions(+), 7 deletions(-)

diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5
index a2dc343..d1ba590 100644
--- a/docs/man/xl.cfg.pod.5
+++ b/docs/man/xl.cfg.pod.5
@@ -870,6 +870,28 @@ More information about Xen gfx_passthru feature is available
 on the XenVGAPassthrough L<http://wiki.xen.org/wiki/XenVGAPassthrough>
 wiki page.
 
+=item B<rdm_mem_boundary=MBYTES>
+
+Number of megabytes to set a boundary for checking rdm conflict.
+
+When RDM conflicts with RAM, RDM probably scatter the whole RAM space.
+Especially multiple RDM entries would worsen this to lead a complicated
+memory layout. So here we're trying to figure out a simple solution to
+avoid breaking existing layout. So when a conflict occurs,
+
+    #1. Above a predefined boundary
+        - move lowmem_end below reserved region to solve conflict;
+
+    #2. Below a predefined boundary
+        - Check strict/relaxed policy.
+        "strict" policy leads to fail libxl. Note when both policies
+        are specified on a given region, 'strict' is always preferred.
+        "relaxed" policy issue a warning message and also mask this
+        entry INVALID to indicate we shouldn't expose this entry to
+        hvmloader.
+
+Here the default is 2G.
+
 =item B<dtdev=[ "DTDEV_PATH", "DTDEV_PATH", ... ]>
 
 Specifies the host device tree nodes to passthrough to this guest. Each
diff --git a/tools/libxl/libxl.h b/tools/libxl/libxl.h
index a1c5d15..6f157c9 100644
--- a/tools/libxl/libxl.h
+++ b/tools/libxl/libxl.h
@@ -863,6 +863,12 @@ const char *libxl_defbool_to_string(libxl_defbool b);
 #define LIBXL_TIMER_MODE_DEFAULT -1
 #define LIBXL_MEMKB_DEFAULT ~0ULL
 
+/*
+ * We'd like to set a memory boundary to determine if we need to check
+ * any overlap with reserved device memory.
+ */
+#define LIBXL_RDM_MEM_BOUNDARY_MEMKB_DEFAULT (2048 * 1024)
+
 #define LIBXL_MS_VM_GENID_LEN 16
 typedef struct {
     uint8_t bytes[LIBXL_MS_VM_GENID_LEN];
diff --git a/tools/libxl/libxl_create.c b/tools/libxl/libxl_create.c
index 7a0c57d..38a8c3a 100644
--- a/tools/libxl/libxl_create.c
+++ b/tools/libxl/libxl_create.c
@@ -109,6 +109,10 @@ void libxl__rdm_setdefault(libxl__gc *gc, libxl_domain_build_info *b_info)
 {
     if (b_info->u.hvm.rdm.reserve == LIBXL_RDM_RESERVE_FLAG_INVALID)
         b_info->u.hvm.rdm.reserve = LIBXL_RDM_RESERVE_FLAG_RELAXED;
+
+    if (b_info->u.hvm.rdm_mem_boundary_memkb == LIBXL_MEMKB_DEFAULT)
+        b_info->u.hvm.rdm_mem_boundary_memkb =
+                            LIBXL_RDM_MEM_BOUNDARY_MEMKB_DEFAULT;
 }
 
 int libxl__domain_build_info_setdefault(libxl__gc *gc,
diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
index f3c39a0..62ef120 100644
--- a/tools/libxl/libxl_dom.c
+++ b/tools/libxl/libxl_dom.c
@@ -922,12 +922,6 @@ int libxl__build_hvm(libxl__gc *gc, uint32_t domid,
     int ret, rc = ERROR_FAIL;
     uint64_t mmio_start, lowmem_end, highmem_end;
     libxl_domain_build_info *const info = &d_config->b_info;
-    /*
-     * Currently we fix this as 2G to guarantte how to handle
-     * our rdm policy. But we'll provide a parameter to set
-     * this dynamically.
-     */
-    uint64_t rdm_mem_boundary = 0x80000000;
 
     memset(&args, 0, sizeof(struct xc_hvm_build_args));
     /* The params from the configuration file are in Mb, which are then
@@ -966,7 +960,7 @@ int libxl__build_hvm(libxl__gc *gc, uint32_t domid,
     args.mmio_start = mmio_start;
 
     ret = libxl__domain_device_construct_rdm(gc, d_config,
-                                             rdm_mem_boundary,
+                                             info->u.hvm.rdm_mem_boundary_memkb*1024,
                                              &args);
     if (ret) {
         LOG(ERROR, "checking reserved device memory failed");
diff --git a/tools/libxl/libxl_types.idl b/tools/libxl/libxl_types.idl
index 1a8a180..a1b95db 100644
--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -484,6 +484,7 @@ libxl_domain_build_info = Struct("domain_build_info",[
                                        ("ms_vm_genid",      libxl_ms_vm_genid),
                                        ("serial_list",      libxl_string_list),
                                        ("rdm", libxl_rdm_reserve),
+                                       ("rdm_mem_boundary_memkb", MemKB),
                                        ])),
                  ("pv", Struct(None, [("kernel", string),
                                       ("slack_memkb", MemKB),
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index c858068..dfb50d6 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -1519,6 +1519,9 @@ static void parse_config_data(const char *config_source,
                     exit(1);
             }
         }
+
+        if (!xlu_cfg_get_long (config, "rdm_mem_boundary", &l, 0))
+            b_info->u.hvm.rdm_mem_boundary_memkb = l * 1024;
         break;
     case LIBXL_DOMAIN_TYPE_PV:
     {
-- 
1.9.1

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

* [v5][PATCH 13/16] libxl: construct e820 map with RDM information for HVM guest
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
                   ` (11 preceding siblings ...)
  2015-07-07  6:17 ` [v5][PATCH 12/16] tools: introduce a new parameter to set a predefined rdm boundary Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07  9:03   ` Wei Liu
  2015-07-07  6:17 ` [v5][PATCH 14/16] xen/vtd: enable USB device assignment Tiejun Chen
                   ` (2 subsequent siblings)
  15 siblings, 1 reply; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Ian Jackson, Ian Campbell, Stefano Stabellini

Here we'll construct a basic guest e820 table via
XENMEM_set_memory_map. This table includes lowmem, highmem
and RDMs if they exist, and hvmloader would need this info
later.

Note this guest e820 table would be same as before if the
platform has no any RDM or we disable RDM (by default).

CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
---
v5:

* Rephrase patch's short log
* Make libxl__domain_construct_e820() hidden

v4:

* Use goto style error handling.
* Instead of NOGC, we shoud use libxl__malloc(gc,XXX) to allocate local e820.

 tools/libxl/libxl_dom.c      |  5 +++
 tools/libxl/libxl_internal.h | 24 +++++++++++++
 tools/libxl/libxl_x86.c      | 83 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 112 insertions(+)

diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c
index 62ef120..41da479 100644
--- a/tools/libxl/libxl_dom.c
+++ b/tools/libxl/libxl_dom.c
@@ -1004,6 +1004,11 @@ int libxl__build_hvm(libxl__gc *gc, uint32_t domid,
         goto out;
     }
 
+    if (libxl__domain_construct_e820(gc, d_config, domid, &args)) {
+        LOG(ERROR, "setting domain memory map failed");
+        goto out;
+    }
+
     ret = hvm_build_set_params(ctx->xch, domid, info, state->store_port,
                                &state->store_mfn, state->console_port,
                                &state->console_mfn, state->store_domid,
diff --git a/tools/libxl/libxl_internal.h b/tools/libxl/libxl_internal.h
index b4d8419..a50449a 100644
--- a/tools/libxl/libxl_internal.h
+++ b/tools/libxl/libxl_internal.h
@@ -3794,6 +3794,30 @@ static inline void libxl__update_config_vtpm(libxl__gc *gc,
  */
 void libxl__bitmap_copy_best_effort(libxl__gc *gc, libxl_bitmap *dptr,
                                     const libxl_bitmap *sptr);
+
+/*
+ * Here we're just trying to set these kinds of e820 mappings:
+ *
+ * #1. Low memory region
+ *
+ * Low RAM starts at least from 1M to make sure all standard regions
+ * of the PC memory map, like BIOS, VGA memory-mapped I/O and vgabios,
+ * have enough space.
+ * Note: Those stuffs below 1M are still constructed with multiple
+ * e820 entries by hvmloader. At this point we don't change anything.
+ *
+ * #2. RDM region if it exists
+ *
+ * #3. High memory region if it exists
+ *
+ * Note: these regions are not overlapping since we already check
+ * to adjust them. Please refer to libxl__domain_device_construct_rdm().
+ */
+_hidden int libxl__domain_construct_e820(libxl__gc *gc,
+                                 libxl_domain_config *d_config,
+                                 uint32_t domid,
+                                 struct xc_hvm_build_args *args);
+
 #endif
 
 /*
diff --git a/tools/libxl/libxl_x86.c b/tools/libxl/libxl_x86.c
index ed2bd38..be297b2 100644
--- a/tools/libxl/libxl_x86.c
+++ b/tools/libxl/libxl_x86.c
@@ -438,6 +438,89 @@ int libxl__arch_domain_map_irq(libxl__gc *gc, uint32_t domid, int irq)
 }
 
 /*
+ * Here we're just trying to set these kinds of e820 mappings:
+ *
+ * #1. Low memory region
+ *
+ * Low RAM starts at least from 1M to make sure all standard regions
+ * of the PC memory map, like BIOS, VGA memory-mapped I/O and vgabios,
+ * have enough space.
+ * Note: Those stuffs below 1M are still constructed with multiple
+ * e820 entries by hvmloader. At this point we don't change anything.
+ *
+ * #2. RDM region if it exists
+ *
+ * #3. High memory region if it exists
+ *
+ * Note: these regions are not overlapping since we already check
+ * to adjust them. Please refer to libxl__domain_device_construct_rdm().
+ */
+#define GUEST_LOW_MEM_START_DEFAULT 0x100000
+int libxl__domain_construct_e820(libxl__gc *gc,
+                                 libxl_domain_config *d_config,
+                                 uint32_t domid,
+                                 struct xc_hvm_build_args *args)
+{
+    int rc = 0;
+    unsigned int nr = 0, i;
+    /* We always own at least one lowmem entry. */
+    unsigned int e820_entries = 1;
+    struct e820entry *e820 = NULL;
+    uint64_t highmem_size =
+                    args->highmem_end ? args->highmem_end - (1ull << 32) : 0;
+
+    /* Add all rdm entries. */
+    for (i = 0; i < d_config->num_rdms; i++)
+        if (d_config->rdms[i].flag != LIBXL_RDM_RESERVE_FLAG_INVALID)
+            e820_entries++;
+
+
+    /* If we should have a highmem range. */
+    if (highmem_size)
+        e820_entries++;
+
+    if (e820_entries >= E820MAX) {
+        LOG(ERROR, "Ooops! Too many entries in the memory map!\n");
+        rc = ERROR_INVAL;
+        goto out;
+    }
+
+    e820 = libxl__malloc(gc, sizeof(struct e820entry) * e820_entries);
+
+    /* Low memory */
+    e820[nr].addr = GUEST_LOW_MEM_START_DEFAULT;
+    e820[nr].size = args->lowmem_end - GUEST_LOW_MEM_START_DEFAULT;
+    e820[nr].type = E820_RAM;
+    nr++;
+
+    /* RDM mapping */
+    for (i = 0; i < d_config->num_rdms; i++) {
+        if (d_config->rdms[i].flag == LIBXL_RDM_RESERVE_FLAG_INVALID)
+            continue;
+
+        e820[nr].addr = d_config->rdms[i].start;
+        e820[nr].size = d_config->rdms[i].size;
+        e820[nr].type = E820_RESERVED;
+        nr++;
+    }
+
+    /* High memory */
+    if (highmem_size) {
+        e820[nr].addr = ((uint64_t)1 << 32);
+        e820[nr].size = highmem_size;
+        e820[nr].type = E820_RAM;
+    }
+
+    if (xc_domain_set_memory_map(CTX->xch, domid, e820, e820_entries) != 0) {
+        rc = ERROR_FAIL;
+        goto out;
+    }
+
+out:
+    return rc;
+}
+
+/*
  * Local variables:
  * mode: C
  * c-basic-offset: 4
-- 
1.9.1

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

* [v5][PATCH 14/16] xen/vtd: enable USB device assignment
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
                   ` (12 preceding siblings ...)
  2015-07-07  6:17 ` [v5][PATCH 13/16] libxl: construct e820 map with RDM information for HVM guest Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 15/16] xen/vtd: prevent from assign the device with shared rmrr Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 16/16] tools: parse to enable new rdm policy parameters Tiejun Chen
  15 siblings, 0 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel; +Cc: Yang Zhang, Kevin Tian

USB RMRR may conflict with guest BIOS region. In such case, identity
mapping setup is simply skipped in previous implementation. Now we
can handle this scenario cleanly with new policy mechanism so previous
hack code can be removed now.

CC: Yang Zhang <yang.z.zhang@intel.com>
CC: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
---
v5:

* Nothing is changed.

v4:

* Refine the patch head description

 xen/drivers/passthrough/vtd/dmar.h  |  1 -
 xen/drivers/passthrough/vtd/iommu.c | 11 ++---------
 xen/drivers/passthrough/vtd/utils.c |  7 -------
 3 files changed, 2 insertions(+), 17 deletions(-)

diff --git a/xen/drivers/passthrough/vtd/dmar.h b/xen/drivers/passthrough/vtd/dmar.h
index af1feef..af205f5 100644
--- a/xen/drivers/passthrough/vtd/dmar.h
+++ b/xen/drivers/passthrough/vtd/dmar.h
@@ -129,7 +129,6 @@ do {                                                \
 
 int vtd_hw_check(void);
 void disable_pmr(struct iommu *iommu);
-int is_usb_device(u16 seg, u8 bus, u8 devfn);
 int is_igd_drhd(struct acpi_drhd_unit *drhd);
 
 #endif /* _DMAR_H_ */
diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c
index 56f5911..c833290 100644
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -2245,11 +2245,9 @@ static int reassign_device_ownership(
     /*
      * If the device belongs to the hardware domain, and it has RMRR, don't
      * remove it from the hardware domain, because BIOS may use RMRR at
-     * booting time. Also account for the special casing of USB below (in
-     * intel_iommu_assign_device()).
+     * booting time.
      */
-    if ( !is_hardware_domain(source) &&
-         !is_usb_device(pdev->seg, pdev->bus, pdev->devfn) )
+    if ( !is_hardware_domain(source) )
     {
         const struct acpi_rmrr_unit *rmrr;
         u16 bdf;
@@ -2303,13 +2301,8 @@ static int intel_iommu_assign_device(
     if ( ret )
         return ret;
 
-    /* FIXME: Because USB RMRR conflicts with guest bios region,
-     * ignore USB RMRR temporarily.
-     */
     seg = pdev->seg;
     bus = pdev->bus;
-    if ( is_usb_device(seg, bus, pdev->devfn) )
-        return 0;
 
     /* Setup rmrr identity mapping */
     for_each_rmrr_device( rmrr, bdf, i )
diff --git a/xen/drivers/passthrough/vtd/utils.c b/xen/drivers/passthrough/vtd/utils.c
index bd14c02..b8a077f 100644
--- a/xen/drivers/passthrough/vtd/utils.c
+++ b/xen/drivers/passthrough/vtd/utils.c
@@ -29,13 +29,6 @@
 #include "extern.h"
 #include <asm/io_apic.h>
 
-int is_usb_device(u16 seg, u8 bus, u8 devfn)
-{
-    u16 class = pci_conf_read16(seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
-                                PCI_CLASS_DEVICE);
-    return (class == 0xc03);
-}
-
 /* Disable vt-d protected memory registers. */
 void disable_pmr(struct iommu *iommu)
 {
-- 
1.9.1

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

* [v5][PATCH 15/16] xen/vtd: prevent from assign the device with shared rmrr
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
                   ` (13 preceding siblings ...)
  2015-07-07  6:17 ` [v5][PATCH 14/16] xen/vtd: enable USB device assignment Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  2015-07-07  6:17 ` [v5][PATCH 16/16] tools: parse to enable new rdm policy parameters Tiejun Chen
  15 siblings, 0 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel; +Cc: Yang Zhang, Kevin Tian

Currently we're intending to cover this kind of devices
with shared RMRR simply since the case of shared RMRR is
a rare case according to our previous experiences. But
late we can group these devices which shared rmrr, and
then allow all devices within a group to be assigned to
same domain.

CC: Yang Zhang <yang.z.zhang@intel.com>
CC: Kevin Tian <kevin.tian@intel.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
Acked-by: Kevin Tian <kevin.tian@intel.com>
---
v5:
 
* Nothing is changed.

v4:

* Refine one code comment.

 xen/drivers/passthrough/vtd/iommu.c | 32 +++++++++++++++++++++++++++++---
 1 file changed, 29 insertions(+), 3 deletions(-)

diff --git a/xen/drivers/passthrough/vtd/iommu.c b/xen/drivers/passthrough/vtd/iommu.c
index c833290..095fb1d 100644
--- a/xen/drivers/passthrough/vtd/iommu.c
+++ b/xen/drivers/passthrough/vtd/iommu.c
@@ -2297,13 +2297,39 @@ static int intel_iommu_assign_device(
     if ( list_empty(&acpi_drhd_units) )
         return -ENODEV;
 
+    seg = pdev->seg;
+    bus = pdev->bus;
+    /*
+     * In rare cases one given rmrr is shared by multiple devices but
+     * obviously this would put the security of a system at risk. So
+     * we should prevent from this sort of device assignment.
+     *
+     * TODO: in the future we can introduce group device assignment
+     * interface to make sure devices sharing RMRR are assigned to the
+     * same domain together.
+     */
+    for_each_rmrr_device( rmrr, bdf, i )
+    {
+        if ( rmrr->segment == seg &&
+             PCI_BUS(bdf) == bus &&
+             PCI_DEVFN2(bdf) == devfn )
+        {
+            if ( rmrr->scope.devices_cnt > 1 )
+            {
+                printk(XENLOG_G_ERR VTDPREFIX
+                       " cannot assign %04x:%02x:%02x.%u"
+                       " with shared RMRR for Dom%d.\n",
+                       seg, bus, PCI_SLOT(devfn), PCI_FUNC(devfn),
+                       d->domain_id);
+                return -EPERM;
+            }
+        }
+    }
+
     ret = reassign_device_ownership(hardware_domain, d, devfn, pdev);
     if ( ret )
         return ret;
 
-    seg = pdev->seg;
-    bus = pdev->bus;
-
     /* Setup rmrr identity mapping */
     for_each_rmrr_device( rmrr, bdf, i )
     {
-- 
1.9.1

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

* [v5][PATCH 16/16] tools: parse to enable new rdm policy parameters
  2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
                   ` (14 preceding siblings ...)
  2015-07-07  6:17 ` [v5][PATCH 15/16] xen/vtd: prevent from assign the device with shared rmrr Tiejun Chen
@ 2015-07-07  6:17 ` Tiejun Chen
  15 siblings, 0 replies; 51+ messages in thread
From: Tiejun Chen @ 2015-07-07  6:17 UTC (permalink / raw)
  To: xen-devel; +Cc: Wei Liu, Ian Jackson, Ian Campbell, Stefano Stabellini

This patch parses to enable user configurable parameters to specify
RDM resource and according policies,

Global RDM parameter:
    rdm = "type=none/host,reserve=strict/relaxed"
Per-device RDM parameter:
    pci = [ 'sbdf, rdm_reserve=strict/relaxed' ]

Default per-device RDM policy is 'strict', while default global RDM policy
is 'relaxed'. When both policies are specified on a given region, 'strict' is
always preferred.

CC: Ian Jackson <ian.jackson@eu.citrix.com>
CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
CC: Ian Campbell <ian.campbell@citrix.com>
CC: Wei Liu <wei.liu2@citrix.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
---
v5:

* Need a rebase after we make all rdm variables specific to .hvm.
* Like other pci option, the per-device policy always follows
  the global policy by default.

v4:

* Separated from current patch #11 to parse/enable our rdm policy parameters
  since its make a lot sense and these stuffs are specific to xl/libxlu.

 tools/libxl/libxlu_pci.c | 92 ++++++++++++++++++++++++++++++++++++++++++++++++
 tools/libxl/libxlutil.h  |  4 +++
 tools/libxl/xl_cmdimpl.c | 13 +++++++
 3 files changed, 109 insertions(+)

diff --git a/tools/libxl/libxlu_pci.c b/tools/libxl/libxlu_pci.c
index 26fb143..9255878 100644
--- a/tools/libxl/libxlu_pci.c
+++ b/tools/libxl/libxlu_pci.c
@@ -42,6 +42,9 @@ static int pcidev_struct_fill(libxl_device_pci *pcidev, unsigned int domain,
 #define STATE_OPTIONS_K 6
 #define STATE_OPTIONS_V 7
 #define STATE_TERMINAL  8
+#define STATE_TYPE      9
+#define STATE_RDM_TYPE      10
+#define STATE_RESERVE_FLAG      11
 int xlu_pci_parse_bdf(XLU_Config *cfg, libxl_device_pci *pcidev, const char *str)
 {
     unsigned state = STATE_DOMAIN;
@@ -143,6 +146,17 @@ int xlu_pci_parse_bdf(XLU_Config *cfg, libxl_device_pci *pcidev, const char *str
                     pcidev->permissive = atoi(tok);
                 }else if ( !strcmp(optkey, "seize") ) {
                     pcidev->seize = atoi(tok);
+                }else if ( !strcmp(optkey, "rdm_reserve") ) {
+                    if ( !strcmp(tok, "strict") ) {
+                        pcidev->rdm_reserve = LIBXL_RDM_RESERVE_FLAG_STRICT;
+                    } else if ( !strcmp(tok, "relaxed") ) {
+                        pcidev->rdm_reserve = LIBXL_RDM_RESERVE_FLAG_RELAXED;
+                    } else {
+                        XLU__PCI_ERR(cfg, "%s is not an valid PCI RDM property"
+                                          " flag: 'strict' or 'relaxed'.",
+                                     tok);
+                        goto parse_error;
+                    }
                 }else{
                     XLU__PCI_ERR(cfg, "Unknown PCI BDF option: %s", optkey);
                 }
@@ -167,6 +181,84 @@ parse_error:
     return ERROR_INVAL;
 }
 
+int xlu_rdm_parse(XLU_Config *cfg, libxl_rdm_reserve *rdm, const char *str)
+{
+    unsigned state = STATE_TYPE;
+    char *buf2, *tok, *ptr, *end;
+
+    if (NULL == (buf2 = ptr = strdup(str)))
+        return ERROR_NOMEM;
+
+    for (tok = ptr, end = ptr + strlen(ptr) + 1; ptr < end; ptr++) {
+        switch(state) {
+        case STATE_TYPE:
+            if (*ptr == '=') {
+                state = STATE_RDM_TYPE;
+                *ptr = '\0';
+                if (strcmp(tok, "type")) {
+                    XLU__PCI_ERR(cfg, "Unknown RDM state option: %s", tok);
+                    goto parse_error;
+                }
+                tok = ptr + 1;
+            }
+            break;
+        case STATE_RDM_TYPE:
+            if (*ptr == '\0' || *ptr == ',') {
+                state = STATE_RESERVE_FLAG;
+                *ptr = '\0';
+                if (!strcmp(tok, "host")) {
+                    rdm->type = LIBXL_RDM_RESERVE_TYPE_HOST;
+                } else if (!strcmp(tok, "none")) {
+                    rdm->type = LIBXL_RDM_RESERVE_TYPE_NONE;
+                } else {
+                    XLU__PCI_ERR(cfg, "Unknown RDM type option: %s", tok);
+                    goto parse_error;
+                }
+                tok = ptr + 1;
+            }
+            break;
+        case STATE_RESERVE_FLAG:
+            if (*ptr == '=') {
+                state = STATE_OPTIONS_V;
+                *ptr = '\0';
+                if (strcmp(tok, "reserve")) {
+                    XLU__PCI_ERR(cfg, "Unknown RDM property value: %s", tok);
+                    goto parse_error;
+                }
+                tok = ptr + 1;
+            }
+            break;
+        case STATE_OPTIONS_V:
+            if (*ptr == ',' || *ptr == '\0') {
+                state = STATE_TERMINAL;
+                *ptr = '\0';
+                if (!strcmp(tok, "strict")) {
+                    rdm->reserve = LIBXL_RDM_RESERVE_FLAG_STRICT;
+                } else if (!strcmp(tok, "relaxed")) {
+                    rdm->reserve = LIBXL_RDM_RESERVE_FLAG_RELAXED;
+                } else {
+                    XLU__PCI_ERR(cfg, "Unknown RDM property flag value: %s",
+                                 tok);
+                    goto parse_error;
+                }
+                tok = ptr + 1;
+            }
+        default:
+            break;
+        }
+    }
+
+    free(buf2);
+
+    if (tok != ptr || state != STATE_TERMINAL)
+        goto parse_error;
+
+    return 0;
+
+parse_error:
+    return ERROR_INVAL;
+}
+
 /*
  * Local variables:
  * mode: C
diff --git a/tools/libxl/libxlutil.h b/tools/libxl/libxlutil.h
index 989605a..e81b644 100644
--- a/tools/libxl/libxlutil.h
+++ b/tools/libxl/libxlutil.h
@@ -106,6 +106,10 @@ int xlu_disk_parse(XLU_Config *cfg, int nspecs, const char *const *specs,
  */
 int xlu_pci_parse_bdf(XLU_Config *cfg, libxl_device_pci *pcidev, const char *str);
 
+/*
+ * RDM parsing
+ */
+int xlu_rdm_parse(XLU_Config *cfg, libxl_rdm_reserve *rdm, const char *str);
 
 /*
  * Vif rate parsing.
diff --git a/tools/libxl/xl_cmdimpl.c b/tools/libxl/xl_cmdimpl.c
index dfb50d6..6c4a4eb 100644
--- a/tools/libxl/xl_cmdimpl.c
+++ b/tools/libxl/xl_cmdimpl.c
@@ -1923,6 +1923,14 @@ skip_vfb:
         xlu_cfg_get_defbool(config, "e820_host", &b_info->u.pv.e820_host, 0);
     }
 
+    if (!xlu_cfg_get_string(config, "rdm", &buf, 0)) {
+        libxl_rdm_reserve rdm;
+        if (!xlu_rdm_parse(config, &rdm, buf)) {
+            b_info->u.hvm.rdm.type = rdm.type;
+            b_info->u.hvm.rdm.reserve = rdm.reserve;
+        }
+    }
+
     if (!xlu_cfg_get_list (config, "pci", &pcis, 0, 0)) {
         d_config->num_pcidevs = 0;
         d_config->pcidevs = NULL;
@@ -1937,6 +1945,11 @@ skip_vfb:
             pcidev->power_mgmt = pci_power_mgmt;
             pcidev->permissive = pci_permissive;
             pcidev->seize = pci_seize;
+            /*
+             * Like other pci option, the per-device policy always follows
+             * the global policy by default.
+             */
+            pcidev->rdm_reserve = b_info->u.hvm.rdm.reserve;
             if (!xlu_pci_parse_bdf(config, pcidev, buf))
                 d_config->num_pcidevs++;
         }
-- 
1.9.1

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

* Re: [v5][PATCH 13/16] libxl: construct e820 map with RDM information for HVM guest
  2015-07-07  6:17 ` [v5][PATCH 13/16] libxl: construct e820 map with RDM information for HVM guest Tiejun Chen
@ 2015-07-07  9:03   ` Wei Liu
  0 siblings, 0 replies; 51+ messages in thread
From: Wei Liu @ 2015-07-07  9:03 UTC (permalink / raw)
  To: Tiejun Chen
  Cc: Wei Liu, Stefano Stabellini, Ian Jackson, Ian Campbell, xen-devel

On Tue, Jul 07, 2015 at 02:17:14PM +0800, Tiejun Chen wrote:
> Here we'll construct a basic guest e820 table via
> XENMEM_set_memory_map. This table includes lowmem, highmem
> and RDMs if they exist, and hvmloader would need this info
> later.
> 
> Note this guest e820 table would be same as before if the
> platform has no any RDM or we disable RDM (by default).
> 
> CC: Ian Jackson <ian.jackson@eu.citrix.com>
> CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> CC: Ian Campbell <ian.campbell@citrix.com>
> CC: Wei Liu <wei.liu2@citrix.com>
> Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>

Acked-by: Wei Liu <wei.liu2@citrix.com>

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07  6:17 ` [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy Tiejun Chen
@ 2015-07-07 10:21   ` Wei Liu
  2015-07-08  0:54     ` Chen, Tiejun
  2015-07-07 11:47   ` Ian Jackson
  1 sibling, 1 reply; 51+ messages in thread
From: Wei Liu @ 2015-07-07 10:21 UTC (permalink / raw)
  To: Tiejun Chen
  Cc: Wei Liu, Stefano Stabellini, Ian Jackson, Ian Campbell, xen-devel

On Tue, Jul 07, 2015 at 02:17:11PM +0800, Tiejun Chen wrote:
> This patch introduces user configurable parameters to specify RDM
> resource and according policies,
> 
> Global RDM parameter:
>     rdm = "type=none/host,reserve=strict/relaxed"
> Per-device RDM parameter:
>     pci = [ 'sbdf, rdm_reserve=strict/relaxed' ]
> 
> Global RDM parameter, "type", allows user to specify reserved regions
> explicitly, e.g. using 'host' to include all reserved regions reported
> on this platform which is good to handle hotplug scenario. In the future
> this parameter may be further extended to allow specifying random regions,
> e.g. even those belonging to another platform as a preparation for live
> migration with passthrough devices. Instead, 'none' means we have nothing
> to do all reserved regions and ignore all policies, so guest work as before.
> 
> 'strict/relaxed' policy decides how to handle conflict when reserving RDM
> regions in pfn space. If conflict exists, 'strict' means an immediate error
> so VM can't keep running, while 'relaxed' allows moving forward with a
> warning message thrown out.
> 
> Default per-device RDM policy is 'strict', while default global RDM policy
> is 'relaxed'. And the per-device policy would override the global policy like
> others.
> 
> CC: Ian Jackson <ian.jackson@eu.citrix.com>
> CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> CC: Ian Campbell <ian.campbell@citrix.com>
> CC: Wei Liu <wei.liu2@citrix.com>
> Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
> ---
> v5:
> 
> * Just make sure the per-device plicy always override the global policy,
>   and so cleanup some associated comments and the patch head description.
> * A little change to follow one bit, XEN_DOMCTL_DEV_RDM_RELAXED.
> * Improve all descriptions in doc.
> * Make all rdm variables specific to .hvm
> 
> v4:
> 
> * No need to define init_val for libxl_rdm_reserve_type since its just zero
> * Grab those changes to xl/libxlu to as a final patch
> 
>  docs/man/xl.cfg.pod.5        | 84 ++++++++++++++++++++++++++++++++++++++++++++
>  docs/misc/vtd.txt            | 24 +++++++++++++
>  tools/libxl/libxl_create.c   |  7 ++++
>  tools/libxl/libxl_internal.h |  2 ++
>  tools/libxl/libxl_pci.c      |  9 +++++
>  tools/libxl/libxl_types.idl  | 18 ++++++++++
>  6 files changed, 144 insertions(+)
> 
> diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5
> index a3e0e2e..a2dc343 100644
> --- a/docs/man/xl.cfg.pod.5
> +++ b/docs/man/xl.cfg.pod.5
> @@ -655,6 +655,83 @@ assigned slave device.
>  
>  =back
>  
> +=item B<rdm="RDM_RESERVATION_STRING">
> +
> +(HVM/x86 only) Specifies information about Reserved Device Memory (RDM),
> +which is necessary to enable robust device passthrough. One example of RDM
> +is reported through ACPI Reserved Memory Region Reporting (RMRR) structure
> +on x86 platform.
> +
> +B<RDM_RESERVE_STRING> has the form C<[KEY=VALUE,KEY=VALUE,...> where:
> +
> +=over 4
> +
> +=item B<KEY=VALUE>
> +
> +Possible B<KEY>s are:
> +
> +=over 4
> +
> +=item B<type="STRING">
> +
> +Currently there are only two valid types:
> +
> +"host" means all reserved device memory on this platform should be checked to
> +reserve regions in this VM's guest address space. This global RDM parameter
> +allows user to specify reserved regions explicitly, and using "host" includes
> +all reserved regions reported on this platform, which is useful when doing
> +hotplug.
> +
> +"none" is the default value and it means we don't check any reserved regions
> +and then all rdm policies would be ignored. Guest just works as before and
> +the conflict of RDM and guest address space wouldn't be handled, and then
> +this may result in the associated device not being able to work or even crash
> +the VM. So if you're assigning this kind of device, this option is not
> +recommended unless you can make sure any conflict doesn't exist.
> +

One issue didn't come to conclusion during last round of review. Ian was
asking what's the difference with type=none vs not specifying rdm option
at all.

You need to either convince Ian or remove "type=none" in *xl* level.
I.e. don't touch the libxl IDL. It still needs a none type.

> +For example, you're trying to set "memory = 2800" to allocate memory to one
> +given VM but the platform owns two RDM regions like,
> +
> +RMRR region: base_addr ac6d3000 end_address ac6e6fff
> +RMRR region: base_addr ad800000 end_address afffffff
> +
> +In this conflict case,
> +
> +#1. If the type options is set with "none",
> +

If B<type> is set to "none", for example,

> +rdm = "type=none,reserve=strict" or rdm = "type=none,reserve=relaxed"
> +
> +mean we don't handle any conflict just to make VM keep running as before.
> +Note this is our default behavior.
> +

It means we don't handle any conflict to make VM run as before. This is
the default behavior.

> +#2. If the type options is set with "host",
> +

If B<type> is set to "host", for example,

> +rdm = "type=host,reserve=strict" or rdm = "type=host,reserve=relaxed"
> +
> +mean all conflict would be handled according to our policies which is
> +introduced by the reserve option as described below.
> +

It means all conflicts will be handled according to the policy
introduced by B<reserve> as described below.

> +=item B<reserve="STRING">
> +
> +Specifies how to deal with conflicts discovered when reserving reserved device
> +memory in the guest address space.
> +

Specifies how to deal with conflicts when reserving reserved device
memory in guest address space.

> +When that conflict is unsolved,
> +
> +"strict" means this VM can't be created successfully, or the associated device
> +can't be attached in the case of hotplug;
> +

"strict" means VM can't be created, or the associated device can't be
attached in the case of hotplug.

> +"relaxed" allows a VM to be created to keep running with a warning message
> +thrown out. But this may crash this VM if this device accesses RDM. For example,
> +Windows IGD GFX driver always access these regions so this lead to a blue screen
> +to crash VM in such a case.
> +

"relaxed" allows VM to be created but may cause VM to crash if
pass-through device accesses RDM. For exampl,e Windows IGD GFX driver
always accessed RDM regions so it leads to VM crash.

Wei.

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

* Re: [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map
  2015-07-07  6:17 ` [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map Tiejun Chen
@ 2015-07-07 11:17   ` Ian Jackson
  2015-07-07 12:46     ` Jan Beulich
  0 siblings, 1 reply; 51+ messages in thread
From: Ian Jackson @ 2015-07-07 11:17 UTC (permalink / raw)
  To: Tiejun Chen; +Cc: Yang Zhang, Kevin Tian, Jan Beulich, xen-devel

Tiejun Chen writes ("[Xen-devel] [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map"):
> From: Jan Beulich <jbeulich@suse.com>
> 
> This is a prerequisite for punching holes into HVM and PVH guests' P2M
> to allow passing through devices that are associated with (on VT-d)
> RMRRs.
...

This function:

> +++ b/xen/common/compat/memory.c
...
> +static int get_reserved_device_memory(xen_pfn_t start, xen_ulong_t nr,
> +                                      u32 id, void *ctxt)

is remarkably similar to this function

> +++ b/xen/common/memory.c
...
> +static int get_reserved_device_memory(xen_pfn_t start, xen_ulong_t nr,
> +                                      u32 id, void *ctxt)


Is this usual in hypervisor code ?  It may be that this is the general
approach in compat code and that any cure would be worse than the
disease, but I found it very striking.


> +/*
> + * With some legacy devices, certain guest-physical addresses cannot safely
> + * be used for other purposes, e.g. to map guest RAM.  This hypercall
> + * enumerates those regions so the toolstack can avoid using them.
...
> +    /* IN/OUT */
> +    unsigned int    nr_entries;

Perhaps I am missing something but I can't find any API documentation
for the return value and error returns from this new hypercall.


Thanks,
Ian.

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

* Re: [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM
  2015-07-07  6:17 ` [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM Tiejun Chen
@ 2015-07-07 11:20   ` Wei Liu
  2015-07-07 11:51   ` Ian Jackson
  2015-07-07 11:57   ` Ian Jackson
  2 siblings, 0 replies; 51+ messages in thread
From: Wei Liu @ 2015-07-07 11:20 UTC (permalink / raw)
  To: Tiejun Chen
  Cc: Wei Liu, Stefano Stabellini, Ian Jackson, Ian Campbell, xen-devel

On Tue, Jul 07, 2015 at 02:17:12PM +0800, Tiejun Chen wrote:
> While building a VM, HVM domain builder provides struct hvm_info_table{}
> to help hvmloader. Currently it includes two fields to construct guest
> e820 table by hvmloader, low_mem_pgend and high_mem_pgend. So we should
> check them to fix any conflict with RDM.
> 
> RMRR can reside in address space beyond 4G theoretically, but we never
> see this in real world. So in order to avoid breaking highmem layout
> we don't solve highmem conflict. Note this means highmem rmrr could still
> be supported if no conflict.
> 
> But in the case of lowmem, RMRR probably scatter the whole RAM space.
> Especially multiple RMRR entries would worsen this to lead a complicated
> memory layout. And then its hard to extend hvm_info_table{} to work
> hvmloader out. So here we're trying to figure out a simple solution to
> avoid breaking existing layout. So when a conflict occurs,
> 
>     #1. Above a predefined boundary (2G)
>         - move lowmem_end below reserved region to solve conflict;
> 
>     #2. Below a predefined boundary (2G)
>         - Check strict/relaxed policy.
>         "strict" policy leads to fail libxl. Note when both policies
>         are specified on a given region, 'strict' is always preferred.
>         "relaxed" policy issue a warning message and also mask this entry INVALID
>         to indicate we shouldn't expose this entry to hvmloader.
> 
> Note later we need to provide a parameter to set that predefined boundary
> dynamically.
> 
> CC: Ian Jackson <ian.jackson@eu.citrix.com>
> CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> CC: Ian Campbell <ian.campbell@citrix.com>
> CC: Wei Liu <wei.liu2@citrix.com>
> Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>
> Reviewed-by: Kevin Tian <kevint.tian@intel.com>
> ---
> v5:
> 
> * A little change to make sure the per-device policy always override the global
>   policy and correct its associated code comments.
> * Fix one typo in the patch head description
> * Rename xc_device_get_rdm() with libxl__xc_device_get_rdm(), and then replace
>   malloc() with libxl__malloc(), and finally cleanup this fallout.
> * libxl__xc_device_get_rdm() should return proper libxl error code, ERROR_FAIL.
>   Then instead, the allocated RDM entries would be returned with an out parameter.
> 

This patch does what we've discussed so

Acked-by: Wei Liu <wei.liu2@citrix.com>

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

* Re: [v5][PATCH 12/16] tools: introduce a new parameter to set a predefined rdm boundary
  2015-07-07  6:17 ` [v5][PATCH 12/16] tools: introduce a new parameter to set a predefined rdm boundary Tiejun Chen
@ 2015-07-07 11:22   ` Wei Liu
  0 siblings, 0 replies; 51+ messages in thread
From: Wei Liu @ 2015-07-07 11:22 UTC (permalink / raw)
  To: Tiejun Chen
  Cc: Wei Liu, Stefano Stabellini, Ian Jackson, Ian Campbell, xen-devel

On Tue, Jul 07, 2015 at 02:17:13PM +0800, Tiejun Chen wrote:
> Previously we always fix that predefined boundary as 2G to handle
> conflict between memory and rdm, but now this predefined boundar
> can be changes with the parameter "rdm_mem_boundary" in .cfg file.
> 
> CC: Ian Jackson <ian.jackson@eu.citrix.com>
> CC: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> CC: Ian Campbell <ian.campbell@citrix.com>
> CC: Wei Liu <wei.liu2@citrix.com>
> Signed-off-by: Tiejun Chen <tiejun.chen@intel.com>

Acked-by: Wei Liu <wei.liu2@citrix.com>

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07  6:17 ` [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy Tiejun Chen
  2015-07-07 10:21   ` Wei Liu
@ 2015-07-07 11:47   ` Ian Jackson
  2015-07-07 12:03     ` Chen, Tiejun
  1 sibling, 1 reply; 51+ messages in thread
From: Ian Jackson @ 2015-07-07 11:47 UTC (permalink / raw)
  To: Tiejun Chen; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

Tiejun Chen writes ("[v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy"):
> This patch introduces user configurable parameters to specify RDM
> resource and according policies,
...
> Global RDM parameter, "type", allows user to specify reserved regions
> explicitly, e.g. using 'host' to include all reserved regions reported

As I understand this feature, I don't think the name `type' is right.
This is a method for handling or overriding/ignoring the RDM problem.

Perhaps `handling=' or `strategy=' ?

And `none' seems quite an innocuous name for such a dangerous
setting.  How about `ignore' ?

> 'strict/relaxed' policy decides how to handle conflict when reserving RDM
> regions in pfn space. If conflict exists, 'strict' means an immediate error
> so VM can't keep running, while 'relaxed' allows moving forward with a
> warning message thrown out.
> 
> Default per-device RDM policy is 'strict', while default global RDM policy
> is 'relaxed'. And the per-device policy would override the global policy like
> others.

I don't think these two sentences can both be true.  If the per-device
policy overrides the global policy, then the per-device policy must
have at least three values: `strict', `relaxed', and `not set'
(implicitly using global policy).

Perhaps I have misunderstood.

> diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5
> index a3e0e2e..a2dc343 100644
> --- a/docs/man/xl.cfg.pod.5
> +++ b/docs/man/xl.cfg.pod.5
> @@ -655,6 +655,83 @@ assigned slave device.
...
> +=item B<type="STRING">

The documentation on this is rather vague about what the default is.
But you do say:

> +In this conflict case,
> +
> +#1. If the type options is set with "none",
> +
> +rdm = "type=none,reserve=strict" or rdm = "type=none,reserve=relaxed"
> +
> +mean we don't handle any conflict just to make VM keep running as before.
> +Note this is our default behavior.

This suggests that the default is "do the dangerous thing".  That
doesn't seem right.

> +#2. If the type options is set with "host",
> +
> +rdm = "type=host,reserve=strict" or rdm = "type=host,reserve=relaxed"
...
> +"relaxed" allows a VM to be created to keep running with a warning message
> +thrown out. But this may crash this VM if this device accesses RDM. For example,
> +Windows IGD GFX driver always access these regions so this lead to a blue screen
> +to crash VM in such a case.

The difference between
   type=host,reserve=relaxed
and
   type=none
is simply whether a warning is printed ?

Ian.

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

* Re: [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM
  2015-07-07  6:17 ` [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM Tiejun Chen
  2015-07-07 11:20   ` Wei Liu
@ 2015-07-07 11:51   ` Ian Jackson
  2015-07-07 12:08     ` Wei Liu
  2015-07-07 11:57   ` Ian Jackson
  2 siblings, 1 reply; 51+ messages in thread
From: Ian Jackson @ 2015-07-07 11:51 UTC (permalink / raw)
  To: Tiejun Chen; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

Tiejun Chen writes ("[v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM"):
> While building a VM, HVM domain builder provides struct hvm_info_table{}
> to help hvmloader. Currently it includes two fields to construct guest
> e820 table by hvmloader, low_mem_pgend and high_mem_pgend. So we should
> check them to fix any conflict with RDM.
...
> Note later we need to provide a parameter to set that predefined boundary
> dynamically.

Why ...

> +libxl_device_rdm = Struct("device_rdm", [
> +    ("start", uint64),
> +    ("size", uint64),
> +    ("flag", libxl_rdm_reserve_flag),
> +    ])
> +
>  libxl_device_dtdev = Struct("device_dtdev", [
>      ("path", string),
>      ])
> @@ -592,6 +598,7 @@ libxl_domain_config = Struct("domain_config", [
>      ("disks", Array(libxl_device_disk, "num_disks")),
>      ("nics", Array(libxl_device_nic, "num_nics")),
>      ("pcidevs", Array(libxl_device_pci, "num_pcidevs")),
> +    ("rdms", Array(libxl_device_rdm, "num_rdms")),
>      ("dtdevs", Array(libxl_device_dtdev, "num_dtdevs")),
>      ("vfbs", Array(libxl_device_vfb, "num_vfbs")),
>      ("vkbs", Array(libxl_device_vkb, "num_vkbs")),

... does this need to be exposed at the libxl API ?  Are we expecting
that callers will want to specify the rdms set explicitly ?

Ian.

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

* Re: [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM
  2015-07-07  6:17 ` [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM Tiejun Chen
  2015-07-07 11:20   ` Wei Liu
  2015-07-07 11:51   ` Ian Jackson
@ 2015-07-07 11:57   ` Ian Jackson
  2015-07-07 14:52     ` Chen, Tiejun
  2 siblings, 1 reply; 51+ messages in thread
From: Ian Jackson @ 2015-07-07 11:57 UTC (permalink / raw)
  To: Tiejun Chen; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

Tiejun Chen writes ("[v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM"):
> While building a VM, HVM domain builder provides struct hvm_info_table{}
> to help hvmloader. Currently it includes two fields to construct guest
> e820 table by hvmloader, low_mem_pgend and high_mem_pgend. So we should
> check them to fix any conflict with RDM.
...
> +    *nr_entries = 0;
> +    rc = xc_reserved_device_memory_map(CTX->xch, flag, seg, bus, devfn,
> +                                       NULL, nr_entries);
> +    assert(rc <= 0);
> +    /* "0" means we have no any rdm entry. */
> +    if (!rc)
> +        goto out;

I think the error handling here is wrong.  Certainly `rc' should not
be used for a libxc return.

See tools/libxl/CODING_STYLE.  I know that much of the existing code
uses rc for libxc returns but this is deprecated, and please don't
make more of it.

> +    if (errno == ENOBUFS) {
> +        *xrdm = libxl__malloc(gc,
> +                              *nr_entries *
> +                              sizeof(xen_reserved_device_memory_t));
> +        rc = xc_reserved_device_memory_map(CTX->xch, flag, seg, bus, devfn,
> +                                           *xrdm, nr_entries);

This might be less code, and a bit clearer, if it were a loop rather
than two calls with the second in an if.

...
> +        if(d_config->rdms[i].flag == LIBXL_RDM_RESERVE_FLAG_STRICT) {
             ^
Missing space.

Thanks,
Ian.

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07 11:47   ` Ian Jackson
@ 2015-07-07 12:03     ` Chen, Tiejun
  2015-07-07 12:14       ` Ian Jackson
  0 siblings, 1 reply; 51+ messages in thread
From: Chen, Tiejun @ 2015-07-07 12:03 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

>> Global RDM parameter, "type", allows user to specify reserved regions
>> explicitly, e.g. using 'host' to include all reserved regions reported
>
> As I understand this feature, I don't think the name `type' is right.
> This is a method for handling or overriding/ignoring the RDM problem.
>
> Perhaps `handling=' or `strategy=' ?

Okay, I prefer to use 'strategy='.

>
> And `none' seems quite an innocuous name for such a dangerous
> setting.  How about `ignore' ?
>
>> 'strict/relaxed' policy decides how to handle conflict when reserving RDM
>> regions in pfn space. If conflict exists, 'strict' means an immediate error
>> so VM can't keep running, while 'relaxed' allows moving forward with a
>> warning message thrown out.
>>
>> Default per-device RDM policy is 'strict', while default global RDM policy
>> is 'relaxed'. And the per-device policy would override the global policy like
>> others.
>
> I don't think these two sentences can both be true.  If the per-device
> policy overrides the global policy, then the per-device policy must
> have at least three values: `strict', `relaxed', and `not set'
> (implicitly using global policy).

Yeah. The per-device policy is first set as the global policy. This 
behavior is same as other pci option. Please see the last patch,

@@ -1937,6 +1945,11 @@ skip_vfb:
              pcidev->power_mgmt = pci_power_mgmt;
              pcidev->permissive = pci_permissive;
              pcidev->seize = pci_seize;
+            /*
+             * Like other pci option, the per-device policy always follows
+             * the global policy by default.
+             */
+            pcidev->rdm_reserve = b_info->u.hvm.rdm.reserve;
              if (!xlu_pci_parse_bdf(config, pcidev, buf))
                  d_config->num_pcidevs++;
          }

>
> Perhaps I have misunderstood.
>
>> diff --git a/docs/man/xl.cfg.pod.5 b/docs/man/xl.cfg.pod.5
>> index a3e0e2e..a2dc343 100644
>> --- a/docs/man/xl.cfg.pod.5
>> +++ b/docs/man/xl.cfg.pod.5
>> @@ -655,6 +655,83 @@ assigned slave device.
> ...
>> +=item B<type="STRING">
>
> The documentation on this is rather vague about what the default is.
> But you do say:
>
>> +In this conflict case,
>> +
>> +#1. If the type options is set with "none",
>> +
>> +rdm = "type=none,reserve=strict" or rdm = "type=none,reserve=relaxed"
>> +
>> +mean we don't handle any conflict just to make VM keep running as before.
>> +Note this is our default behavior.
>
> This suggests that the default is "do the dangerous thing".  That
> doesn't seem right.

As I discussed with Campbell we'd like not to expose "none" in xl level 
since this is equivalent to that case we don't set anything.

>
>> +#2. If the type options is set with "host",
>> +
>> +rdm = "type=host,reserve=strict" or rdm = "type=host,reserve=relaxed"
> ...
>> +"relaxed" allows a VM to be created to keep running with a warning message
>> +thrown out. But this may crash this VM if this device accesses RDM. For example,
>> +Windows IGD GFX driver always access these regions so this lead to a blue screen
>> +to crash VM in such a case.
>
> The difference between
>     type=host,reserve=relaxed
> and
>     type=none
> is simply whether a warning is printed ?
>

"none" means we have a chance to work as before since not all devices 
own RDM. But as I said above this is same as !rdm.

Thanks
Tiejun

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

* Re: [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM
  2015-07-07 11:51   ` Ian Jackson
@ 2015-07-07 12:08     ` Wei Liu
  2015-07-07 12:16       ` Ian Jackson
  0 siblings, 1 reply; 51+ messages in thread
From: Wei Liu @ 2015-07-07 12:08 UTC (permalink / raw)
  To: Ian Jackson
  Cc: Tiejun Chen, Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

On Tue, Jul 07, 2015 at 12:51:48PM +0100, Ian Jackson wrote:
> Tiejun Chen writes ("[v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM"):
> > While building a VM, HVM domain builder provides struct hvm_info_table{}
> > to help hvmloader. Currently it includes two fields to construct guest
> > e820 table by hvmloader, low_mem_pgend and high_mem_pgend. So we should
> > check them to fix any conflict with RDM.
> ...
> > Note later we need to provide a parameter to set that predefined boundary
> > dynamically.
> 
> Why ...
> 
> > +libxl_device_rdm = Struct("device_rdm", [
> > +    ("start", uint64),
> > +    ("size", uint64),
> > +    ("flag", libxl_rdm_reserve_flag),
> > +    ])
> > +
> >  libxl_device_dtdev = Struct("device_dtdev", [
> >      ("path", string),
> >      ])
> > @@ -592,6 +598,7 @@ libxl_domain_config = Struct("domain_config", [
> >      ("disks", Array(libxl_device_disk, "num_disks")),
> >      ("nics", Array(libxl_device_nic, "num_nics")),
> >      ("pcidevs", Array(libxl_device_pci, "num_pcidevs")),
> > +    ("rdms", Array(libxl_device_rdm, "num_rdms")),
> >      ("dtdevs", Array(libxl_device_dtdev, "num_dtdevs")),
> >      ("vfbs", Array(libxl_device_vfb, "num_vfbs")),
> >      ("vkbs", Array(libxl_device_vkb, "num_vkbs")),
> 
> ... does this need to be exposed at the libxl API ?  Are we expecting
> that callers will want to specify the rdms set explicitly ?
> 

Yes according to their design -- so that they can migrate guests among
hosts which have different RDM ranges by setting RDM parameter to the
super set of all RDM regions on all hosts.

Wei.

> Ian.

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07 12:03     ` Chen, Tiejun
@ 2015-07-07 12:14       ` Ian Jackson
  2015-07-07 12:31         ` Chen, Tiejun
  0 siblings, 1 reply; 51+ messages in thread
From: Ian Jackson @ 2015-07-07 12:14 UTC (permalink / raw)
  To: Chen, Tiejun; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

Chen, Tiejun writes ("Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy"):
> [Ian Jackson:]
> > As I understand this feature, I don't think the name `type' is right.
> > This is a method for handling or overriding/ignoring the RDM problem.
> >
> > Perhaps `handling=' or `strategy=' ?
> 
> Okay, I prefer to use 'strategy='.

(We are discussing this on irc.)

> > And `none' seems quite an innocuous name for such a dangerous
> > setting.  How about `ignore' ?
...

[Later:]
> As I discussed with Campbell we'd like not to expose "none" in xl level 
> since this is equivalent to that case we don't set anything.

I think this observation of mine applies to the libxl API level too.


> >> Default per-device RDM policy is 'strict', while default global
> >> RDM policy is 'relaxed'. And the per-device policy would override
> >> the global policy like others.
> >
> > I don't think these two sentences can both be true.  If the per-device
> > policy overrides the global policy, then the per-device policy must
> > have at least three values: `strict', `relaxed', and `not set'
> > (implicitly using global policy).
> 
> Yeah. The per-device policy is first set as the global policy. This 
> behavior is same as other pci option. Please see the last patch,

OK, then can you please amend the commit message to be true :-).


> > This suggests that the default is "do the dangerous thing".  That
> > doesn't seem right.
> 
> As I discussed with Campbell we'd like not to expose "none" in xl level 
> since this is equivalent to that case we don't set anything.

That's not really an answer to what I have said, I think.

Why is the default the option that the documentation recommends to
avoid ?

> "none" means we have a chance to work as before since not all devices 
> own RDM. But as I said above this is same as !rdm.

Are we expecting many existing devices, and existing setups, to break
if we don't make the default be to ignore the problem ?

Ian.

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

* Re: [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM
  2015-07-07 12:08     ` Wei Liu
@ 2015-07-07 12:16       ` Ian Jackson
  0 siblings, 0 replies; 51+ messages in thread
From: Ian Jackson @ 2015-07-07 12:16 UTC (permalink / raw)
  To: Wei Liu; +Cc: Tiejun Chen, Stefano Stabellini, Ian Campbell, xen-devel

Wei Liu writes ("Re: [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM"):
> On Tue, Jul 07, 2015 at 12:51:48PM +0100, Ian Jackson wrote:
> > Why does this need to be exposed at the libxl API ?  Are we expecting
> > that callers will want to specify the rdms set explicitly ?
> 
> Yes according to their design -- so that they can migrate guests among
> hosts which have different RDM ranges by setting RDM parameter to the
> super set of all RDM regions on all hosts.

That makes sense, thanks.

Ian.

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07 12:14       ` Ian Jackson
@ 2015-07-07 12:31         ` Chen, Tiejun
  2015-07-07 13:26           ` Ian Jackson
  0 siblings, 1 reply; 51+ messages in thread
From: Chen, Tiejun @ 2015-07-07 12:31 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

> [Later:]
>> As I discussed with Campbell we'd like not to expose "none" in xl level
>> since this is equivalent to that case we don't set anything.
>
> I think this observation of mine applies to the libxl API level too.

Sorry I don't know what I should do at this point.

>
>
>>>> Default per-device RDM policy is 'strict', while default global
>>>> RDM policy is 'relaxed'. And the per-device policy would override
>>>> the global policy like others.
>>>
>>> I don't think these two sentences can both be true.  If the per-device
>>> policy overrides the global policy, then the per-device policy must
>>> have at least three values: `strict', `relaxed', and `not set'
>>> (implicitly using global policy).
>>
>> Yeah. The per-device policy is first set as the global policy. This
>> behavior is same as other pci option. Please see the last patch,
>
> OK, then can you please amend the commit message to be true :-).

Sure.

>
>
>>> This suggests that the default is "do the dangerous thing".  That
>>> doesn't seem right.
>>
>> As I discussed with Campbell we'd like not to expose "none" in xl level
>> since this is equivalent to that case we don't set anything.
>
> That's not really an answer to what I have said, I think.
>
> Why is the default the option that the documentation recommends to
> avoid ?

I mean not all devices really needs this option and actually these 
devices are very rare. Currently just IGD GFX needs this consideration 
so we'd like to make "none" as a default value.

>
>> "none" means we have a chance to work as before since not all devices
>> own RDM. But as I said above this is same as !rdm.
>
> Are we expecting many existing devices, and existing setups, to break
> if we don't make the default be to ignore the problem ?
>

If we don't set anything we don't hope you can ignore this existing problem.

Thanks
Tiejun

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

* Re: [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map
  2015-07-07 11:17   ` Ian Jackson
@ 2015-07-07 12:46     ` Jan Beulich
  2015-07-07 13:23       ` Ian Jackson
  0 siblings, 1 reply; 51+ messages in thread
From: Jan Beulich @ 2015-07-07 12:46 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Yang Zhang, Tiejun Chen, Kevin Tian, xen-devel

>>> On 07.07.15 at 13:17, <Ian.Jackson@eu.citrix.com> wrote:
> Tiejun Chen writes ("[Xen-devel] [v5][PATCH 01/16] xen: introduce 
> XENMEM_reserved_device_memory_map"):
>> From: Jan Beulich <jbeulich@suse.com>
>> 
>> This is a prerequisite for punching holes into HVM and PVH guests' P2M
>> to allow passing through devices that are associated with (on VT-d)
>> RMRRs.
> ...
> 
> This function:
> 
>> +++ b/xen/common/compat/memory.c
> ...
>> +static int get_reserved_device_memory(xen_pfn_t start, xen_ulong_t nr,
>> +                                      u32 id, void *ctxt)
> 
> is remarkably similar to this function
> 
>> +++ b/xen/common/memory.c
> ...
>> +static int get_reserved_device_memory(xen_pfn_t start, xen_ulong_t nr,
>> +                                      u32 id, void *ctxt)
> 
> 
> Is this usual in hypervisor code ?  It may be that this is the general
> approach in compat code and that any cure would be worse than the
> disease, but I found it very striking.

The types involved are slightly different, and hence folding them
isn't as easy as it might seem.

>> +/*
>> + * With some legacy devices, certain guest-physical addresses cannot safely
>> + * be used for other purposes, e.g. to map guest RAM.  This hypercall
>> + * enumerates those regions so the toolstack can avoid using them.
> ...
>> +    /* IN/OUT */
>> +    unsigned int    nr_entries;
> 
> Perhaps I am missing something but I can't find any API documentation
> for the return value and error returns from this new hypercall.

I think this is in line with everything else in this header - am I
overlooking something?

Jan

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

* Re: [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map
  2015-07-07 12:46     ` Jan Beulich
@ 2015-07-07 13:23       ` Ian Jackson
  2015-07-07 14:05         ` Jan Beulich
  0 siblings, 1 reply; 51+ messages in thread
From: Ian Jackson @ 2015-07-07 13:23 UTC (permalink / raw)
  To: Jan Beulich; +Cc: Yang Zhang, Tiejun Chen, Kevin Tian, xen-devel

Jan Beulich writes ("Re: [Xen-devel] [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map"):
> On 07.07.15 at 13:17, <Ian.Jackson@eu.citrix.com> wrote:
> >> +/*
> >> + * With some legacy devices, certain guest-physical addresses cannot safely
> >> + * be used for other purposes, e.g. to map guest RAM.  This hypercall
> >> + * enumerates those regions so the toolstack can avoid using them.
> > ...
> >> +    /* IN/OUT */
> >> +    unsigned int    nr_entries;
> > 
> > Perhaps I am missing something but I can't find any API documentation
> > for the return value and error returns from this new hypercall.
> 
> I think this is in line with everything else in this header - am I
> overlooking something?

In particular, wouldn't it be sensible to write down that if the
number of entries available is bigger than nr_entries, the hypercall
fails with ERANGE, sets nr_entries to the real number of entries, and
leaves the buffer in an undefined state ?

> > This function:
...
> > is remarkably similar to this function
...
> > Is this usual in hypervisor code ?  It may be that this is the general
> > approach in compat code and that any cure would be worse than the
> > disease, but I found it very striking.
> 
> The types involved are slightly different, and hence folding them
> isn't as easy as it might seem.

Fair enough.

Ian.

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07 12:31         ` Chen, Tiejun
@ 2015-07-07 13:26           ` Ian Jackson
  2015-07-07 13:53             ` Chen, Tiejun
  0 siblings, 1 reply; 51+ messages in thread
From: Ian Jackson @ 2015-07-07 13:26 UTC (permalink / raw)
  To: Chen, Tiejun; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

Chen, Tiejun writes ("Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy"):
> > [Later:]
> >> As I discussed with Campbell we'd like not to expose "none" in xl level
> >> since this is equivalent to that case we don't set anything.
> >
> > I think this observation of mine applies to the libxl API level too.
> 
> Sorry I don't know what I should do at this point.

I was suggesting (in text that you have snipped) that "none" in the
API should be remamed "ignore".

> >>> This suggests that the default is "do the dangerous thing".  That
> >>> doesn't seem right.
> >>
> >> As I discussed with Campbell we'd like not to expose "none" in xl level
> >> since this is equivalent to that case we don't set anything.
> >
> > That's not really an answer to what I have said, I think.
> >
> > Why is the default the option that the documentation recommends to
> > avoid ?
> 
> I mean not all devices really needs this option and actually these 
> devices are very rare. Currently just IGD GFX needs this consideration 
> so we'd like to make "none" as a default value.

What happens if "host" is used as a default with other devices ?
AFAICT such other decices do not have any RDM so "host" would work
fine.

> >> "none" means we have a chance to work as before since not all devices
> >> own RDM. But as I said above this is same as !rdm.
> >
> > Are we expecting many existing devices, and existing setups, to break
> > if we don't make the default be to ignore the problem ?
> 
> If we don't set anything we don't hope you can ignore this existing problem.

Is "none" not "hoping the user can ignore the problem" ?

Ian.

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07 13:26           ` Ian Jackson
@ 2015-07-07 13:53             ` Chen, Tiejun
  2015-07-07 14:16               ` Ian Jackson
  2015-07-07 14:40               ` Ian Jackson
  0 siblings, 2 replies; 51+ messages in thread
From: Chen, Tiejun @ 2015-07-07 13:53 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

On 2015/7/7 21:26, Ian Jackson wrote:
> Chen, Tiejun writes ("Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy"):
>>> [Later:]
>>>> As I discussed with Campbell we'd like not to expose "none" in xl level
>>>> since this is equivalent to that case we don't set anything.
>>>
>>> I think this observation of mine applies to the libxl API level too.
>>
>> Sorry I don't know what I should do at this point.
>
> I was suggesting (in text that you have snipped) that "none" in the
> API should be remamed "ignore".

So sounds you're saying these two changes,

@@ -77,7 +77,7 @@ libxl_domain_type = Enumeration("domain_type", [
      ], init_val = "LIBXL_DOMAIN_TYPE_INVALID")

  libxl_rdm_reserve_type = Enumeration("rdm_reserve_type", [
-    (0, "none"),
+    (0, "ignore"),
      (1, "host"),
      ])

@@ -381,8 +381,8 @@ libxl_vnode_info = Struct("vnode_info", [
      ])

  libxl_rdm_reserve = Struct("rdm_reserve", [
-    ("type",    libxl_rdm_reserve_type),
-    ("reserve",   libxl_rdm_reserve_flag),
+    ("strategy",    libxl_rdm_reserve_type),
+    ("reserve",     libxl_rdm_reserve_flag),
      ])

  libxl_domain_build_info = Struct("domain_build_info",[

Right?

>
>>>>> This suggests that the default is "do the dangerous thing".  That
>>>>> doesn't seem right.
>>>>
>>>> As I discussed with Campbell we'd like not to expose "none" in xl level
>>>> since this is equivalent to that case we don't set anything.
>>>
>>> That's not really an answer to what I have said, I think.
>>>
>>> Why is the default the option that the documentation recommends to
>>> avoid ?
>>
>> I mean not all devices really needs this option and actually these
>> devices are very rare. Currently just IGD GFX needs this consideration
>> so we'd like to make "none" as a default value.
>
> What happens if "host" is used as a default with other devices ?

"host" just means we should concern all RDMS no matter if these devices 
own any RDM, and even actually you don't pass though any devices.

> AFAICT such other decices do not have any RDM so "host" would work
> fine.

Yes but its really not pointless to keep setting host if you already 
make sure nothing is involved to RDM. So why we still set 'host' to cost 
those instructions cycles in this case? I don't think its not better to 
set 'host' by default.

>
>>>> "none" means we have a chance to work as before since not all devices
>>>> own RDM. But as I said above this is same as !rdm.
>>>
>>> Are we expecting many existing devices, and existing setups, to break
>>> if we don't make the default be to ignore the problem ?
>>
>> If we don't set anything we don't hope you can ignore this existing problem.
>
> Is "none" not "hoping the user can ignore the problem" ?

Its impossible since the hypervisor or tools can't prevent from 
accessing RDM by a VM. So as I said early, "none" is just suitable to 
two cases,

#1. Those devices don't own any RDM
#2. Guest OS doesn't access RDM

Compared to other cases, these two cases are more popular in real world 
and actual usage. So we'd like to keep "none" as a default.

Thanks
Tiejun

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

* Re: [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map
  2015-07-07 13:23       ` Ian Jackson
@ 2015-07-07 14:05         ` Jan Beulich
  2015-07-07 21:32           ` Chen, Tiejun
  0 siblings, 1 reply; 51+ messages in thread
From: Jan Beulich @ 2015-07-07 14:05 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Yang Zhang, Tiejun Chen, Kevin Tian, xen-devel

>>> On 07.07.15 at 15:23, <Ian.Jackson@eu.citrix.com> wrote:
> Jan Beulich writes ("Re: [Xen-devel] [v5][PATCH 01/16] xen: introduce 
> XENMEM_reserved_device_memory_map"):
>> On 07.07.15 at 13:17, <Ian.Jackson@eu.citrix.com> wrote:
>> >> +/*
>> >> + * With some legacy devices, certain guest-physical addresses cannot safely
>> >> + * be used for other purposes, e.g. to map guest RAM.  This hypercall
>> >> + * enumerates those regions so the toolstack can avoid using them.
>> > ...
>> >> +    /* IN/OUT */
>> >> +    unsigned int    nr_entries;
>> > 
>> > Perhaps I am missing something but I can't find any API documentation
>> > for the return value and error returns from this new hypercall.
>> 
>> I think this is in line with everything else in this header - am I
>> overlooking something?
> 
> In particular, wouldn't it be sensible to write down that if the
> number of entries available is bigger than nr_entries, the hypercall
> fails with ERANGE, sets nr_entries to the real number of entries, and
> leaves the buffer in an undefined state ?

I can add a sentence to that effect.

Jan

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07 13:53             ` Chen, Tiejun
@ 2015-07-07 14:16               ` Ian Jackson
  2015-07-07 14:40               ` Ian Jackson
  1 sibling, 0 replies; 51+ messages in thread
From: Ian Jackson @ 2015-07-07 14:16 UTC (permalink / raw)
  To: Chen, Tiejun; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

Chen, Tiejun writes ("Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy"):
> On 2015/7/7 21:26, Ian Jackson wrote:
> > I was suggesting (in text that you have snipped) that "none" in the
> > API should be remamed "ignore".
> 
> So sounds you're saying these two changes,

I think so, yes.

But I think I need to go away and read your 00/ message and the design
document.  I still feel confused.  I will get back to you RSN.

> > Is "none" not "hoping the user can ignore the problem" ?
> 
> Its impossible since the hypervisor or tools can't prevent from 
> accessing RDM by a VM. So as I said early, "none" is just suitable to 
> two cases,
> 
> #1. Those devices don't own any RDM
> #2. Guest OS doesn't access RDM
> 
> Compared to other cases, these two cases are more popular in real world 
> and actual usage. So we'd like to keep "none" as a default.

Hopefully this answer will make more sense to me after I have read the
design info.

Ian.

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07 13:53             ` Chen, Tiejun
  2015-07-07 14:16               ` Ian Jackson
@ 2015-07-07 14:40               ` Ian Jackson
  2015-07-07 15:16                 ` Chen, Tiejun
  1 sibling, 1 reply; 51+ messages in thread
From: Ian Jackson @ 2015-07-07 14:40 UTC (permalink / raw)
  To: Chen, Tiejun; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

Chen, Tiejun writes ("Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy"):
> On 2015/7/7 21:26, Ian Jackson wrote:
> > Is "none" not "hoping the user can ignore the problem" ?
> 
> Its impossible since the hypervisor or tools can't prevent from 
> accessing RDM by a VM. So as I said early, "none" is just suitable to 
> two cases,
> 
> #1. Those devices don't own any RDM
> #2. Guest OS doesn't access RDM
> 
> Compared to other cases, these two cases are more popular in real world 
> and actual usage. So we'd like to keep "none" as a default.

I have read your 00/ description, and these two emails:
 http://lists.xen.org/archives/html/xen-devel/2015-01/msg01580.html
 http://lists.xenproject.org/archives/html/xen-devel/2015-01/msg00524.html
I have also reread the documentation you provide in this patch.

I'm afraid I still don't understand why it is safe for the default to
be `none'.  My view is that the default setting should avoid a
possibility of memory corruption or system malfunction.

Your description in the document says this:

 +"none" is the default value and it means we don't check any reserved
 +regions and then all rdm policies would be ignored. Guest just works
 +as before and the conflict of RDM and guest address space wouldn't
 +be handled, and then this may result in the associated device not
 +being able to work or even crash the VM. So if you're assigning this
 +kind of device, this option is not recommended unless you can make
 +sure any conflict doesn't exist.

So you do not recommend the use of `none', however you make it the
default.

I'm afraid also that I don't quite understand the interaction between
none-vs-host on the one hand and strict-vs-relaxed on the other.  The
documentation would suggest that the only difference between
   type=none
and
   type=host,reserve=relaxed
is that the latter may print some extra warning messages.  But the
code appears to do a lot of work to move guest memory about, when
type=none is specified.


Also I don't understand this:

> Its impossible since the hypervisor or tools can't prevent from 
> accessing RDM by a VM. So as I said early, "none" is just suitable to 
> two cases,

Perhaps I am missing something here.

The hypervisor can obviously prevent a VM from accessing RDM by not
setting up a mapping for it.  The problem is then that the VM might
try to make the access anyway, and then crash or malfunction.  But
presumably the VM can be instructed via the E820 or some such not to
access these regions.

For a VM which has been given passthrough access to a device which
does DMA things are more complicated but again I think the hypervisor
and tools should be able to deny accesses using the iommu tables.

But then I also don't understand why your comment "the hypervisor or
tools can't prevent from accessing RDM by a VM" explains why "none" is
a good default.


Sorry if I'm being dense.

Ian.

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

* Re: [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM
  2015-07-07 11:57   ` Ian Jackson
@ 2015-07-07 14:52     ` Chen, Tiejun
  2015-07-07 14:57       ` Ian Jackson
  0 siblings, 1 reply; 51+ messages in thread
From: Chen, Tiejun @ 2015-07-07 14:52 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

On 2015/7/7 19:57, Ian Jackson wrote:
> Tiejun Chen writes ("[v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM"):
>> While building a VM, HVM domain builder provides struct hvm_info_table{}
>> to help hvmloader. Currently it includes two fields to construct guest
>> e820 table by hvmloader, low_mem_pgend and high_mem_pgend. So we should
>> check them to fix any conflict with RDM.
> ...
>> +    *nr_entries = 0;
>> +    rc = xc_reserved_device_memory_map(CTX->xch, flag, seg, bus, devfn,
>> +                                       NULL, nr_entries);
>> +    assert(rc <= 0);
>> +    /* "0" means we have no any rdm entry. */
>> +    if (!rc)
>> +        goto out;
>
> I think the error handling here is wrong.  Certainly `rc' should not
> be used for a libxc return.

Nope, we don't return rc directly. In any case of error, rc is reset as 
"ERROR_FAIL" finally.

>
> See tools/libxl/CODING_STYLE.  I know that much of the existing code
> uses rc for libxc returns but this is deprecated, and please don't
> make more of it.
>
>> +    if (errno == ENOBUFS) {
>> +        *xrdm = libxl__malloc(gc,
>> +                              *nr_entries *
>> +                              sizeof(xen_reserved_device_memory_t));
>> +        rc = xc_reserved_device_memory_map(CTX->xch, flag, seg, bus, devfn,
>> +                                           *xrdm, nr_entries);
>
> This might be less code, and a bit clearer, if it were a loop rather
> than two calls with the second in an if.

Sorry I can't understand completely what you want to do. But I really 
agree we should improve this chunk of codes, what about this?

     if (errno != ENOBUFS) {
         rc = ERROR_FAIL;
         goto out;
     }

     *xrdm = libxl__malloc(gc,
                           *nr_entries * 
sizeof(xen_reserved_device_memory_t));
     rc = xc_reserved_device_memory_map(CTX->xch, flag, seg, bus, devfn,
                                        *xrdm, nr_entries);
     if (rc)
         rc = ERROR_FAIL;

  out:
     if (rc) {
         *nr_entries = 0;
         *xrdm = NULL;
         LOG(ERROR, "Could not get reserved device memory maps.\n");
     }
     return rc;

I think this make more readable and clear.

>
> ...
>> +        if(d_config->rdms[i].flag == LIBXL_RDM_RESERVE_FLAG_STRICT) {
>               ^
> Missing space.
>

Fixed.

Thanks
Tiejun

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

* Re: [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM
  2015-07-07 14:52     ` Chen, Tiejun
@ 2015-07-07 14:57       ` Ian Jackson
  2015-07-07 15:27         ` Chen, Tiejun
  0 siblings, 1 reply; 51+ messages in thread
From: Ian Jackson @ 2015-07-07 14:57 UTC (permalink / raw)
  To: Chen, Tiejun; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

Chen, Tiejun writes ("Re: [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM"):
> On 2015/7/7 19:57, Ian Jackson wrote:
> > I think the error handling here is wrong.  Certainly `rc' should not
> > be used for a libxc return.
> 
> Nope, we don't return rc directly. In any case of error, rc is reset as 
> "ERROR_FAIL" finally.

Did you see

> > See tools/libxl/CODING_STYLE.  I know that much of the existing code
> > uses rc for libxc returns but this is deprecated, and please don't
> > make more of it.

this ?

> >> +    if (errno == ENOBUFS) {
> >> +        *xrdm = libxl__malloc(gc,
> >> +                              *nr_entries *
> >> +                              sizeof(xen_reserved_device_memory_t));
> >> +        rc = xc_reserved_device_memory_map(CTX->xch, flag, seg, bus, devfn,
> >> +                                           *xrdm, nr_entries);
> >
> > This might be less code, and a bit clearer, if it were a loop rather
> > than two calls with the second in an if.
> 
> Sorry I can't understand completely what you want to do.

I meant that you could have a loop containing one call to
xc_reserved_device_memory_map.  The loop would normally execute twice.
But it was just a suggestion.  If you don't want to do it that way,
the existing arrangement is tolerable.

>      if (errno != ENOBUFS) {
>          rc = ERROR_FAIL;
>          goto out;
>      }

That would be clearer, yes.

Ian.

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07 14:40               ` Ian Jackson
@ 2015-07-07 15:16                 ` Chen, Tiejun
  2015-07-07 15:39                   ` Chen, Tiejun
  2015-07-07 17:08                   ` Ian Jackson
  0 siblings, 2 replies; 51+ messages in thread
From: Chen, Tiejun @ 2015-07-07 15:16 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

On 2015/7/7 22:40, Ian Jackson wrote:
> Chen, Tiejun writes ("Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy"):
>> On 2015/7/7 21:26, Ian Jackson wrote:
>>> Is "none" not "hoping the user can ignore the problem" ?
>>
>> Its impossible since the hypervisor or tools can't prevent from
>> accessing RDM by a VM. So as I said early, "none" is just suitable to
>> two cases,
>>
>> #1. Those devices don't own any RDM
>> #2. Guest OS doesn't access RDM
>>
>> Compared to other cases, these two cases are more popular in real world
>> and actual usage. So we'd like to keep "none" as a default.
>
> I have read your 00/ description, and these two emails:
>   http://lists.xen.org/archives/html/xen-devel/2015-01/msg01580.html
>   http://lists.xenproject.org/archives/html/xen-devel/2015-01/msg00524.html
> I have also reread the documentation you provide in this patch.
>
> I'm afraid I still don't understand why it is safe for the default to
> be `none'.  My view is that the default setting should avoid a
> possibility of memory corruption or system malfunction.

RMRR is used to pass through a device. And in this case this require 
this sort of 1:1 mapping. And especially RMRR is always masked as 
RESERVED in e820 table. So originally, any VM can't create these 
mappings, right? So as I said, if these devices you're trying to pass 
though don't own RDM or you don't pass through any devices at all, so 
there's no any memory corruption.

>
> Your description in the document says this:
>
>   +"none" is the default value and it means we don't check any reserved
>   +regions and then all rdm policies would be ignored. Guest just works
>   +as before and the conflict of RDM and guest address space wouldn't
>   +be handled, and then this may result in the associated device not
>   +being able to work or even crash the VM. So if you're assigning this
>   +kind of device, this option is not recommended unless you can make
>   +sure any conflict doesn't exist.
>
> So you do not recommend the use of `none', however you make it the
> default.
>
> I'm afraid also that I don't quite understand the interaction between
> none-vs-host on the one hand and strict-vs-relaxed on the other.  The
> documentation would suggest that the only difference between
>     type=none
> and
>     type=host,reserve=relaxed
> is that the latter may print some extra warning messages.  But the
> code appears to do a lot of work to move guest memory about, when
> type=none is specified.
>
>
> Also I don't understand this:
>
>> Its impossible since the hypervisor or tools can't prevent from
>> accessing RDM by a VM. So as I said early, "none" is just suitable to
>> two cases,
>
> Perhaps I am missing something here.
>
> The hypervisor can obviously prevent a VM from accessing RDM by not
> setting up a mapping for it.  The problem is then that the VM might
> try to make the access anyway, and then crash or malfunction.  But

Yes.

> presumably the VM can be instructed via the E820 or some such not to
> access these regions.

As I said above we need to create them as 1:1.

>
> For a VM which has been given passthrough access to a device which
> does DMA things are more complicated but again I think the hypervisor
> and tools should be able to deny accesses using the iommu tables.

RMRR is a special case, and we have to set these mapping as 1:1. This is 
why we introduce these patches to make sure RMRR don't overlap normal 
RAM and MMIO.

>
> But then I also don't understand why your comment "the hypervisor or
> tools can't prevent from accessing RDM by a VM" explains why "none" is
> a good default.

I mean if you don't set these mappings, these devices can't work at all 
and then crash VM like IGD passthrough. But I'm also saying we don't 
pass through any devices in most cases, and those devices which own RDM 
are very rare. So why should we set 'none' to Xen by default?

>
>
> Sorry if I'm being dense.
>

Ian,

Its always fine to me but I just think, is it a good time to start to 
seek another *optional* approach to overturn current design and 
implementation ? Unless you're very sure we're doing something wrong. I 
noticed you should be CCed when we posted this associated design.

Thanks
Tiejun

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

* Re: [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM
  2015-07-07 14:57       ` Ian Jackson
@ 2015-07-07 15:27         ` Chen, Tiejun
  2015-07-07 16:01           ` Ian Jackson
  0 siblings, 1 reply; 51+ messages in thread
From: Chen, Tiejun @ 2015-07-07 15:27 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

On 2015/7/7 22:57, Ian Jackson wrote:
> Chen, Tiejun writes ("Re: [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM"):
>> On 2015/7/7 19:57, Ian Jackson wrote:
>>> I think the error handling here is wrong.  Certainly `rc' should not
>>> be used for a libxc return.
>>
>> Nope, we don't return rc directly. In any case of error, rc is reset as
>> "ERROR_FAIL" finally.
>
> Did you see
>
>>> See tools/libxl/CODING_STYLE.  I know that much of the existing code
>>> uses rc for libxc returns but this is deprecated, and please don't
>>> make more of it.
>
> this ?
>

Are you saying this? We should use 'r' as the return value of libxc call

     int rc = 0, r;

     r = xc_reserved_device_memory_map(CTX->xch, flag, seg, bus, devfn,
                                       NULL, nr_entries);
     assert(r <= 0);
     /* "0" means we have no any rdm entry. */
     if (!r) goto out;

Thanks
Tiejun

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07 15:16                 ` Chen, Tiejun
@ 2015-07-07 15:39                   ` Chen, Tiejun
  2015-07-07 17:08                   ` Ian Jackson
  1 sibling, 0 replies; 51+ messages in thread
From: Chen, Tiejun @ 2015-07-07 15:39 UTC (permalink / raw)
  To: Ian Jackson; +Cc: xen-devel, Wei Liu, Ian Campbell, Stefano Stabellini

> I mean if you don't set these mappings, these devices can't work at all
> and then crash VM like IGD passthrough. But I'm also saying we don't
> pass through any devices in most cases, and those devices which own RDM
> are very rare. So why should we set 'none' to Xen by default?

One typo, s/should/shouldn't/

Thanks
Tiejun

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

* Re: [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM
  2015-07-07 15:27         ` Chen, Tiejun
@ 2015-07-07 16:01           ` Ian Jackson
  0 siblings, 0 replies; 51+ messages in thread
From: Ian Jackson @ 2015-07-07 16:01 UTC (permalink / raw)
  To: Chen, Tiejun; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

Chen, Tiejun writes ("Re: [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM"):
> Are you saying this? We should use 'r' as the return value of libxc call
> 
>      int rc = 0, r;
> 
>      r = xc_reserved_device_memory_map(CTX->xch, flag, seg, bus, devfn,
>                                        NULL, nr_entries);
>      assert(r <= 0);
>      /* "0" means we have no any rdm entry. */
>      if (!r) goto out;

Yes, thanks.

Ian.

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07 15:16                 ` Chen, Tiejun
  2015-07-07 15:39                   ` Chen, Tiejun
@ 2015-07-07 17:08                   ` Ian Jackson
  2015-07-07 21:45                     ` Chen, Tiejun
  1 sibling, 1 reply; 51+ messages in thread
From: Ian Jackson @ 2015-07-07 17:08 UTC (permalink / raw)
  To: Chen, Tiejun; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

Chen, Tiejun writes ("Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy"):
> Its always fine to me but I just think, is it a good time to start to 
> seek another *optional* approach to overturn current design and 
> implementation ? Unless you're very sure we're doing something wrong. I 
> noticed you should be CCed when we posted this associated design.

I don't think I'm trying to overturn the design.  I have read the
design documents and they don't go into this kind of detail about the
libxl API and the xl configuration interface.

Questions of defaults (and of exact API names) are matters of detail.

  > But then I also don't understand why your comment "the hypervisor
  > or tools can't prevent from accessing RDM by a VM" explains why
  > "none" is a good default.

  I mean if you don't set these mappings, these devices can't work at all 
  and then crash VM like IGD passthrough. But I'm also saying we don't 
  pass through any devices in most cases, and those devices which own RDM 
  are very rare. So why should we set 'none' to Xen by default?

(I guess you mean "why _shouldn't we".)

The answer I would give is that defaults should be safe.  That is, the
default configuration settings should not lead to uncontrolled memory
accesses or crashes, even in less common setups.

If the default were changed to `host', what would go wrong ?

AFAICT nothing would change for guests which do not have devices
assigned at build time (and which haven't had `rdm' set).

And, AFACIT, if there are no devices which advertise these RMRRs,
again, there is no difference.

So the only difference occurs when 1. a guest is configured for device
assginemnt 2. some device on the system (perhaps not the one being
assigned) has an RMRR.

Ian.

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

* Re: [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map
  2015-07-07 14:05         ` Jan Beulich
@ 2015-07-07 21:32           ` Chen, Tiejun
  2015-07-08  6:25             ` Jan Beulich
  0 siblings, 1 reply; 51+ messages in thread
From: Chen, Tiejun @ 2015-07-07 21:32 UTC (permalink / raw)
  To: Jan Beulich, Ian Jackson; +Cc: Yang Zhang, Kevin Tian, xen-devel

>>>>> +    /* IN/OUT */
>>>>> +    unsigned int    nr_entries;
>>>>
>>>> Perhaps I am missing something but I can't find any API documentation
>>>> for the return value and error returns from this new hypercall.
>>>
>>> I think this is in line with everything else in this header - am I
>>> overlooking something?
>>
>> In particular, wouldn't it be sensible to write down that if the
>> number of entries available is bigger than nr_entries, the hypercall
>> fails with ERANGE, sets nr_entries to the real number of entries, and
>> leaves the buffer in an undefined state ?
>
> I can add a sentence to that effect.
>

Jan,

Please deliver your final patch to me and then I can resend that next.

Thanks
Tiejun

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07 17:08                   ` Ian Jackson
@ 2015-07-07 21:45                     ` Chen, Tiejun
  0 siblings, 0 replies; 51+ messages in thread
From: Chen, Tiejun @ 2015-07-07 21:45 UTC (permalink / raw)
  To: Ian Jackson; +Cc: Stefano Stabellini, Wei Liu, Ian Campbell, xen-devel

On 2015/7/8 1:08, Ian Jackson wrote:
> Chen, Tiejun writes ("Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy"):
>> Its always fine to me but I just think, is it a good time to start to
>> seek another *optional* approach to overturn current design and
>> implementation ? Unless you're very sure we're doing something wrong. I
>> noticed you should be CCed when we posted this associated design.
>
> I don't think I'm trying to overturn the design.  I have read the
> design documents and they don't go into this kind of detail about the
> libxl API and the xl configuration interface.

Understood.

This design just started concerning everything in high level since RMRR 
is complicated, and its hard to go into details at that moment. And in 
fact this is one reason why we posted two RFC revisions. You know, its 
better to finalize that design based on actual codes.

>
> Questions of defaults (and of exact API names) are matters of detail.
>
>    > But then I also don't understand why your comment "the hypervisor
>    > or tools can't prevent from accessing RDM by a VM" explains why
>    > "none" is a good default.
>
>    I mean if you don't set these mappings, these devices can't work at all
>    and then crash VM like IGD passthrough. But I'm also saying we don't
>    pass through any devices in most cases, and those devices which own RDM
>    are very rare. So why should we set 'none' to Xen by default?
>
> (I guess you mean "why _shouldn't we".)

Yeah, this is my typo. (I corrected this on another ensuing email :) )

>
> The answer I would give is that defaults should be safe.  That is, the

safe and efficient to most cases. As I said previously, the RDM problem 
rarely occurs in real world.

> default configuration settings should not lead to uncontrolled memory
> accesses or crashes, even in less common setups.

Yes.

>
> If the default were changed to `host', what would go wrong ?
>

Some behaviors are different.

> AFAICT nothing would change for guests which do not have devices
> assigned at build time (and which haven't had `rdm' set).

This seems not be correct partially.

More precisely, we have two conditions approaching to our policy,

#1. "host" means we always concern all RDMs resided on this host, no 
matter if either you're passing through those devices associated to 
RDMs, or you don't pass though any devices.

#2. "!host" means we just check if we're passing through some devices 
owning RDM. If yes, we would step into our policy just to each 
per-device rdm. If not, nothing is changed.

>
> And, AFACIT, if there are no devices which advertise these RMRRs,
> again, there is no difference.
>

Just see above.

> So the only difference occurs when 1. a guest is configured for device

In the case of "host",  this is not a precondition to handle RDMs. 
Instead, "host" indicates we *always" handle RDM issues.

> assginemnt 2. some device on the system (perhaps not the one being
> assigned) has an RMRR.
>

#2 is right.

Thanks
Tiejun

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-07 10:21   ` Wei Liu
@ 2015-07-08  0:54     ` Chen, Tiejun
  2015-07-08  8:32       ` Ian Campbell
  0 siblings, 1 reply; 51+ messages in thread
From: Chen, Tiejun @ 2015-07-08  0:54 UTC (permalink / raw)
  To: Wei Liu; +Cc: Stefano Stabellini, Ian Jackson, Ian Campbell, xen-devel

>> +"none" is the default value and it means we don't check any reserved regions
>> +and then all rdm policies would be ignored. Guest just works as before and
>> +the conflict of RDM and guest address space wouldn't be handled, and then
>> +this may result in the associated device not being able to work or even crash
>> +the VM. So if you're assigning this kind of device, this option is not
>> +recommended unless you can make sure any conflict doesn't exist.
>> +
>
> One issue didn't come to conclusion during last round of review. Ian was
> asking what's the difference with type=none vs not specifying rdm option
> at all.
>
> You need to either convince Ian or remove "type=none" in *xl* level.
> I.e. don't touch the libxl IDL. It still needs a none type.

I'll update this next revision. And also rephrase this doc to address 
your comments below.

Thanks
Tiejun

>
>> +For example, you're trying to set "memory = 2800" to allocate memory to one
>> +given VM but the platform owns two RDM regions like,
>> +
>> +RMRR region: base_addr ac6d3000 end_address ac6e6fff
>> +RMRR region: base_addr ad800000 end_address afffffff
>> +
>> +In this conflict case,
>> +
>> +#1. If the type options is set with "none",
>> +
>
> If B<type> is set to "none", for example,
>
>> +rdm = "type=none,reserve=strict" or rdm = "type=none,reserve=relaxed"
>> +
>> +mean we don't handle any conflict just to make VM keep running as before.
>> +Note this is our default behavior.
>> +
>
> It means we don't handle any conflict to make VM run as before. This is
> the default behavior.
>
>> +#2. If the type options is set with "host",
>> +
>
> If B<type> is set to "host", for example,
>
>> +rdm = "type=host,reserve=strict" or rdm = "type=host,reserve=relaxed"
>> +
>> +mean all conflict would be handled according to our policies which is
>> +introduced by the reserve option as described below.
>> +
>
> It means all conflicts will be handled according to the policy
> introduced by B<reserve> as described below.
>
>> +=item B<reserve="STRING">
>> +
>> +Specifies how to deal with conflicts discovered when reserving reserved device
>> +memory in the guest address space.
>> +
>
> Specifies how to deal with conflicts when reserving reserved device
> memory in guest address space.
>
>> +When that conflict is unsolved,
>> +
>> +"strict" means this VM can't be created successfully, or the associated device
>> +can't be attached in the case of hotplug;
>> +
>
> "strict" means VM can't be created, or the associated device can't be
> attached in the case of hotplug.
>
>> +"relaxed" allows a VM to be created to keep running with a warning message
>> +thrown out. But this may crash this VM if this device accesses RDM. For example,
>> +Windows IGD GFX driver always access these regions so this lead to a blue screen
>> +to crash VM in such a case.
>> +
>
> "relaxed" allows VM to be created but may cause VM to crash if
> pass-through device accesses RDM. For exampl,e Windows IGD GFX driver
> always accessed RDM regions so it leads to VM crash.
>
> Wei.
>
>

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

* Re: [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map
  2015-07-07 21:32           ` Chen, Tiejun
@ 2015-07-08  6:25             ` Jan Beulich
  0 siblings, 0 replies; 51+ messages in thread
From: Jan Beulich @ 2015-07-08  6:25 UTC (permalink / raw)
  To: Tiejun Chen; +Cc: Yang Zhang, Kevin Tian, Ian Jackson, xen-devel

>>> On 07.07.15 at 23:32, <tiejun.chen@intel.com> wrote:
>>>>>> +    /* IN/OUT */
>>>>>> +    unsigned int    nr_entries;
>>>>>
>>>>> Perhaps I am missing something but I can't find any API documentation
>>>>> for the return value and error returns from this new hypercall.
>>>>
>>>> I think this is in line with everything else in this header - am I
>>>> overlooking something?
>>>
>>> In particular, wouldn't it be sensible to write down that if the
>>> number of entries available is bigger than nr_entries, the hypercall
>>> fails with ERANGE, sets nr_entries to the real number of entries, and
>>> leaves the buffer in an undefined state ?
>>
>> I can add a sentence to that effect.
> 
> Please deliver your final patch to me and then I can resend that next.

Here's the respective updated hunk:

--- a/xen/include/public/memory.h
+++ b/xen/include/public/memory.h
@@ -573,7 +573,34 @@ struct xen_vnuma_topology_info {
 typedef struct xen_vnuma_topology_info xen_vnuma_topology_info_t;
 DEFINE_XEN_GUEST_HANDLE(xen_vnuma_topology_info_t);
 
-/* Next available subop number is 27 */
+/*
+ * With some legacy devices, certain guest-physical addresses cannot safely
+ * be used for other purposes, e.g. to map guest RAM.  This hypercall
+ * enumerates those regions so the toolstack can avoid using them.
+ */
+#define XENMEM_reserved_device_memory_map   27
+struct xen_reserved_device_memory {
+    xen_pfn_t start_pfn;
+    xen_ulong_t nr_pages;
+};
+typedef struct xen_reserved_device_memory xen_reserved_device_memory_t;
+DEFINE_XEN_GUEST_HANDLE(xen_reserved_device_memory_t);
+
+struct xen_reserved_device_memory_map {
+    /*
+     * IN/OUT
+     *
+     * Gets set to the required number of entries when too low,
+     * signaled by error code -ERANGE. */
+     */
+    unsigned int nr_entries;
+    /* OUT */
+    XEN_GUEST_HANDLE(xen_reserved_device_memory_t) buffer;
+};
+typedef struct xen_reserved_device_memory_map xen_reserved_device_memory_map_t;
+DEFINE_XEN_GUEST_HANDLE(xen_reserved_device_memory_map_t);
+
+/* Next available subop number is 28 */
 
 #endif /* __XEN_PUBLIC_MEMORY_H__ */
 
Jan

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-08  0:54     ` Chen, Tiejun
@ 2015-07-08  8:32       ` Ian Campbell
  2015-07-08  9:06         ` Chen, Tiejun
  0 siblings, 1 reply; 51+ messages in thread
From: Ian Campbell @ 2015-07-08  8:32 UTC (permalink / raw)
  To: Chen, Tiejun; +Cc: Ian Jackson, Stefano Stabellini, Wei Liu, xen-devel

On Wed, 2015-07-08 at 08:54 +0800, Chen, Tiejun wrote:
> >> +"none" is the default value and it means we don't check any reserved regions
> >> +and then all rdm policies would be ignored. Guest just works as before and
> >> +the conflict of RDM and guest address space wouldn't be handled, and then
> >> +this may result in the associated device not being able to work or even crash
> >> +the VM. So if you're assigning this kind of device, this option is not
> >> +recommended unless you can make sure any conflict doesn't exist.
> >> +
> >
> > One issue didn't come to conclusion during last round of review. Ian was
> > asking what's the difference with type=none vs not specifying rdm option
> > at all.
> >
> > You need to either convince Ian or remove "type=none" in *xl* level.
> > I.e. don't touch the libxl IDL. It still needs a none type.
> 
> I'll update this next revision. And also rephrase this doc to address 
> your comments below.

FTR I think I indicated yesterday that I was satisfied with your
explanation for why type=none exists as an option even at the xl level,
namely that it allows us to change the default in the future.

Ian.

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-08  8:32       ` Ian Campbell
@ 2015-07-08  9:06         ` Chen, Tiejun
  2015-07-08  9:17           ` Ian Campbell
  0 siblings, 1 reply; 51+ messages in thread
From: Chen, Tiejun @ 2015-07-08  9:06 UTC (permalink / raw)
  To: Ian Campbell, Ian Jackson; +Cc: Stefano Stabellini, Wei Liu, xen-devel

>> I'll update this next revision. And also rephrase this doc to address
>> your comments below.
>
> FTR I think I indicated yesterday that I was satisfied with your
> explanation for why type=none exists as an option even at the xl level,
> namely that it allows us to change the default in the future.
>

Campbell,

Jackson had some different comments at this point,

#1. Rename "type" to "strategy " and "none" to "ignore"

--- a/tools/libxl/libxl_types.idl
+++ b/tools/libxl/libxl_types.idl
@@ -76,6 +76,17 @@ libxl_domain_type = Enumeration("domain_type", [
      (2, "PV"),
      ], init_val = "LIBXL_DOMAIN_TYPE_INVALID")

+libxl_rdm_reserve_strategy = Enumeration("rdm_reserve_strategy", [
+    (0, "ignore"),
+    (1, "host"),
+    ])
+
...
  libxl_channel_connection = Enumeration("channel_connection", [
      (0, "UNKNOWN"),
      (1, "PTY"),
@@ -369,6 +380,11 @@ libxl_vnode_info = Struct("vnode_info", [
      ("vcpus", libxl_bitmap), # vcpus in this node
      ])

+libxl_rdm_reserve = Struct("rdm_reserve", [
+    ("strategy",    libxl_rdm_reserve_strategy),
+    ("reserve",     libxl_rdm_reserve_flag),
+    ])
+

#2. Don't expose "ignore" to user and just keep "host" as the default

He told me he would discuss this with you, but sounds he didn't do this, 
or I'm missing something here?

Thanks
Tiejun

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

* Re: [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy
  2015-07-08  9:06         ` Chen, Tiejun
@ 2015-07-08  9:17           ` Ian Campbell
  0 siblings, 0 replies; 51+ messages in thread
From: Ian Campbell @ 2015-07-08  9:17 UTC (permalink / raw)
  To: Chen, Tiejun; +Cc: Wei Liu, xen-devel, Ian Jackson, Stefano Stabellini

On Wed, 2015-07-08 at 17:06 +0800, Chen, Tiejun wrote:

> #2. Don't expose "ignore" to user and just keep "host" as the default
> 
> He told me he would discuss this with you, but sounds he didn't do this, 
> or I'm missing something here?

My question was regarding how xl rdm="type=none" differed from not
saying anything (i.e. getting the default). You explained that this was
useful to allow the default to be changed, which I agreed with.

The question regarding the actually naming of the options at either the
xl level or the libxl (which seems to be what Ian J's comments were on)
are orthogonal to the question of whether there should be a way to
explicitly ask for the default (as opposed to implicitly asking for it
by omission of the option).

Ian.

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

end of thread, other threads:[~2015-07-08  9:17 UTC | newest]

Thread overview: 51+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2015-07-07  6:17 [v5][PATCH 00/16] Fix RMRR Tiejun Chen
2015-07-07  6:17 ` [v5][PATCH 01/16] xen: introduce XENMEM_reserved_device_memory_map Tiejun Chen
2015-07-07 11:17   ` Ian Jackson
2015-07-07 12:46     ` Jan Beulich
2015-07-07 13:23       ` Ian Jackson
2015-07-07 14:05         ` Jan Beulich
2015-07-07 21:32           ` Chen, Tiejun
2015-07-08  6:25             ` Jan Beulich
2015-07-07  6:17 ` [v5][PATCH 02/16] xen/vtd: create RMRR mapping Tiejun Chen
2015-07-07  6:17 ` [v5][PATCH 03/16] xen/passthrough: extend hypercall to support rdm reservation policy Tiejun Chen
2015-07-07  6:17 ` [v5][PATCH 04/16] xen: enable XENMEM_memory_map in hvm Tiejun Chen
2015-07-07  6:17 ` [v5][PATCH 05/16] hvmloader: get guest memory map into memory_map[] Tiejun Chen
2015-07-07  6:17 ` [v5][PATCH 06/16] hvmloader/pci: skip reserved ranges Tiejun Chen
2015-07-07  6:17 ` [v5][PATCH 07/16] hvmloader/e820: construct guest e820 table Tiejun Chen
2015-07-07  6:17 ` [v5][PATCH 08/16] tools/libxc: Expose new hypercall xc_reserved_device_memory_map Tiejun Chen
2015-07-07  6:17 ` [v5][PATCH 09/16] tools: extend xc_assign_device() to support rdm reservation policy Tiejun Chen
2015-07-07  6:17 ` [v5][PATCH 10/16] tools: introduce some new parameters to set rdm policy Tiejun Chen
2015-07-07 10:21   ` Wei Liu
2015-07-08  0:54     ` Chen, Tiejun
2015-07-08  8:32       ` Ian Campbell
2015-07-08  9:06         ` Chen, Tiejun
2015-07-08  9:17           ` Ian Campbell
2015-07-07 11:47   ` Ian Jackson
2015-07-07 12:03     ` Chen, Tiejun
2015-07-07 12:14       ` Ian Jackson
2015-07-07 12:31         ` Chen, Tiejun
2015-07-07 13:26           ` Ian Jackson
2015-07-07 13:53             ` Chen, Tiejun
2015-07-07 14:16               ` Ian Jackson
2015-07-07 14:40               ` Ian Jackson
2015-07-07 15:16                 ` Chen, Tiejun
2015-07-07 15:39                   ` Chen, Tiejun
2015-07-07 17:08                   ` Ian Jackson
2015-07-07 21:45                     ` Chen, Tiejun
2015-07-07  6:17 ` [v5][PATCH 11/16] tools/libxl: detect and avoid conflicts with RDM Tiejun Chen
2015-07-07 11:20   ` Wei Liu
2015-07-07 11:51   ` Ian Jackson
2015-07-07 12:08     ` Wei Liu
2015-07-07 12:16       ` Ian Jackson
2015-07-07 11:57   ` Ian Jackson
2015-07-07 14:52     ` Chen, Tiejun
2015-07-07 14:57       ` Ian Jackson
2015-07-07 15:27         ` Chen, Tiejun
2015-07-07 16:01           ` Ian Jackson
2015-07-07  6:17 ` [v5][PATCH 12/16] tools: introduce a new parameter to set a predefined rdm boundary Tiejun Chen
2015-07-07 11:22   ` Wei Liu
2015-07-07  6:17 ` [v5][PATCH 13/16] libxl: construct e820 map with RDM information for HVM guest Tiejun Chen
2015-07-07  9:03   ` Wei Liu
2015-07-07  6:17 ` [v5][PATCH 14/16] xen/vtd: enable USB device assignment Tiejun Chen
2015-07-07  6:17 ` [v5][PATCH 15/16] xen/vtd: prevent from assign the device with shared rmrr Tiejun Chen
2015-07-07  6:17 ` [v5][PATCH 16/16] tools: parse to enable new rdm policy parameters Tiejun Chen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).